Skip to content
Permalink
Browse files
[Cairo] Incorrect dashed and dotted border painting after r177686.
https://bugs.webkit.org/show_bug.cgi?id=141967

Reviewed by Gyuyoung Kim.

Fix the incorrect dashed/dotted border painting in cairo.

Source/WebCore:

* platform/graphics/cairo/GraphicsContextCairo.cpp:
(WebCore::GraphicsContext::drawLine):
(WebCore::calculateStrokePatternOffset): Deleted.
(WebCore::drawLineOnCairoContext): Deleted.

LayoutTests:

* platform/gtk/TestExpectations: Removed the passed test.


Canonical link: https://commits.webkit.org/168771@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191658 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
HunseopJeong committed Oct 28, 2015
1 parent 809f726 commit e0d3a5296e79934f2a5e8e77baf11a69a1497119
Showing with 97 additions and 75 deletions.
  1. +11 −0 LayoutTests/ChangeLog
  2. +0 −1 LayoutTests/platform/gtk/TestExpectations
  3. +14 −0 Source/WebCore/ChangeLog
  4. +72 −74 Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -1,3 +1,14 @@
2015-10-27 Hunseop Jeong <hs85.jeong@samsung.com>

[Cairo] Incorrect dashed and dotted border painting after r177686.
https://bugs.webkit.org/show_bug.cgi?id=141967

Reviewed by Gyuyoung Kim.

Fix the incorrect dashed/dotted border painting in cairo.

* platform/gtk/TestExpectations: Removed the passed test.

2015-10-27 Chris Dumez <cdumez@apple.com>

id of iframe incorrectly sets window name
@@ -529,7 +529,6 @@ webkit.org/b/98653 svg/text/lengthAdjust-text-metrics.html [ Failure ]

webkit.org/b/141837 fast/borders/border-painting-correctness-dashed.html [ ImageOnlyFailure ]
webkit.org/b/141837 fast/borders/border-painting-correctness-dotted.html [ ImageOnlyFailure ]
webkit.org/b/141838 fast/borders/0px-borders.html [ ImageOnlyFailure ]

webkit.org/b/141458 imported/mozilla/svg/blend-color-burn.svg [ ImageOnlyFailure ]
webkit.org/b/141458 imported/mozilla/svg/blend-color-dodge.svg [ ImageOnlyFailure ]
@@ -1,3 +1,17 @@
2015-10-27 Hunseop Jeong <hs85.jeong@samsung.com>

[Cairo] Incorrect dashed and dotted border painting after r177686.
https://bugs.webkit.org/show_bug.cgi?id=141967

Reviewed by Gyuyoung Kim.

Fix the incorrect dashed/dotted border painting in cairo.

* platform/graphics/cairo/GraphicsContextCairo.cpp:
(WebCore::GraphicsContext::drawLine):
(WebCore::calculateStrokePatternOffset): Deleted.
(WebCore::drawLineOnCairoContext): Deleted.

2015-10-27 Chris Dumez <cdumez@apple.com>

id of iframe incorrectly sets window name
@@ -253,93 +253,91 @@ void GraphicsContext::drawRect(const FloatRect& rect, float)
cairo_restore(cr);
}

static double calculateStrokePatternOffset(int distance, int patternWidth)
// This is only used to draw borders, so we should not draw shadows.
void GraphicsContext::drawLine(const FloatPoint& point1, const FloatPoint& point2)
{
// Example: 80 pixels with a width of 30 pixels. Remainder is 20.
// The maximum pixels of line we could paint will be 50 pixels.
int remainder = distance % patternWidth;
int numSegments = (distance - remainder) / patternWidth;

// Special case 1px dotted borders for speed.
if (patternWidth == 1)
return 1;

bool evenNumberOfSegments = !(numSegments % 2);
if (remainder)
evenNumberOfSegments = !evenNumberOfSegments;

if (evenNumberOfSegments) {
if (remainder)
return (patternWidth - remainder) + (remainder / 2);
return patternWidth / 2;
}
if (paintingDisabled())
return;

// Odd number of segments.
if (remainder)
return (patternWidth - remainder) / 2.f;
return 0;
}
if (strokeStyle() == NoStroke)
return;

static void drawLineOnCairoContext(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point1, const FloatPoint& point2)
{
StrokeStyle style = graphicsContext->strokeStyle();
if (style == NoStroke)
const Color& strokeColor = this->strokeColor();
float thickness = strokeThickness();
bool isVerticalLine = (point1.x() + thickness == point2.x());
float strokeWidth = isVerticalLine ? point2.y() - point1.y() : point2.x() - point1.x();
if (!thickness || !strokeWidth)
return;

const Color& strokeColor = graphicsContext->strokeColor();
int strokeThickness = floorf(graphicsContext->strokeThickness());
if (graphicsContext->strokeThickness() < 1)
strokeThickness = 1;

int patternWidth = 0;
if (style == DottedStroke)
patternWidth = strokeThickness;
else if (style == DashedStroke)
patternWidth = 3 * strokeThickness;

bool isVerticalLine = point1.x() == point2.x();
FloatPoint point1OnPixelBoundaries = point1;
FloatPoint point2OnPixelBoundaries = point2;
GraphicsContext::adjustLineToPixelBoundaries(point1OnPixelBoundaries, point2OnPixelBoundaries, strokeThickness, style);

if (patternWidth) {
// Do a rect fill of our endpoints. This ensures we always have the
// appearance of being a border. We then draw the actual dotted/dashed line.
FloatRect firstRect(point1OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness));
FloatRect secondRect(point2OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness));
cairo_t* cairoContext = platformContext()->cr();
StrokeStyle strokeStyle = this->strokeStyle();
float cornerWidth = 0;
bool drawsDashedLine = strokeStyle == DottedStroke || strokeStyle == DashedStroke;

if (drawsDashedLine) {
cairo_save(cairoContext);
// Figure out end points to ensure we always paint corners.
cornerWidth = strokeStyle == DottedStroke ? thickness : std::min(2 * thickness, std::max(thickness, strokeWidth / 3));
if (isVerticalLine) {
firstRect.move(-strokeThickness / 2, -strokeThickness);
secondRect.move(-strokeThickness / 2, 0);
fillRectWithColor(cairoContext, FloatRect(point1.x(), point1.y(), thickness, cornerWidth), strokeColor);
fillRectWithColor(cairoContext, FloatRect(point1.x(), point2.y() - cornerWidth, thickness, cornerWidth), strokeColor);
} else {
firstRect.move(-strokeThickness, -strokeThickness / 2);
secondRect.move(0, -strokeThickness / 2);
fillRectWithColor(cairoContext, FloatRect(point1.x(), point1.y(), cornerWidth, thickness), strokeColor);
fillRectWithColor(cairoContext, FloatRect(point2.x() - cornerWidth, point1.y(), cornerWidth, thickness), strokeColor);
}
strokeWidth -= 2 * cornerWidth;
float patternWidth = strokeStyle == DottedStroke ? thickness : std::min(3 * thickness, std::max(thickness, strokeWidth / 3));
// Check if corner drawing sufficiently covers the line.
if (strokeWidth <= patternWidth + 1) {
cairo_restore(cairoContext);
return;
}
fillRectWithColor(context, firstRect, strokeColor);
fillRectWithColor(context, secondRect, strokeColor);

int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2 * strokeThickness;
double patternOffset = calculateStrokePatternOffset(distance, patternWidth);
double patternWidthAsDouble = patternWidth;
cairo_set_dash(context, &patternWidthAsDouble, 1, patternOffset);
// Pattern starts with full fill and ends with the empty fill.
// 1. Let's start with the empty phase after the corner.
// 2. Check if we've got odd or even number of patterns and whether they fully cover the line.
// 3. In case of even number of patterns and/or remainder, move the pattern start position
// so that the pattern is balanced between the corners.
float patternOffset = patternWidth;
int numberOfSegments = std::floor(strokeWidth / patternWidth);
bool oddNumberOfSegments = numberOfSegments % 2;
float remainder = strokeWidth - (numberOfSegments * patternWidth);
if (oddNumberOfSegments && remainder)
patternOffset -= remainder / 2.f;
else if (!oddNumberOfSegments) {
if (remainder)
patternOffset += patternOffset - (patternWidth + remainder) / 2.f;
else
patternOffset += patternWidth / 2.f;
}
const double dashedLine[2] = { static_cast<double>(patternWidth), static_cast<double>(patternWidth) };
cairo_set_dash(cairoContext, dashedLine, 2, patternOffset);
}

setSourceRGBAFromColor(context, strokeColor);
cairo_set_line_width(context, strokeThickness);
cairo_move_to(context, point1OnPixelBoundaries.x(), point1OnPixelBoundaries.y());
cairo_line_to(context, point2OnPixelBoundaries.x(), point2OnPixelBoundaries.y());
cairo_stroke(context);
}
FloatPoint p1 = point1;
FloatPoint p2 = point2;
// Center line and cut off corners for pattern patining.
if (isVerticalLine) {
float centerOffset = (p2.x() - p1.x()) / 2;
p1.move(centerOffset, cornerWidth);
p2.move(-centerOffset, -cornerWidth);
} else {
float centerOffset = (p2.y() - p1.y()) / 2;
p1.move(cornerWidth, centerOffset);
p2.move(-cornerWidth, -centerOffset);
}

// This is only used to draw borders, so we should not draw shadows.
void GraphicsContext::drawLine(const FloatPoint& point1, const FloatPoint& point2)
{
if (paintingDisabled())
return;
if (shouldAntialias())
cairo_set_antialias(cairoContext, CAIRO_ANTIALIAS_NONE);

cairo_t* cairoContext = platformContext()->cr();
cairo_save(cairoContext);
drawLineOnCairoContext(this, cairoContext, point1, point2);
cairo_restore(cairoContext);
cairo_new_path(cairoContext);
cairo_move_to(cairoContext, p1.x(), p1.y());
cairo_line_to(cairoContext, p2.x(), p2.y());
cairo_stroke(cairoContext);
if (drawsDashedLine)
cairo_restore(cairoContext);
if (shouldAntialias())
cairo_set_antialias(cairoContext, CAIRO_ANTIALIAS_DEFAULT);
}

// This method is only used to draw the little circles used in lists.

0 comments on commit e0d3a52

Please sign in to comment.