Changeset 85279 in webkit


Ignore:
Timestamp:
Apr 28, 2011 5:57:22 PM (13 years ago)
Author:
Martin Robinson
Message:

2011-04-28 Martin Robinson <mrobinson@igalia.com>

Reviewed by Dirk Schulze.

[Cairo] Text underline is not shadowed when text-shadow is enabled
https://bugs.webkit.org/show_bug.cgi?id=48074

Updated pixel results for this test. They were previously incorrect
because text underlines were not shadowed.

  • platform/gtk/fast/text/stroking-decorations-expected.png:

2011-04-28 Martin Robinson <mrobinson@igalia.com>

Reviewed by Dirk Schulze.

[Cairo] Text underline is not shadowed when text-shadow is enabled
https://bugs.webkit.org/show_bug.cgi?id=48074

Use ShadowContext to enable shadows for text underlines. Also remove quite a bit
of duplicate code in GraphicsContext used for stroking lines. This code looks like it was
originally copied from the CG GraphicsContext.

  • platform/graphics/GraphicsContext.h: Make adjustLineToPixelBoundaries so that we can call it from a static helper function.
  • platform/graphics/cairo/GraphicsContextCairo.cpp: (WebCore::calculateStrokePatternOffset): Abstracted this code into a helper. (WebCore::drawLineOnCairoContext): Abstracted this code into a helper. We need to call it multiple times when shadowing text underlines. (WebCore::GraphicsContext::drawLine): Use drawLineOnCairoContext. (WebCore::GraphicsContext::strokeArc): Use calculateStrokePatternOffset. (WebCore::GraphicsContext::drawLineForText): Use drawLineOnCairoContext.
Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r85276 r85279  
     12011-04-28  Martin Robinson  <mrobinson@igalia.com>
     2
     3        Reviewed by Dirk Schulze.
     4
     5        [Cairo] Text underline is not shadowed when text-shadow is enabled
     6        https://bugs.webkit.org/show_bug.cgi?id=48074
     7
     8        Updated pixel results for this test. They were previously incorrect
     9        because text underlines were not shadowed.
     10
     11        * platform/gtk/fast/text/stroking-decorations-expected.png:
     12
    1132011-04-28  Dirk Pranke  <dpranke@chromium.org>
    214
  • trunk/Source/WebCore/ChangeLog

    r85277 r85279  
     12011-04-28  Martin Robinson  <mrobinson@igalia.com>
     2
     3        Reviewed by Dirk Schulze.
     4
     5        [Cairo] Text underline is not shadowed when text-shadow is enabled
     6        https://bugs.webkit.org/show_bug.cgi?id=48074
     7
     8        Use ShadowContext to enable shadows for text underlines. Also remove quite a bit
     9        of duplicate code in GraphicsContext used for stroking lines. This code looks like it was
     10        originally copied from the CG GraphicsContext.
     11
     12        * platform/graphics/GraphicsContext.h: Make adjustLineToPixelBoundaries so that we
     13          can call it from a static helper function.
     14        * platform/graphics/cairo/GraphicsContextCairo.cpp:
     15        (WebCore::calculateStrokePatternOffset): Abstracted this code into a helper.
     16        (WebCore::drawLineOnCairoContext): Abstracted this code into a helper. We need to
     17        call it multiple times when shadowing text underlines.
     18        (WebCore::GraphicsContext::drawLine): Use drawLineOnCairoContext.
     19        (WebCore::GraphicsContext::strokeArc): Use calculateStrokePatternOffset.
     20        (WebCore::GraphicsContext::drawLineForText): Use drawLineOnCairoContext.
     21
    1222011-04-28  Sam Weinig  <sam@webkit.org>
    223
  • trunk/Source/WebCore/platform/graphics/GraphicsContext.h

    r84504 r85279  
    513513        void markDirtyRect(const IntRect&); // Hints that a portion of the backing store is dirty.
    514514
     515        static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle);
     516
    515517    private:
    516518        void platformInit(PlatformGraphicsContext*);
     
    544546
    545547        void setPlatformCompositeOperation(CompositeOperator);
    546 
    547         static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle);
    548548
    549549        GraphicsContextPlatformPrivate* m_data;
  • trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp

    r84088 r85279  
    278278}
    279279
    280 // This is only used to draw borders.
    281 void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
    282 {
    283     if (paintingDisabled())
    284         return;
    285 
    286     StrokeStyle style = strokeStyle();
     280static double calculateStrokePatternOffset(int distance, int patternWidth)
     281{
     282    // Example: 80 pixels with a width of 30 pixels. Remainder is 20.
     283    // The maximum pixels of line we could paint will be 50 pixels.
     284    int remainder = distance % patternWidth;
     285    int numSegments = (distance - remainder) / patternWidth;
     286
     287    // Special case 1px dotted borders for speed.
     288    if (patternWidth == 1)
     289        return 1;
     290
     291    bool evenNumberOfSegments = !(numSegments % 2);
     292    if (remainder)
     293        evenNumberOfSegments = !evenNumberOfSegments;
     294
     295    if (evenNumberOfSegments) {
     296        if (remainder)
     297            return (patternWidth - remainder) + (remainder / 2);
     298        return patternWidth / 2;
     299    }
     300
     301    // Odd number of segments.
     302    if (remainder)
     303        return (patternWidth - remainder) / 2.f;
     304    return 0;
     305}
     306
     307static void drawLineOnCairoContext(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point1, const FloatPoint& point2)
     308{
     309    StrokeStyle style = graphicsContext->strokeStyle();
    287310    if (style == NoStroke)
    288311        return;
    289312
    290     cairo_t* cr = platformContext()->cr();
    291     cairo_save(cr);
    292 
    293     float width = strokeThickness();
    294     if (width < 1)
    295         width = 1;
    296 
    297     FloatPoint p1 = point1;
    298     FloatPoint p2 = point2;
    299     bool isVerticalLine = (p1.x() == p2.x());
    300 
    301     adjustLineToPixelBoundaries(p1, p2, width, style);
    302     cairo_set_line_width(cr, width);
    303 
    304     int patWidth = 0;
    305     switch (style) {
    306     case NoStroke:
    307     case SolidStroke:
    308         break;
    309     case DottedStroke:
    310         patWidth = static_cast<int>(width);
    311         break;
    312     case DashedStroke:
    313         patWidth = 3*static_cast<int>(width);
    314         break;
    315     }
    316 
    317     setSourceRGBAFromColor(cr, strokeColor());
    318 
    319     cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
    320 
    321     if (patWidth) {
     313    const Color& strokeColor = graphicsContext->strokeColor();
     314    int strokeThickness = floorf(graphicsContext->strokeThickness());
     315    if (graphicsContext->strokeThickness() < 1)
     316        strokeThickness = 1;
     317
     318    int patternWidth = 0;
     319    if (style == DottedStroke)
     320        patternWidth = strokeThickness;
     321    else if (style == DashedStroke)
     322        patternWidth = 3 * strokeThickness;
     323
     324    bool isVerticalLine = point1.x() == point2.x();
     325    FloatPoint point1OnPixelBoundaries = point1;
     326    FloatPoint point2OnPixelBoundaries = point2;
     327    GraphicsContext::adjustLineToPixelBoundaries(point1OnPixelBoundaries, point2OnPixelBoundaries, strokeThickness, style);
     328
     329    cairo_set_antialias(context, CAIRO_ANTIALIAS_NONE);
     330    if (patternWidth) {
    322331        // Do a rect fill of our endpoints.  This ensures we always have the
    323332        // appearance of being a border.  We then draw the actual dotted/dashed line.
     333        FloatRect firstRect(point1OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness));
     334        FloatRect secondRect(point2OnPixelBoundaries, FloatSize(strokeThickness, strokeThickness));
    324335        if (isVerticalLine) {
    325             fillRectSourceOver(cr, FloatRect(p1.x() - width/2, p1.y() - width, width, width), strokeColor());
    326             fillRectSourceOver(cr, FloatRect(p2.x() - width/2, p2.y(), width, width), strokeColor());
     336            firstRect.move(-strokeThickness / 2, -strokeThickness);
     337            secondRect.move(-strokeThickness / 2, 0);
    327338        } else {
    328             fillRectSourceOver(cr, FloatRect(p1.x() - width, p1.y() - width/2, width, width), strokeColor());
    329             fillRectSourceOver(cr, FloatRect(p2.x(), p2.y() - width/2, width, width), strokeColor());
     339            firstRect.move(-strokeThickness, -strokeThickness / 2);
     340            secondRect.move(0, -strokeThickness / 2);
    330341        }
    331 
    332         // Example: 80 pixels with a width of 30 pixels.
    333         // Remainder is 20.  The maximum pixels of line we could paint
    334         // will be 50 pixels.
    335         int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*static_cast<int>(width);
    336         int remainder = distance%patWidth;
    337         int coverage = distance-remainder;
    338         int numSegments = coverage/patWidth;
    339 
    340         float patternOffset = 0;
    341         // Special case 1px dotted borders for speed.
    342         if (patWidth == 1)
    343             patternOffset = 1.0;
    344         else {
    345             bool evenNumberOfSegments = !(numSegments % 2);
    346             if (remainder)
    347                 evenNumberOfSegments = !evenNumberOfSegments;
    348             if (evenNumberOfSegments) {
    349                 if (remainder) {
    350                     patternOffset += patWidth - remainder;
    351                     patternOffset += remainder / 2;
    352                 } else
    353                     patternOffset = patWidth / 2;
    354             } else if (!evenNumberOfSegments) {
    355                 if (remainder)
    356                     patternOffset = (patWidth - remainder) / 2;
    357             }
    358         }
    359 
    360         double dash = patWidth;
    361         cairo_set_dash(cr, &dash, 1, patternOffset);
    362     }
    363 
    364     cairo_move_to(cr, p1.x(), p1.y());
    365     cairo_line_to(cr, p2.x(), p2.y());
    366 
    367     cairo_stroke(cr);
    368     cairo_restore(cr);
     342        fillRectSourceOver(context, firstRect, strokeColor);
     343        fillRectSourceOver(context, secondRect, strokeColor);
     344
     345        int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2 * strokeThickness;
     346        double patternOffset = calculateStrokePatternOffset(distance, patternWidth);
     347        double patternWidthAsDouble = patternWidth;
     348        cairo_set_dash(context, &patternWidthAsDouble, 1, patternOffset);
     349    }
     350
     351    setSourceRGBAFromColor(context, strokeColor);
     352    cairo_set_line_width(context, strokeThickness);
     353    cairo_move_to(context, point1OnPixelBoundaries.x(), point1OnPixelBoundaries.y());
     354    cairo_line_to(context, point2OnPixelBoundaries.x(), point2OnPixelBoundaries.y());
     355    cairo_stroke(context);
     356}
     357
     358// This is only used to draw borders, so we should not draw shadows.
     359void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
     360{
     361    if (paintingDisabled())
     362        return;
     363
     364    cairo_t* cairoContext = platformContext()->cr();
     365    cairo_save(cairoContext);
     366    drawLineOnCairoContext(this, cairoContext, point1, point2);
     367    cairo_restore(cairoContext);
    369368}
    370369
     
    425424        cairo_scale(cr, 1., reverseScaleFactor);
    426425
    427     float width = strokeThickness();
    428     int patWidth = 0;
    429 
     426    int patternWidth = 0;
    430427    switch (strokeStyle()) {
    431428    case DottedStroke:
    432         patWidth = static_cast<int>(width / 2);
     429        patternWidth = floorf(strokeThickness() / 2.f);
    433430        break;
    434431    case DashedStroke:
    435         patWidth = 3 * static_cast<int>(width / 2);
     432        patternWidth = 3 * floorf(strokeThickness() / 2.f);
    436433        break;
    437434    default:
     
    441438    setSourceRGBAFromColor(cr, strokeColor());
    442439
    443     if (patWidth) {
    444         // Example: 80 pixels with a width of 30 pixels.
    445         // Remainder is 20.  The maximum pixels of line we could paint
    446         // will be 50 pixels.
    447         int distance;
     440    if (patternWidth) {
     441        float distance = 0;
    448442        if (hRadius == vRadius)
    449             distance = static_cast<int>((M_PI * hRadius) / 2.0);
     443            distance = (piFloat * hRadius) / 2.f;
    450444        else // We are elliptical and will have to estimate the distance
    451             distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0);
    452 
    453         int remainder = distance % patWidth;
    454         int coverage = distance - remainder;
    455         int numSegments = coverage / patWidth;
    456 
    457         float patternOffset = 0.0;
    458         // Special case 1px dotted borders for speed.
    459         if (patWidth == 1)
    460             patternOffset = 1.0;
    461         else {
    462             bool evenNumberOfSegments = !(numSegments % 2);
    463             if (remainder)
    464                 evenNumberOfSegments = !evenNumberOfSegments;
    465             if (evenNumberOfSegments) {
    466                 if (remainder) {
    467                     patternOffset += patWidth - remainder;
    468                     patternOffset += remainder / 2.0;
    469                 } else
    470                     patternOffset = patWidth / 2.0;
    471             } else {
    472                 if (remainder)
    473                     patternOffset = (patWidth - remainder) / 2.0;
    474             }
    475         }
    476 
    477         double dash = patWidth;
    478         cairo_set_dash(cr, &dash, 1, patternOffset);
     445            distance = (piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.f)) / 2.f;
     446        double patternOffset = calculateStrokePatternOffset(floorf(distance), patternWidth);
     447        double patternWidthAsDouble = patternWidth;
     448        cairo_set_dash(cr, &patternWidthAsDouble, 1, patternOffset);
    479449    }
    480450
     
    716686        return;
    717687
    718     FloatPoint endPoint = origin + FloatSize(width, 0);
    719    
    720     // FIXME: Loss of precision here. Might consider rounding.
    721     drawLine(IntPoint(origin.x(), origin.y()), IntPoint(endPoint.x(), endPoint.y()));
     688    cairo_t* cairoContext = platformContext()->cr();
     689    cairo_save(cairoContext);
     690
     691    // This bumping of <1 stroke thicknesses matches the one in drawLineOnCairoContext.
     692    FloatPoint endPoint(origin + IntSize(width, 0));
     693    FloatRect lineExtents(origin, FloatSize(width, strokeThickness()));
     694
     695    ContextShadow* shadow = contextShadow();
     696    ASSERT(shadow);
     697    cairo_t* shadowContext = shadow->beginShadowLayer(this, lineExtents);
     698    if (shadowContext) {
     699        drawLineOnCairoContext(this, shadowContext, origin, endPoint);
     700        shadow->endShadowLayer(this);
     701    }
     702
     703    drawLineOnCairoContext(this, cairoContext, origin, endPoint);
     704    cairo_restore(cairoContext);
    722705}
    723706
Note: See TracChangeset for help on using the changeset viewer.