Changeset 228776 in webkit


Ignore:
Timestamp:
Feb 20, 2018 2:52:16 AM (6 years ago)
Author:
zandobersek@gmail.com
Message:

[Cairo] Leverage ShadowBlur without using scratch buffer, target GraphicsContext
https://bugs.webkit.org/show_bug.cgi?id=182958

Reviewed by Carlos Garcia Campos.

To allow ShadowBlur usage in different threads, avoid the ShadowBlur
class using the scratch buffer internally. The current implementation of
that scratch buffer is not thread-safe and its usage in such conditions
can lead to crashes.

Instead, the new methods use a temporary ImageBuffer object for drawing.
This does negate the efficiency of possibly reusing the scratch buffer,
but at this point that is not yet the priority. This only affects ports
using Cairo for drawing.

The added methods don't require a target GraphicsContext object to be
passed in, instead they accept buffer draw callbacks that are invoked
with the temporary ImageBuffer object containing the rasterized shadow,
as well as position and size parameters. The CTM and clip bounds values
also have to be passed in manually. In CairoOperations.cpp, the provided
callbacks invoke commands that are equivalent in effect to those that
would otherwise be invoked on the target GraphicsContext object in the
ShadowBlur class.

For now, this approach has to avoid the tiling-based drawing of the
rectangular shadows in drawRectShadow() and inset shadows in
drawInsetShadow(), and instead stick to the non-tiling fallback. While
only affecting Cairo-using ports, with some refactoring it should be
possible to again leverage the tiling-based approach as well.

The beginShadowLayer() and endShadowLayer() functions, which are only
used in CairoOperations.cpp, are replaced with the drawShadowLayer()
method. This one accepts an additional callback that allows the caller
to explicitly draw the shadow shape using the provided shadowing
GraphicsContext object. As with the other two new methods, a temporary
ImageBuffer object is used, and the buffer draw callback is invoked to
allow caller to properly handle the shadowing output.

In CairoOperations.cpp, the new ShadowBlur methods are exercised, with
direct Cairo operation invocation replacing the GraphicsContext calls
otherwise done through ShadowBlur. ShadowState object now also has to
track the global alpha and the global composite operator values so that
it can properly rasterize the resulting shadow into the final image.

No new tests -- no change in behavior.

  • platform/graphics/ShadowBlur.cpp:

(WebCore::ShadowBlur::adjustBlurRadius):
(WebCore::ShadowBlur::calculateLayerBoundingRect):
(WebCore::ShadowBlur::drawRectShadow):
(WebCore::ShadowBlur::drawInsetShadow):
(WebCore::ShadowBlur::drawShadowLayer):
(WebCore::ShadowBlur::beginShadowLayer): Deleted.
(WebCore::ShadowBlur::endShadowLayer): Deleted.

  • platform/graphics/ShadowBlur.h:
  • platform/graphics/cairo/CairoOperations.cpp:

(WebCore::Cairo::drawShadowLayerBuffer):
(WebCore::Cairo::fillShadowBuffer):
(WebCore::Cairo::drawPathShadow):
(WebCore::Cairo::drawGlyphsShadow):
(WebCore::Cairo::ShadowState::ShadowState):
(WebCore::Cairo::fillRect):
(WebCore::Cairo::fillRoundedRect):
(WebCore::Cairo::fillRectWithRoundedHole):
(WebCore::Cairo::drawSurface):

  • platform/graphics/cairo/CairoOperations.h:

Default-initialize FillSource::fillRule to RULE_NONZERO.

  • platform/graphics/cairo/PlatformContextCairo.h:

Drop the ShadowBlur.h include, it's moved to CairoOperations.cpp.

  • rendering/RenderThemeGtk.cpp:

Explicitly include the FloatRoundedRect.h header now that it's not
included through the ShadowBlur.h header via PlatformContextCairo.h.

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r228771 r228776  
     12018-02-20  Zan Dobersek  <zdobersek@igalia.com>
     2
     3        [Cairo] Leverage ShadowBlur without using scratch buffer, target GraphicsContext
     4        https://bugs.webkit.org/show_bug.cgi?id=182958
     5
     6        Reviewed by Carlos Garcia Campos.
     7
     8        To allow ShadowBlur usage in different threads, avoid the ShadowBlur
     9        class using the scratch buffer internally. The current implementation of
     10        that scratch buffer is not thread-safe and its usage in such conditions
     11        can lead to crashes.
     12
     13        Instead, the new methods use a temporary ImageBuffer object for drawing.
     14        This does negate the efficiency of possibly reusing the scratch buffer,
     15        but at this point that is not yet the priority. This only affects ports
     16        using Cairo for drawing.
     17
     18        The added methods don't require a target GraphicsContext object to be
     19        passed in, instead they accept buffer draw callbacks that are invoked
     20        with the temporary ImageBuffer object containing the rasterized shadow,
     21        as well as position and size parameters. The CTM and clip bounds values
     22        also have to be passed in manually. In CairoOperations.cpp, the provided
     23        callbacks invoke commands that are equivalent in effect to those that
     24        would otherwise be invoked on the target GraphicsContext object in the
     25        ShadowBlur class.
     26
     27        For now, this approach has to avoid the tiling-based drawing of the
     28        rectangular shadows in drawRectShadow() and inset shadows in
     29        drawInsetShadow(), and instead stick to the non-tiling fallback. While
     30        only affecting Cairo-using ports, with some refactoring it should be
     31        possible to again leverage the tiling-based approach as well.
     32
     33        The beginShadowLayer() and endShadowLayer() functions, which are only
     34        used in CairoOperations.cpp, are replaced with the drawShadowLayer()
     35        method. This one accepts an additional callback that allows the caller
     36        to explicitly draw the shadow shape using the provided shadowing
     37        GraphicsContext object. As with the other two new methods, a temporary
     38        ImageBuffer object is used, and the buffer draw callback is invoked to
     39        allow caller to properly handle the shadowing output.
     40
     41        In CairoOperations.cpp, the new ShadowBlur methods are exercised, with
     42        direct Cairo operation invocation replacing the GraphicsContext calls
     43        otherwise done through ShadowBlur. ShadowState object now also has to
     44        track the global alpha and the global composite operator values so that
     45        it can properly rasterize the resulting shadow into the final image.
     46
     47        No new tests -- no change in behavior.
     48
     49        * platform/graphics/ShadowBlur.cpp:
     50        (WebCore::ShadowBlur::adjustBlurRadius):
     51        (WebCore::ShadowBlur::calculateLayerBoundingRect):
     52        (WebCore::ShadowBlur::drawRectShadow):
     53        (WebCore::ShadowBlur::drawInsetShadow):
     54        (WebCore::ShadowBlur::drawShadowLayer):
     55        (WebCore::ShadowBlur::beginShadowLayer): Deleted.
     56        (WebCore::ShadowBlur::endShadowLayer): Deleted.
     57        * platform/graphics/ShadowBlur.h:
     58        * platform/graphics/cairo/CairoOperations.cpp:
     59        (WebCore::Cairo::drawShadowLayerBuffer):
     60        (WebCore::Cairo::fillShadowBuffer):
     61        (WebCore::Cairo::drawPathShadow):
     62        (WebCore::Cairo::drawGlyphsShadow):
     63        (WebCore::Cairo::ShadowState::ShadowState):
     64        (WebCore::Cairo::fillRect):
     65        (WebCore::Cairo::fillRoundedRect):
     66        (WebCore::Cairo::fillRectWithRoundedHole):
     67        (WebCore::Cairo::drawSurface):
     68        * platform/graphics/cairo/CairoOperations.h:
     69        Default-initialize FillSource::fillRule to RULE_NONZERO.
     70        * platform/graphics/cairo/PlatformContextCairo.h:
     71        Drop the ShadowBlur.h include, it's moved to CairoOperations.cpp.
     72        * rendering/RenderThemeGtk.cpp:
     73        Explicitly include the FloatRoundedRect.h header now that it's not
     74        included through the ShadowBlur.h header via PlatformContextCairo.h.
     75
    1762018-02-20  Sergio Villar Senin  <svillar@igalia.com>
    277
  • trunk/Source/WebCore/platform/graphics/ShadowBlur.cpp

    r227051 r228776  
    360360}
    361361
    362 void ShadowBlur::adjustBlurRadius(GraphicsContext& context)
    363 {
    364     if (!m_shadowsIgnoreTransforms)
    365         return;
    366 
    367     AffineTransform transform = context.getCTM();
    368     m_blurRadius.scale(1 / static_cast<float>(transform.xScale()), 1 / static_cast<float>(transform.yScale()));
     362void ShadowBlur::adjustBlurRadius(const AffineTransform& transform)
     363{
     364    if (m_shadowsIgnoreTransforms)
     365        m_blurRadius.scale(1 / static_cast<float>(transform.xScale()), 1 / static_cast<float>(transform.yScale()));
    369366}
    370367
     
    383380}
    384381
    385 IntSize ShadowBlur::calculateLayerBoundingRect(GraphicsContext& context, const FloatRect& shadowedRect, const IntRect& clipRect)
     382IntSize ShadowBlur::calculateLayerBoundingRect(const AffineTransform& transform, const FloatRect& shadowedRect, const IntRect& clipRect)
    386383{
    387384    IntSize edgeSize = blurredEdgeSize();
     
    391388    IntSize inflation;
    392389
    393     const AffineTransform transform = context.getCTM();
    394390    if (m_shadowsIgnoreTransforms && !transform.isIdentity()) {
    395391        FloatQuad transformedPolygon = transform.mapQuad(FloatQuad(shadowedRect));
     
    498494void ShadowBlur::drawRectShadow(GraphicsContext& graphicsContext, const FloatRoundedRect& shadowedRect)
    499495{
    500     IntSize layerSize = calculateLayerBoundingRect(graphicsContext, shadowedRect.rect(), graphicsContext.clipBounds());
     496    IntSize layerSize = calculateLayerBoundingRect(graphicsContext.getCTM(), shadowedRect.rect(), graphicsContext.clipBounds());
    501497    if (layerSize.isEmpty())
    502498        return;
    503499
    504     adjustBlurRadius(graphicsContext);
     500    adjustBlurRadius(graphicsContext.getCTM());
    505501
    506502    // drawRectShadowWithTiling does not work with rotations.
     
    526522void ShadowBlur::drawInsetShadow(GraphicsContext& graphicsContext, const FloatRect& rect, const FloatRoundedRect& holeRect)
    527523{
    528     IntSize layerSize = calculateLayerBoundingRect(graphicsContext, rect, graphicsContext.clipBounds());
     524    IntSize layerSize = calculateLayerBoundingRect(graphicsContext.getCTM(), rect, graphicsContext.clipBounds());
    529525    if (layerSize.isEmpty())
    530526        return;
    531527
    532     adjustBlurRadius(graphicsContext);
     528    adjustBlurRadius(graphicsContext.getCTM());
    533529
    534530    // drawInsetShadowWithTiling does not work with rotations.
     
    550546
    551547    drawInsetShadowWithTiling(graphicsContext, rect, holeRect, templateSize, edgeSize);
     548}
     549
     550void ShadowBlur::drawRectShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRoundedRect& shadowedRect, const DrawBufferCallback& drawBuffer)
     551{
     552    // FIXME: Try incorporating tile-based rect shadow drawing for the same use case.
     553
     554    IntSize layerSize = calculateLayerBoundingRect(transform, shadowedRect.rect(), clipBounds);
     555    if (layerSize.isEmpty())
     556        return;
     557
     558    adjustBlurRadius(transform);
     559
     560    auto layerImage = ImageBuffer::create(layerSize, Unaccelerated, 1);
     561    if (!layerImage)
     562        return;
     563    m_layerImage = layerImage.get();
     564
     565    {
     566        GraphicsContext& shadowContext = layerImage->context();
     567        GraphicsContextStateSaver stateSaver(shadowContext);
     568        shadowContext.translate(m_layerContextTranslation);
     569        shadowContext.setFillColor(Color::black);
     570        if (shadowedRect.radii().isZero())
     571            shadowContext.fillRect(shadowedRect.rect());
     572        else {
     573            Path path;
     574            path.addRoundedRect(shadowedRect);
     575            shadowContext.fillPath(path);
     576        }
     577
     578        blurShadowBuffer(layerSize);
     579    }
     580
     581    drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
     582}
     583
     584void ShadowBlur::drawInsetShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRect& rect, const FloatRoundedRect& holeRect, const DrawBufferCallback& drawBuffer)
     585{
     586    // FIXME: Try incorporating tile-based inset shadow drawing for the same use case.
     587
     588    IntSize layerSize = calculateLayerBoundingRect(transform, rect, clipBounds);
     589    if (layerSize.isEmpty())
     590        return;
     591
     592    adjustBlurRadius(transform);
     593
     594    auto layerImage = ImageBuffer::create(layerSize, Unaccelerated, 1);
     595    if (!layerImage)
     596        return;
     597    m_layerImage = layerImage.get();
     598
     599    {
     600        GraphicsContext& shadowContext = layerImage->context();
     601        GraphicsContextStateSaver stateSaver(shadowContext);
     602        shadowContext.translate(m_layerContextTranslation);
     603
     604        Path path;
     605        path.addRect(rect);
     606        if (holeRect.radii().isZero())
     607            path.addRect(holeRect.rect());
     608        else
     609            path.addRoundedRect(holeRect);
     610
     611        shadowContext.setFillRule(RULE_EVENODD);
     612        shadowContext.setFillColor(Color::black);
     613        shadowContext.fillPath(path);
     614
     615        blurShadowBuffer(layerSize);
     616    }
     617
     618    drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
    552619}
    553620
     
    875942}
    876943
    877 GraphicsContext* ShadowBlur::beginShadowLayer(GraphicsContext& context, const FloatRect& layerArea)
    878 {
    879     adjustBlurRadius(context);
    880 
    881     IntSize layerSize = calculateLayerBoundingRect(context, layerArea, context.clipBounds());
    882 
     944void ShadowBlur::drawShadowLayer(const AffineTransform& transform, const IntRect& clipBounds, const FloatRect& layerArea, const DrawShadowCallback& drawShadow, const DrawBufferCallback& drawBuffer)
     945{
     946    IntSize layerSize = calculateLayerBoundingRect(transform, layerArea, clipBounds);
    883947    if (layerSize.isEmpty())
    884         return nullptr;
    885 
    886     // We reset the scratch buffer values here, because the buffer will no longer contain
    887     // data from any previous rectangle or inset shadows drawn via the tiling path.
    888     auto& scratchBuffer = ScratchBuffer::singleton();
    889     scratchBuffer.setCachedShadowValues(FloatSize(), Color::black, IntRect(), FloatRoundedRect::Radii(), m_layerSize);
    890     m_layerImage = scratchBuffer.getScratchBuffer(layerSize);
    891 
    892     GraphicsContext& shadowContext = m_layerImage->context();
    893     shadowContext.save();
    894 
    895     // Add a pixel to avoid later edge aliasing when rotated.
    896     shadowContext.clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1));
    897 
    898     shadowContext.translate(m_layerContextTranslation);
    899     return &shadowContext;
    900 }
    901 
    902 void ShadowBlur::endShadowLayer(GraphicsContext& context)
    903 {
    904     m_layerImage->context().restore();
     948        return;
     949
     950    adjustBlurRadius(transform);
     951
     952    auto layerImage = ImageBuffer::create(layerSize, Unaccelerated, 1);
     953    if (!layerImage)
     954        return;
     955    m_layerImage = layerImage.get();
     956
     957    {
     958        GraphicsContext& shadowContext = layerImage->context();
     959        GraphicsContextStateSaver stateSaver(shadowContext);
     960        shadowContext.translate(m_layerContextTranslation);
     961        drawShadow(shadowContext);
     962    }
    905963
    906964    blurAndColorShadowBuffer(expandedIntSize(m_layerSize));
    907     GraphicsContextStateSaver stateSave(context);
    908 
    909     context.clearShadow();
    910     context.drawImageBuffer(*m_layerImage, FloatRect(roundedIntPoint(m_layerOrigin), m_layerSize), FloatRect(FloatPoint(), m_layerSize), context.compositeOperation());
    911 
    912     m_layerImage = nullptr;
    913     ScratchBuffer::singleton().scheduleScratchBufferPurge();
     965    drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
    914966}
    915967
  • trunk/Source/WebCore/platform/graphics/ShadowBlur.h

    r227051 r228776  
    3333#include "FloatRect.h"
    3434#include "FloatRoundedRect.h"
     35#include <wtf/Function.h>
    3536#include <wtf/Noncopyable.h>
    3637
     
    6061    bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; }
    6162
    62     GraphicsContext* beginShadowLayer(GraphicsContext&, const FloatRect& layerArea);
    63     void endShadowLayer(GraphicsContext&);
    64 
    6563    void drawRectShadow(GraphicsContext&, const FloatRoundedRect&);
    6664    void drawInsetShadow(GraphicsContext&, const FloatRect&, const FloatRoundedRect& holeRect);
     65
     66    using DrawBufferCallback = WTF::Function<void(ImageBuffer&, const FloatPoint&, const FloatSize&, const FloatRect&)>;
     67    void drawRectShadow(const AffineTransform&, const IntRect&, const FloatRoundedRect&, const DrawBufferCallback&);
     68    void drawInsetShadow(const AffineTransform&, const IntRect&, const FloatRect&, const FloatRoundedRect&, const DrawBufferCallback&);
     69
     70    using DrawShadowCallback = WTF::Function<void(GraphicsContext&)>;
     71    void drawShadowLayer(const AffineTransform&, const IntRect&, const FloatRect&, const DrawShadowCallback&, const DrawBufferCallback&);
    6772
    6873    void blurLayerImage(unsigned char*, const IntSize&, int stride);
     
    7782    void drawShadowBuffer(GraphicsContext&);
    7883
    79     void adjustBlurRadius(GraphicsContext&);
     84    void adjustBlurRadius(const AffineTransform&);
    8085   
    8186    enum ShadowDirection {
     
    8489    };
    8590   
    86     IntSize calculateLayerBoundingRect(GraphicsContext&, const FloatRect& layerArea, const IntRect& clipRect);
     91    IntSize calculateLayerBoundingRect(const AffineTransform&, const FloatRect& layerArea, const IntRect& clipRect);
    8792    IntSize templateSize(const IntSize& blurredEdgeSize, const FloatRoundedRect::Radii&) const;
    8893
  • trunk/Source/WebCore/platform/graphics/cairo/CairoOperations.cpp

    r227292 r228776  
    4242#include "GraphicsContextPlatformPrivateCairo.h"
    4343#include "Image.h"
     44#include "ImageBuffer.h"
    4445#include "Path.h"
    4546#include "PlatformContextCairo.h"
    4647#include "PlatformPathCairo.h"
     48#include "ShadowBlur.h"
    4749#include <algorithm>
    4850#include <cairo.h>
     
    174176};
    175177
     178static void drawShadowLayerBuffer(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const ShadowState& shadowState, GraphicsContext& targetContext)
     179{
     180    RefPtr<Image> image = layerImage.copyImage(DontCopyBackingStore);
     181    if (!image)
     182        return;
     183
     184    if (auto surface = image->nativeImageForCurrentFrame()) {
     185        drawNativeImage(platformContext, surface.get(), FloatRect(roundedIntPoint(layerOrigin), layerSize), FloatRect(FloatPoint(), layerSize),
     186            shadowState.globalCompositeOperator, BlendModeNormal, ImageOrientation(),
     187            InterpolationDefault, shadowState.globalAlpha, ShadowState(), targetContext);
     188    }
     189}
     190
     191static void fillShadowBuffer(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect, const ShadowState& shadowState, GraphicsContext& targetContext)
     192{
     193    save(platformContext);
     194
     195    RefPtr<Image> image = layerImage.copyImage(DontCopyBackingStore);
     196    if (image) {
     197        if (auto surface = image->nativeImageForCurrentFrame())
     198            clipToImageBuffer(platformContext, surface.get(), FloatRect(layerOrigin, expandedIntSize(layerSize)));
     199    }
     200
     201    FillSource fillSource;
     202    fillSource.globalAlpha = shadowState.globalAlpha;
     203    fillSource.color = shadowState.color;
     204    fillRect(platformContext, FloatRect(layerOrigin, sourceRect.size()), fillSource, ShadowState(), targetContext);
     205
     206    restore(platformContext);
     207}
     208
    176209static inline void drawPathShadow(PlatformContextCairo& platformContext, const FillSource& fillSource, const StrokeSource& strokeSource, const ShadowState& shadowState, GraphicsContext& targetContext, PathDrawingStyle drawingStyle)
    177210{
     
    201234    }
    202235
    203     GraphicsContext* shadowContext = shadow.beginShadowLayer(targetContext, solidFigureExtents);
    204     if (!shadowContext)
    205         return;
    206 
    207     cairo_t* cairoShadowContext = shadowContext->platformContext()->cr();
    208 
    209     // It's important to copy the context properties to the new shadow
    210     // context to preserve things such as the fill rule and stroke width.
    211     copyContextProperties(cairoContext, cairoShadowContext);
    212 
    213     if (drawingStyle & Fill) {
    214         cairo_save(cairoShadowContext);
    215         cairo_append_path(cairoShadowContext, path.get());
    216         prepareForFilling(cairoShadowContext, fillSource, NoAdjustment);
    217         cairo_fill(cairoShadowContext);
    218         cairo_restore(cairoShadowContext);
    219     }
    220 
    221     if (drawingStyle & Stroke) {
    222         cairo_append_path(cairoShadowContext, path.get());
    223         prepareForStroking(cairoShadowContext, strokeSource, DoNotPreserveAlpha);
    224         cairo_stroke(cairoShadowContext);
    225     }
    226 
    227     // The original path may still be hanging around on the context and endShadowLayer
    228     // will take care of properly creating a path to draw the result shadow. We remove the path
    229     // temporarily and then restore it.
    230     // See: https://bugs.webkit.org/show_bug.cgi?id=108897
    231     cairo_new_path(cairoContext);
    232     shadow.endShadowLayer(targetContext);
    233     cairo_append_path(cairoContext, path.get());
     236    shadow.drawShadowLayer(State::getCTM(platformContext), State::getClipBounds(platformContext), solidFigureExtents,
     237        [cairoContext, drawingStyle, &path, &fillSource, &strokeSource](GraphicsContext& shadowContext)
     238        {
     239            cairo_t* cairoShadowContext = shadowContext.platformContext()->cr();
     240
     241            // It's important to copy the context properties to the new shadow
     242            // context to preserve things such as the fill rule and stroke width.
     243            copyContextProperties(cairoContext, cairoShadowContext);
     244
     245            if (drawingStyle & Fill) {
     246                cairo_save(cairoShadowContext);
     247                cairo_append_path(cairoShadowContext, path.get());
     248                prepareForFilling(cairoShadowContext, fillSource, NoAdjustment);
     249                cairo_fill(cairoShadowContext);
     250                cairo_restore(cairoShadowContext);
     251            }
     252
     253            if (drawingStyle & Stroke) {
     254                cairo_append_path(cairoShadowContext, path.get());
     255                prepareForStroking(cairoShadowContext, strokeSource, DoNotPreserveAlpha);
     256                cairo_stroke(cairoShadowContext);
     257            }
     258        },
     259        [&platformContext, &shadowState, &cairoContext, &path, &targetContext](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
     260        {
     261            // The original path may still be hanging around on the context and endShadowLayer
     262            // will take care of properly creating a path to draw the result shadow. We remove the path
     263            // temporarily and then restore it.
     264            // See: https://bugs.webkit.org/show_bug.cgi?id=108897
     265            cairo_new_path(cairoContext);
     266
     267            drawShadowLayerBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState, targetContext);
     268
     269            cairo_append_path(cairoContext, path.get());
     270        });
    234271}
    235272
     
    313350    FloatRect fontExtentsRect(point.x() + extents.x_bearing, point.y() + extents.y_bearing, extents.width, extents.height);
    314351
    315     if (GraphicsContext* shadowContext = shadow.beginShadowLayer(targetContext, fontExtentsRect)) {
    316         drawGlyphsToContext(shadowContext->platformContext()->cr(), scaledFont, syntheticBoldOffset, glyphs);
    317         shadow.endShadowLayer(targetContext);
    318     }
     352    shadow.drawShadowLayer(State::getCTM(platformContext), State::getClipBounds(platformContext), fontExtentsRect,
     353        [scaledFont, syntheticBoldOffset, &glyphs](GraphicsContext& shadowContext)
     354        {
     355            drawGlyphsToContext(shadowContext.platformContext()->cr(), scaledFont, syntheticBoldOffset, glyphs);
     356        },
     357        [&platformContext, &shadowState, &targetContext](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
     358        {
     359            drawShadowLayerBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState, targetContext);
     360        });
    319361}
    320362
     
    563605    , color(state.shadowColor)
    564606    , ignoreTransforms(state.shadowsIgnoreTransforms)
     607    , globalAlpha(state.alpha)
     608    , globalCompositeOperator(state.compositeOperator)
    565609{
    566610}
     
    650694    if (shadowState.isVisible()) {
    651695        ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
    652         shadow.drawRectShadow(targetContext, FloatRoundedRect(rect));
     696        shadow.drawRectShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), FloatRoundedRect(rect),
     697            [&platformContext, &shadowState, &targetContext](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
     698            {
     699                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState, targetContext);
     700            });
    653701    }
    654702
     
    669717    if (shadowState.isVisible()) {
    670718        ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
    671         shadow.drawRectShadow(targetContext, rect);
     719        shadow.drawRectShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), rect,
     720            [&platformContext, &shadowState, &targetContext](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
     721            {
     722                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState, targetContext);
     723            });
    672724    }
    673725
     
    690742    if (shadowState.isRequired(platformContext)) {
    691743        ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
    692         shadow.drawInsetShadow(targetContext, rect, roundedHoleRect);
     744        shadow.drawInsetShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), rect, roundedHoleRect,
     745            [&platformContext, &shadowState, &targetContext](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
     746            {
     747                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState, targetContext);
     748            });
    693749    }
    694750
     
    814870}
    815871
    816 void drawSurface(PlatformContextCairo& platformContext, cairo_surface_t* surface, const FloatRect& destRect, const FloatRect& originalSrcRect, InterpolationQuality imageInterpolationQuality, float globalAlpha, const ShadowState& shadowState, GraphicsContext& context)
     872void drawSurface(PlatformContextCairo& platformContext, cairo_surface_t* surface, const FloatRect& destRect, const FloatRect& originalSrcRect, InterpolationQuality imageInterpolationQuality, float globalAlpha, const ShadowState& shadowState, GraphicsContext& targetContext)
    817873{
    818874    // Avoid invalid cairo matrix with small values.
     
    876932    ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
    877933    if (shadow.type() != ShadowBlur::NoShadow) {
    878         if (GraphicsContext* shadowContext = shadow.beginShadowLayer(context, destRect)) {
    879             drawPatternToCairoContext(shadowContext->platformContext()->cr(), pattern.get(), destRect, 1);
    880             shadow.endShadowLayer(context);
    881         }
     934        shadow.drawShadowLayer(State::getCTM(platformContext), State::getClipBounds(platformContext), destRect,
     935            [&pattern, &destRect](GraphicsContext& shadowContext)
     936            {
     937                drawPatternToCairoContext(shadowContext.platformContext()->cr(), pattern.get(), destRect, 1);
     938            },
     939            [&platformContext, &shadowState, &targetContext](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
     940            {
     941                drawShadowLayerBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState, targetContext);
     942            });
    882943    }
    883944
  • trunk/Source/WebCore/platform/graphics/cairo/CairoOperations.h

    r227593 r228776  
    9191    Color color;
    9292
    93     WindRule fillRule;
     93    WindRule fillRule { RULE_NONZERO };
    9494};
    9595
     
    108108
    109109struct ShadowState {
     110    ShadowState() = default;
    110111    WEBCORE_EXPORT explicit ShadowState(const GraphicsContextState&);
    111112
     
    117118    Color color;
    118119    bool ignoreTransforms { false };
     120
     121    float globalAlpha { 1.0 };
     122    CompositeOperator globalCompositeOperator { CompositeSourceOver };
    119123};
    120124
  • trunk/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h

    r227292 r228776  
    3131#include "GraphicsContext.h"
    3232#include "RefPtrCairo.h"
    33 #include "ShadowBlur.h"
    3433
    3534namespace WebCore {
  • trunk/Source/WebCore/rendering/RenderThemeGtk.cpp

    r224371 r228776  
    2929#include "FileList.h"
    3030#include "FileSystem.h"
     31#include "FloatRoundedRect.h"
    3132#include "FontDescription.h"
    3233#include "GRefPtrGtk.h"
Note: See TracChangeset for help on using the changeset viewer.