Changeset 244913 in webkit


Ignore:
Timestamp:
May 3, 2019 11:31:06 AM (5 years ago)
Author:
commit-queue@webkit.org
Message:

[Cairo] Improve ShadowBlur performance using tiling optimization
https://bugs.webkit.org/show_bug.cgi?id=197308
Patch by Tomoki Imai <Tomoki Imai> on 2019-05-03
Reviewed by Žan Doberšek.

Enable tiling tiling-based optimization for drawRectShadow() and drawInsetShadow().
Since r228776, cairo ports doesn't have tiling-based optimization.

For AppleWin, this patch refactors code and it shares almost same code as cairo port.
Only the difference is that AppleWin uses ScratchBuffer, but cairo ports doesn't.
This should avoid a performance regression for AppleWin.

No new tests, covered by existing tests.

  • platform/graphics/ShadowBlur.cpp:

(WebCore::calculateLobes):
Fix stylecheck errors

(WebCore::ShadowBlur::blurLayerImage):
Fix stylecheck errors

(WebCore::ShadowBlur::calculateLayerBoundingRect):
We don't use position of m_sourceRect, so change the type to FloatSize.

(WebCore::ShadowBlur::drawShadowBuffer):
Use m_layerSize instead of m_shadowedResultSize to fillRect, as m_layerSize is always smaller than m_shadowedResultSize.
It's because in m_layerSize is equal to m_shadowedResultSize if it's not clipped.
Clipping doesn't increase size of m_layerSize, so m_layerSize is always smaller than or equal to m_shadowedResultSize.

(WebCore::ShadowBlur::templateSize const):
Fix stylecheck errors

(WebCore::ShadowBlur::drawRectShadow):
(WebCore::ShadowBlur::drawInsetShadow):
(WebCore::ShadowBlur::drawRectShadowWithoutTiling):
(WebCore::ShadowBlur::drawInsetShadowWithoutTiling):
(WebCore::ShadowBlur::drawRectShadowWithTiling):
(WebCore::ShadowBlur::drawInsetShadowWithTiling):
Incorporate tile-based drawing.
To accomplish it, this patch abstracts GraphicsContext::drawImageBuffer to ShadowBlur::DrawImageCallback,
GraphicsContext::fillRect to ShadowBlur::FillRectCallback, drawing rect with hole to ShadowBlur::FillRectWithHoleCallback.

Variants which takes GraphicsContext as parameter now just calls another drawRectShadow.

(WebCore::ShadowBlur::drawLayerPieces):
Instead of graphicsContext.drawImageBuffer, call corresponding callback.

(WebCore::ShadowBlur::drawLayerPiecesAndFillCenter):
This function calls drawLayerPieces and fill center for outer shadow.
Drawing outer shadow requires another callback for graphicsContext.fillRect.

(WebCore::ShadowBlur::drawShadowLayer):
Use m_layerSize instead of m_shadowedResultSize to fillRect,
as m_layerSize is always smaller than m_shadowedResultSize.

  • platform/graphics/ShadowBlur.h:

Rename m_sourceRect to m_shadowedResultSize, and change it to FloatSize from FloatRect.
Remove GraphicsContext usage as much as possible and replace them by corresponding callbacks.

  • platform/graphics/cairo/CairoOperations.cpp:

(WebCore::Cairo::drawShadowImage):
This function corresponds to ShadowBlur::DrawImageCallback.

(WebCore::Cairo::fillShadowBuffer):
Erase sourceRect, as it's always bigger than layerSize.

(WebCore::Cairo::drawPathShadow):
(WebCore::Cairo::drawGlyphsShadow):
Erase unused parameter.

(WebCore::Cairo::fillRect):
(WebCore::Cairo::fillRoundedRect):
(WebCore::Cairo::fillRectWithRoundedHole):
For tile-based optimization, add extra arguments to drawRectShadow.

(WebCore::Cairo::drawSurface):
Erase unused parameter.

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r244912 r244913  
     12019-05-03  Tomoki Imai  <Tomoki.Imai@sony.com>
     2
     3        [Cairo] Improve ShadowBlur performance using tiling optimization
     4        https://bugs.webkit.org/show_bug.cgi?id=197308
     5        Reviewed by Žan Doberšek.
     6
     7        Enable tiling tiling-based optimization for drawRectShadow() and drawInsetShadow().
     8        Since r228776, cairo ports doesn't have tiling-based optimization.
     9
     10        For AppleWin, this patch refactors code and it shares almost same code as cairo port.
     11        Only the difference is that AppleWin uses ScratchBuffer, but cairo ports doesn't.
     12        This should avoid a performance regression for AppleWin.
     13
     14        No new tests, covered by existing tests.
     15
     16        * platform/graphics/ShadowBlur.cpp:
     17        (WebCore::calculateLobes):
     18        Fix stylecheck errors
     19
     20        (WebCore::ShadowBlur::blurLayerImage):
     21        Fix stylecheck errors
     22
     23        (WebCore::ShadowBlur::calculateLayerBoundingRect):
     24        We don't use position of m_sourceRect, so change the type to FloatSize.
     25
     26        (WebCore::ShadowBlur::drawShadowBuffer):
     27        Use m_layerSize instead of m_shadowedResultSize to fillRect, as m_layerSize is always smaller than m_shadowedResultSize.
     28        It's because in m_layerSize is equal to m_shadowedResultSize if it's not clipped.
     29        Clipping doesn't increase size of m_layerSize, so m_layerSize is always smaller than or equal to m_shadowedResultSize.
     30
     31        (WebCore::ShadowBlur::templateSize const):
     32        Fix stylecheck errors
     33
     34        (WebCore::ShadowBlur::drawRectShadow):
     35        (WebCore::ShadowBlur::drawInsetShadow):
     36        (WebCore::ShadowBlur::drawRectShadowWithoutTiling):
     37        (WebCore::ShadowBlur::drawInsetShadowWithoutTiling):
     38        (WebCore::ShadowBlur::drawRectShadowWithTiling):
     39        (WebCore::ShadowBlur::drawInsetShadowWithTiling):
     40        Incorporate tile-based drawing.
     41        To accomplish it, this patch abstracts GraphicsContext::drawImageBuffer to ShadowBlur::DrawImageCallback,
     42        GraphicsContext::fillRect to ShadowBlur::FillRectCallback, drawing rect with hole to  ShadowBlur::FillRectWithHoleCallback.
     43
     44        Variants which takes GraphicsContext as parameter now just calls another drawRectShadow.
     45
     46        (WebCore::ShadowBlur::drawLayerPieces):
     47        Instead of graphicsContext.drawImageBuffer, call corresponding callback.
     48
     49        (WebCore::ShadowBlur::drawLayerPiecesAndFillCenter):
     50        This function calls drawLayerPieces and fill center for outer shadow.
     51        Drawing outer shadow requires another callback for graphicsContext.fillRect.
     52
     53        (WebCore::ShadowBlur::drawShadowLayer):
     54        Use m_layerSize instead of m_shadowedResultSize to fillRect,
     55        as m_layerSize is always smaller than m_shadowedResultSize.
     56
     57        * platform/graphics/ShadowBlur.h:
     58        Rename m_sourceRect to m_shadowedResultSize, and change it to FloatSize from FloatRect.
     59        Remove GraphicsContext usage as much as possible and replace them by corresponding callbacks.
     60
     61        * platform/graphics/cairo/CairoOperations.cpp:
     62        (WebCore::Cairo::drawShadowImage):
     63        This function corresponds to ShadowBlur::DrawImageCallback.
     64
     65        (WebCore::Cairo::fillShadowBuffer):
     66        Erase sourceRect, as it's always bigger than layerSize.
     67
     68        (WebCore::Cairo::drawPathShadow):
     69        (WebCore::Cairo::drawGlyphsShadow):
     70        Erase unused parameter.
     71
     72        (WebCore::Cairo::fillRect):
     73        (WebCore::Cairo::fillRoundedRect):
     74        (WebCore::Cairo::fillRectWithRoundedHole):
     75        For tile-based optimization, add extra arguments to drawRectShadow.
     76
     77        (WebCore::Cairo::drawSurface):
     78        Erase unused parameter.
     79
    1802019-05-03  Antti Koivisto  <antti@apple.com>
    281
  • trunk/Source/WebCore/platform/graphics/ShadowBlur.cpp

    r239461 r244913  
    2525 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2626 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2828 */
    2929
     
    4343
    4444enum {
    45     leftLobe = 0,
    46     rightLobe = 1
     45    LeftLobe = 0,
     46    RightLobe = 1
    4747};
    4848
     49#if USE(CG)
    4950static inline int roundUpToMultipleOf32(int d)
    5051{
     
    6667    {
    6768    }
    68    
     69
    6970    ImageBuffer* getScratchBuffer(const IntSize& size)
    7071    {
     
    128129        m_purgeTimer.startOneShot(scratchBufferPurgeInterval);
    129130    }
    130    
     131
    131132    static ScratchBuffer& singleton();
    132133
     
    141142    std::unique_ptr<ImageBuffer> m_imageBuffer;
    142143    Timer m_purgeTimer;
    143    
     144
    144145    FloatRect m_lastInsetBounds;
    145146    FloatRect m_lastShadowRect;
     
    149150    bool m_lastWasInset;
    150151    FloatSize m_lastLayerSize;
    151    
     152
    152153#if !ASSERT_DISABLED
    153154    bool m_bufferInUse;
     
    161162}
    162163
     164static float radiusToLegacyRadius(float radius)
     165{
     166    return radius > 8 ? 8 + 4 * sqrt((radius - 8) / 2) : radius;
     167}
     168#endif
     169
    163170static const int templateSideLength = 1;
    164 
    165 #if USE(CG)
    166 static float radiusToLegacyRadius(float radius)
    167 {
    168     return radius > 8 ? 8 + 4 * sqrt((radius - 8) / 2) : radius;
    169 }
    170 #endif
    171171
    172172ShadowBlur::ShadowBlur() = default;
     
    250250        // if d is odd, use three box-blurs of size 'd', centered on the output pixel.
    251251        int lobeSize = (diameter - 1) / 2;
    252         lobes[0][leftLobe] = lobeSize;
    253         lobes[0][rightLobe] = lobeSize;
    254         lobes[1][leftLobe] = lobeSize;
    255         lobes[1][rightLobe] = lobeSize;
    256         lobes[2][leftLobe] = lobeSize;
    257         lobes[2][rightLobe] = lobeSize;
     252        lobes[0][LeftLobe] = lobeSize;
     253        lobes[0][RightLobe] = lobeSize;
     254        lobes[1][LeftLobe] = lobeSize;
     255        lobes[1][RightLobe] = lobeSize;
     256        lobes[2][LeftLobe] = lobeSize;
     257        lobes[2][RightLobe] = lobeSize;
    258258    } else {
    259259        // if d is even, two box-blurs of size 'd' (the first one centered on the pixel boundary
     
    261261        // boundary between the output pixel and the one to the right) and one box blur of size 'd+1' centered on the output pixel
    262262        int lobeSize = diameter / 2;
    263         lobes[0][leftLobe] = lobeSize;
    264         lobes[0][rightLobe] = lobeSize - 1;
    265         lobes[1][leftLobe] = lobeSize - 1;
    266         lobes[1][rightLobe] = lobeSize;
    267         lobes[2][leftLobe] = lobeSize;
    268         lobes[2][rightLobe] = lobeSize;
     263        lobes[0][LeftLobe] = lobeSize;
     264        lobes[0][RightLobe] = lobeSize - 1;
     265        lobes[1][LeftLobe] = lobeSize - 1;
     266        lobes[1][RightLobe] = lobeSize;
     267        lobes[2][LeftLobe] = lobeSize;
     268        lobes[2][RightLobe] = lobeSize;
    269269    }
    270270}
     
    294294    for (int pass = 0; pass < 2; ++pass) {
    295295        unsigned char* pixels = imageData;
    296        
     296
    297297        if (!pass && !m_blurRadius.width())
    298298            final = 0; // Do no work if horizonal blur is zero.
     
    305305            // covered by the box kernel size for each x.
    306306            for (int step = 0; step < 3; ++step) {
    307                 int side1 = lobes[step][leftLobe];
    308                 int side2 = lobes[step][rightLobe];
     307                int side1 = lobes[step][LeftLobe];
     308                int side2 = lobes[step][RightLobe];
    309309                int pixelCount = side1 + 1 + side2;
    310310                int invCount = ((1 << blurSumShift) + pixelCount - 1) / pixelCount;
     
    332332                    sum += ((ofs < dim) ? *next : alpha2) - alpha1;
    333333                }
    334                
     334
    335335                prev = pixels + channels[step];
    336336                for (; ofs < dim; ptr += stride, prev += stride, next += stride, ++i, ++ofs) {
     
    338338                    sum += (*next) - (*prev);
    339339                }
    340                
     340
    341341                for (; i < dim; ptr += stride, prev += stride, ++i) {
    342342                    *ptr = (sum * invCount) >> blurSumShift;
     
    423423            inflatedClip.inflateY(1);
    424424        }
    425        
     425
    426426        layerRect.intersect(inflatedClip);
    427427    }
     
    429429    IntSize frameSize = inflation;
    430430    frameSize.scale(2);
    431     m_sourceRect = FloatRect(0, 0, shadowedRect.width() + frameSize.width(), shadowedRect.height() + frameSize.height());
     431    m_shadowedResultSize = FloatSize(shadowedRect.width() + frameSize.width(), shadowedRect.height() + frameSize.height());
    432432    m_layerOrigin = FloatPoint(layerRect.x(), layerRect.y());
    433433    m_layerSize = layerRect.size();
     
    462462
    463463    graphicsContext.clearShadow();
    464     graphicsContext.fillRect(FloatRect(m_layerOrigin, m_sourceRect.size()));
     464    graphicsContext.fillRect(FloatRect(m_layerOrigin, m_layerSize));
    465465}
    466466
     
    482482    int topSlice;
    483483    int bottomSlice;
    484    
     484
    485485    IntSize blurExpansion = radiusPadding;
    486486    blurExpansion.scale(2);
    487487
    488488    computeSliceSizesFromRadii(blurExpansion, radii, leftSlice, rightSlice, topSlice, bottomSlice);
    489    
    490     return IntSize(templateSideLength + leftSlice + rightSlice,
    491                    templateSideLength + topSlice + bottomSlice);
     489
     490    return IntSize(templateSideLength + leftSlice + rightSlice, templateSideLength + topSlice + bottomSlice);
    492491}
    493492
    494493void ShadowBlur::drawRectShadow(GraphicsContext& graphicsContext, const FloatRoundedRect& shadowedRect)
    495494{
    496     IntSize layerSize = calculateLayerBoundingRect(graphicsContext.getCTM(), shadowedRect.rect(), graphicsContext.clipBounds());
     495    drawRectShadow(graphicsContext.getCTM(), graphicsContext.clipBounds(), shadowedRect,
     496        [this, &graphicsContext](ImageBuffer&, const FloatPoint&, const FloatSize&) {
     497            // FIXME: Use parameters instead of implicit parameters defined as class variables.
     498            drawShadowBuffer(graphicsContext);
     499        },
     500        [&graphicsContext](ImageBuffer& image, const FloatRect& destRect, const FloatRect& srcRect) {
     501            GraphicsContextStateSaver stateSaver(graphicsContext);
     502            graphicsContext.clearShadow();
     503            graphicsContext.drawImageBuffer(image, destRect, srcRect);
     504        },
     505        [&graphicsContext](const FloatRect& rect, const Color& color) {
     506            GraphicsContextStateSaver stateSaver(graphicsContext);
     507            graphicsContext.setFillColor(color);
     508            graphicsContext.clearShadow();
     509            graphicsContext.fillRect(rect);
     510        });
     511}
     512
     513void ShadowBlur::drawInsetShadow(GraphicsContext& graphicsContext, const FloatRect& fullRect, const FloatRoundedRect& holeRect)
     514{
     515    drawInsetShadow(graphicsContext.getCTM(), graphicsContext.clipBounds(), fullRect, holeRect,
     516        [this, &graphicsContext](ImageBuffer&, const FloatPoint&, const FloatSize&) {
     517            // FIXME: Use parameters instead of implicit parameters defined as class variables.
     518            drawShadowBuffer(graphicsContext);
     519        },
     520        [&graphicsContext](ImageBuffer& image, const FloatRect& destRect, const FloatRect& srcRect) {
     521            // Note that drawing the ImageBuffer is faster than creating a Image and drawing that,
     522            // because ImageBuffer::draw() knows that it doesn't have to copy the image bits.
     523            GraphicsContextStateSaver stateSaver(graphicsContext);
     524            graphicsContext.clearShadow();
     525            graphicsContext.drawImageBuffer(image, destRect, srcRect);
     526        },
     527        [&graphicsContext](const FloatRect& rect, const FloatRect& holeRect, const Color& color) {
     528            Path exteriorPath;
     529            exteriorPath.addRect(rect);
     530            exteriorPath.addRect(holeRect);
     531
     532            GraphicsContextStateSaver fillStateSaver(graphicsContext);
     533            graphicsContext.setFillRule(WindRule::EvenOdd);
     534            graphicsContext.setFillColor(color);
     535            graphicsContext.clearShadow();
     536            graphicsContext.fillPath(exteriorPath);
     537        });
     538}
     539
     540void ShadowBlur::drawRectShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRoundedRect& shadowedRect, const DrawBufferCallback& drawBuffer, const DrawImageCallback& drawImage, const FillRectCallback& fillRect)
     541{
     542    IntSize layerSize = calculateLayerBoundingRect(transform, shadowedRect.rect(), clipBounds);
    497543    if (layerSize.isEmpty())
    498544        return;
    499545
    500     adjustBlurRadius(graphicsContext.getCTM());
     546    adjustBlurRadius(transform);
     547
     548    bool canUseTilingTechnique = true;
    501549
    502550    // drawRectShadowWithTiling does not work with rotations.
    503551    // https://bugs.webkit.org/show_bug.cgi?id=45042
    504     if (!graphicsContext.getCTM().preservesAxisAlignment() || m_type != BlurShadow) {
    505         drawRectShadowWithoutTiling(graphicsContext, shadowedRect, layerSize);
    506         return;
    507     }
     552    if (!transform.preservesAxisAlignment() || m_type != BlurShadow)
     553        canUseTilingTechnique = false;
    508554
    509555    IntSize edgeSize = blurredEdgeSize();
     
    512558
    513559    if (templateSize.width() > rect.width() || templateSize.height() > rect.height()
    514         || (templateSize.width() * templateSize.height() > m_sourceRect.width() * m_sourceRect.height())) {
    515         drawRectShadowWithoutTiling(graphicsContext, shadowedRect, layerSize);
    516         return;
    517     }
    518 
    519     drawRectShadowWithTiling(graphicsContext, shadowedRect, templateSize, edgeSize);
    520 }
    521 
    522 void ShadowBlur::drawInsetShadow(GraphicsContext& graphicsContext, const FloatRect& rect, const FloatRoundedRect& holeRect)
    523 {
    524     IntSize layerSize = calculateLayerBoundingRect(graphicsContext.getCTM(), rect, graphicsContext.clipBounds());
     560        || (templateSize.width() * templateSize.height() > m_shadowedResultSize.width() * m_shadowedResultSize.height()))
     561        canUseTilingTechnique = false;
     562
     563    if (canUseTilingTechnique)
     564        drawRectShadowWithTiling(transform, shadowedRect, templateSize, edgeSize, drawImage, fillRect);
     565    else
     566        drawRectShadowWithoutTiling(transform, shadowedRect, layerSize, drawBuffer);
     567}
     568
     569void ShadowBlur::drawInsetShadow(const AffineTransform& transform, const IntRect& clipBounds, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const DrawBufferCallback& drawBuffer, const DrawImageCallback& drawImage, const FillRectWithHoleCallback& fillRectWithHole)
     570{
     571    IntSize layerSize = calculateLayerBoundingRect(transform, fullRect, clipBounds);
    525572    if (layerSize.isEmpty())
    526573        return;
    527574
    528     adjustBlurRadius(graphicsContext.getCTM());
    529 
    530     // drawInsetShadowWithTiling does not work with rotations.
     575    adjustBlurRadius(transform);
     576
     577    bool canUseTilingTechnique = true;
     578
     579    // drawRectShadowWithTiling does not work with rotations.
    531580    // https://bugs.webkit.org/show_bug.cgi?id=45042
    532     if (!graphicsContext.getCTM().preservesAxisAlignment() || m_type != BlurShadow) {
    533         drawInsetShadowWithoutTiling(graphicsContext, rect, holeRect, layerSize);
    534         return;
    535     }
     581    if (!transform.preservesAxisAlignment() || m_type != BlurShadow)
     582        canUseTilingTechnique = false;
    536583
    537584    IntSize edgeSize = blurredEdgeSize();
     
    540587
    541588    if (templateSize.width() > hRect.width() || templateSize.height() > hRect.height()
    542         || (templateSize.width() * templateSize.height() > hRect.width() * hRect.height())) {
    543         drawInsetShadowWithoutTiling(graphicsContext, rect, holeRect, layerSize);
    544         return;
    545     }
    546 
    547     drawInsetShadowWithTiling(graphicsContext, rect, holeRect, templateSize, edgeSize);
    548 }
    549 
    550 void 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 
     589        || (templateSize.width() * templateSize.height() > hRect.width() * hRect.height()))
     590        canUseTilingTechnique = false;
     591
     592    if (canUseTilingTechnique)
     593        drawInsetShadowWithTiling(transform, fullRect, holeRect, templateSize, edgeSize, drawImage, fillRectWithHole);
     594    else
     595        drawInsetShadowWithoutTiling(transform, fullRect, holeRect, layerSize, drawBuffer);
     596}
     597
     598void ShadowBlur::drawRectShadowWithoutTiling(const AffineTransform&, const FloatRoundedRect& shadowedRect, const IntSize& layerSize, const DrawBufferCallback& drawBuffer)
     599{
    560600    auto layerImage = ImageBuffer::create(layerSize, Unaccelerated, 1);
    561601    if (!layerImage)
    562602        return;
    563603    m_layerImage = layerImage.get();
     604
     605    GraphicsContext& shadowContext = layerImage->context();
     606    GraphicsContextStateSaver stateSaver(shadowContext);
     607    shadowContext.setFillColor(Color::black);
    564608
    565609    {
     
    578622        blurShadowBuffer(layerSize);
    579623    }
    580 
    581     drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
    582 }
    583 
    584 void 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 
     624    drawBuffer(*layerImage, m_layerOrigin, m_layerSize);
     625}
     626
     627void ShadowBlur::drawInsetShadowWithoutTiling(const AffineTransform&, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& layerSize, const DrawBufferCallback& drawBuffer)
     628{
    594629    auto layerImage = ImageBuffer::create(layerSize, Unaccelerated, 1);
    595630    if (!layerImage)
     
    603638
    604639        Path path;
    605         path.addRect(rect);
     640        path.addRect(fullRect);
    606641        if (holeRect.radii().isZero())
    607642            path.addRect(holeRect.rect());
     
    616651    }
    617652
    618     drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
    619 }
    620 
    621 void ShadowBlur::drawRectShadowWithoutTiling(GraphicsContext& graphicsContext, const FloatRoundedRect& shadowedRect, const IntSize& layerSize)
    622 {
    623     m_layerImage = ScratchBuffer::singleton().getScratchBuffer(layerSize);
    624     if (!m_layerImage)
    625         return;
    626 
    627     FloatRect bufferRelativeShadowedRect = shadowedRect.rect();
    628     bufferRelativeShadowedRect.move(m_layerContextTranslation);
    629 
    630     // Only redraw in the scratch buffer if its cached contents don't match our needs
    631     bool redrawNeeded = ScratchBuffer::singleton().setCachedShadowValues(m_blurRadius, Color::black, bufferRelativeShadowedRect, shadowedRect.radii(), m_layerSize);
    632     if (redrawNeeded) {
    633         GraphicsContext& shadowContext = m_layerImage->context();
    634         GraphicsContextStateSaver stateSaver(shadowContext);
    635 
    636         // Add a pixel to avoid later edge aliasing when rotated.
    637         shadowContext.clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1));
    638         shadowContext.translate(m_layerContextTranslation);
    639         shadowContext.setFillColor(Color::black);
    640         if (shadowedRect.radii().isZero())
    641             shadowContext.fillRect(shadowedRect.rect());
    642         else {
    643             Path path;
    644             path.addRoundedRect(shadowedRect);
    645             shadowContext.fillPath(path);
    646         }
    647 
    648         blurShadowBuffer(layerSize);
    649     }
    650    
    651     drawShadowBuffer(graphicsContext);
    652     m_layerImage = nullptr;
    653     ScratchBuffer::singleton().scheduleScratchBufferPurge();
    654 }
    655 
    656 void ShadowBlur::drawInsetShadowWithoutTiling(GraphicsContext& graphicsContext, const FloatRect& rect, const FloatRoundedRect& holeRect, const IntSize& layerSize)
    657 {
    658     m_layerImage = ScratchBuffer::singleton().getScratchBuffer(layerSize);
    659     if (!m_layerImage)
    660         return;
    661 
    662     FloatRect bufferRelativeRect = rect;
    663     bufferRelativeRect.move(m_layerContextTranslation);
    664 
    665     FloatRect bufferRelativeHoleRect = holeRect.rect();
    666     bufferRelativeHoleRect.move(m_layerContextTranslation);
    667 
    668     // Only redraw in the scratch buffer if its cached contents don't match our needs
    669     bool redrawNeeded = ScratchBuffer::singleton().setCachedInsetShadowValues(m_blurRadius, Color::black, bufferRelativeRect, bufferRelativeHoleRect, holeRect.radii());
    670     if (redrawNeeded) {
    671         GraphicsContext& shadowContext = m_layerImage->context();
    672         GraphicsContextStateSaver stateSaver(shadowContext);
    673 
    674         // Add a pixel to avoid later edge aliasing when rotated.
    675         shadowContext.clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1));
    676         shadowContext.translate(m_layerContextTranslation);
    677 
    678         Path path;
    679         path.addRect(rect);
    680         if (holeRect.radii().isZero())
    681             path.addRect(holeRect.rect());
    682         else
    683             path.addRoundedRect(holeRect);
    684 
    685         shadowContext.setFillRule(WindRule::EvenOdd);
    686         shadowContext.setFillColor(Color::black);
    687         shadowContext.fillPath(path);
    688 
    689         blurShadowBuffer(layerSize);
    690     }
    691    
    692     drawShadowBuffer(graphicsContext);
    693     m_layerImage = nullptr;
    694     ScratchBuffer::singleton().scheduleScratchBufferPurge();
     653    drawBuffer(*layerImage, m_layerOrigin, m_layerSize);
    695654}
    696655
     
    727686 */
    728687
    729 void ShadowBlur::drawInsetShadowWithTiling(GraphicsContext& graphicsContext, const FloatRect& rect, const FloatRoundedRect& holeRect, const IntSize& templateSize, const IntSize& edgeSize)
    730 {
     688void ShadowBlur::drawRectShadowWithTiling(const AffineTransform& transform, const FloatRoundedRect& shadowedRect, const IntSize& templateSize, const IntSize& edgeSize, const DrawImageCallback& drawImage, const FillRectCallback& fillRect)
     689{
     690#if USE(CG)
    731691    m_layerImage = ScratchBuffer::singleton().getScratchBuffer(templateSize);
     692#else
     693    auto layerImage = ImageBuffer::create(templateSize, Unaccelerated, 1);
     694    m_layerImage = layerImage.get();
     695#endif
     696
     697    if (!m_layerImage)
     698        return;
     699
     700    FloatRect templateShadow = FloatRect(edgeSize.width(), edgeSize.height(), templateSize.width() - 2 * edgeSize.width(), templateSize.height() - 2 * edgeSize.height());
     701
     702    bool redrawNeeded = true;
     703#if USE(CG)
     704    // Only redraw in the scratch buffer if its cached contents don't match our needs
     705    redrawNeeded = ScratchBuffer::singleton().setCachedShadowValues(m_blurRadius, m_color, templateShadow, shadowedRect.radii(), m_layerSize);
     706#endif
     707
     708    if (redrawNeeded) {
     709        // Draw shadow into the ImageBuffer.
     710        GraphicsContext& shadowContext = m_layerImage->context();
     711        GraphicsContextStateSaver shadowStateSaver(shadowContext);
     712
     713        shadowContext.clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height()));
     714        shadowContext.setFillColor(Color::black);
     715
     716        if (shadowedRect.radii().isZero())
     717            shadowContext.fillRect(templateShadow);
     718        else {
     719            Path path;
     720            path.addRoundedRect(FloatRoundedRect(templateShadow, shadowedRect.radii()));
     721            shadowContext.fillPath(path);
     722        }
     723        blurAndColorShadowBuffer(templateSize);
     724    }
     725
     726    FloatSize offset = m_offset;
     727    if (shadowsIgnoreTransforms())
     728        offset.scale(1 / transform.xScale(), 1 / transform.yScale());
     729
     730    FloatRect shadowBounds = shadowedRect.rect();
     731    shadowBounds.move(offset);
     732    shadowBounds.inflateX(edgeSize.width());
     733    shadowBounds.inflateY(edgeSize.height());
     734
     735    drawLayerPiecesAndFillCenter(shadowBounds, shadowedRect.radii(), edgeSize, templateSize, drawImage, fillRect);
     736
     737    m_layerImage = nullptr;
     738
     739#if USE(CG)
     740    ScratchBuffer::singleton().scheduleScratchBufferPurge();
     741#endif
     742}
     743
     744void ShadowBlur::drawInsetShadowWithTiling(const AffineTransform& transform, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& templateSize, const IntSize& edgeSize, const DrawImageCallback& drawImage, const FillRectWithHoleCallback& fillRectWithHole)
     745{
     746#if USE(CG)
     747    m_layerImage = ScratchBuffer::singleton().getScratchBuffer(templateSize);
     748#else
     749    auto layerImage = ImageBuffer::create(templateSize, Unaccelerated, 1);
     750    m_layerImage = layerImage.get();
     751#endif
     752
    732753    if (!m_layerImage)
    733754        return;
     
    737758    FloatRect templateHole = FloatRect(edgeSize.width(), edgeSize.height(), templateSize.width() - 2 * edgeSize.width(), templateSize.height() - 2 * edgeSize.height());
    738759
     760    bool redrawNeeded = true;
     761#if USE(CG)
    739762    // Only redraw in the scratch buffer if its cached contents don't match our needs
    740     bool redrawNeeded = ScratchBuffer::singleton().setCachedInsetShadowValues(m_blurRadius, m_color, templateBounds, templateHole, holeRect.radii());
     763    redrawNeeded = ScratchBuffer::singleton().setCachedInsetShadowValues(m_blurRadius, m_color, templateBounds, templateHole, holeRect.radii());
     764#endif
     765
    741766    if (redrawNeeded) {
    742767        // Draw shadow into a new ImageBuffer.
     
    759784    }
    760785    FloatSize offset = m_offset;
    761     if (shadowsIgnoreTransforms()) {
    762         AffineTransform transform = graphicsContext.getCTM();
     786    if (shadowsIgnoreTransforms())
    763787        offset.scale(1 / transform.xScale(), 1 / transform.yScale());
    764     }
    765 
    766     FloatRect boundingRect = rect;
     788
     789    FloatRect boundingRect = fullRect;
    767790    boundingRect.move(offset);
    768791
     
    774797
    775798    // Fill the external part of the shadow (which may be visible because of offset).
    776     Path exteriorPath;
    777     exteriorPath.addRect(boundingRect);
    778     exteriorPath.addRect(destHoleBounds);
    779 
    780     {
    781         GraphicsContextStateSaver fillStateSaver(graphicsContext);
    782         graphicsContext.setFillRule(WindRule::EvenOdd);
    783         graphicsContext.setFillColor(m_color);
    784         graphicsContext.clearShadow();
    785         graphicsContext.fillPath(exteriorPath);
    786     }
    787    
    788     drawLayerPieces(graphicsContext, destHoleBounds, holeRect.radii(), edgeSize, templateSize, InnerShadow);
     799    fillRectWithHole(boundingRect, destHoleBounds, m_color);
     800
     801    drawLayerPieces(destHoleBounds, holeRect.radii(), edgeSize, templateSize, drawImage);
    789802
    790803    m_layerImage = nullptr;
     804
     805#if USE(CG)
    791806    ScratchBuffer::singleton().scheduleScratchBufferPurge();
    792 }
    793 
    794 void ShadowBlur::drawRectShadowWithTiling(GraphicsContext& graphicsContext, const FloatRoundedRect& shadowedRect, const IntSize& templateSize, const IntSize& edgeSize)
    795 {
    796     auto& scratchBuffer = ScratchBuffer::singleton();
    797     m_layerImage = scratchBuffer.getScratchBuffer(templateSize);
    798     if (!m_layerImage)
    799         return;
    800 
    801     FloatRect templateShadow = FloatRect(edgeSize.width(), edgeSize.height(), templateSize.width() - 2 * edgeSize.width(), templateSize.height() - 2 * edgeSize.height());
    802 
    803     // Only redraw in the scratch buffer if its cached contents don't match our needs
    804     bool redrawNeeded = scratchBuffer.setCachedShadowValues(m_blurRadius, m_color, templateShadow, shadowedRect.radii(), m_layerSize);
    805     if (redrawNeeded) {
    806         // Draw shadow into the ImageBuffer.
    807         GraphicsContext& shadowContext = m_layerImage->context();
    808         GraphicsContextStateSaver shadowStateSaver(shadowContext);
    809 
    810         shadowContext.clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height()));
    811         shadowContext.setFillColor(Color::black);
    812        
    813         if (shadowedRect.radii().isZero())
    814             shadowContext.fillRect(templateShadow);
    815         else {
    816             Path path;
    817             path.addRoundedRect(FloatRoundedRect(templateShadow, shadowedRect.radii()));
    818             shadowContext.fillPath(path);
    819         }
    820 
    821         blurAndColorShadowBuffer(templateSize);
    822     }
    823     FloatSize offset = m_offset;
    824     if (shadowsIgnoreTransforms()) {
    825         AffineTransform transform = graphicsContext.getCTM();
    826         offset.scale(1 / transform.xScale(), 1 / transform.yScale());
    827     }
    828 
    829     FloatRect shadowBounds = shadowedRect.rect();
    830     shadowBounds.move(offset);
    831     shadowBounds.inflateX(edgeSize.width());
    832     shadowBounds.inflateY(edgeSize.height());
    833 
    834     drawLayerPieces(graphicsContext, shadowBounds, shadowedRect.radii(), edgeSize, templateSize, OuterShadow);
    835 
    836     m_layerImage = nullptr;
    837     ScratchBuffer::singleton().scheduleScratchBufferPurge();
    838 }
    839 
    840 void ShadowBlur::drawLayerPieces(GraphicsContext& graphicsContext, const FloatRect& shadowBounds, const FloatRoundedRect::Radii& radii, const IntSize& bufferPadding, const IntSize& templateSize, ShadowDirection direction)
     807#endif
     808}
     809
     810void ShadowBlur::drawLayerPieces(const FloatRect& shadowBounds, const FloatRoundedRect::Radii& radii, const IntSize& bufferPadding, const IntSize& templateSize, const DrawImageCallback& drawImage)
    841811{
    842812    const IntSize twiceRadius = IntSize(bufferPadding.width() * 2, bufferPadding.height() * 2);
     
    850820    int centerWidth = shadowBounds.width() - leftSlice - rightSlice;
    851821    int centerHeight = shadowBounds.height() - topSlice - bottomSlice;
    852 
    853     if (direction == OuterShadow) {
    854         FloatRect shadowInterior(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight);
    855         if (!shadowInterior.isEmpty()) {
    856             GraphicsContextStateSaver stateSaver(graphicsContext);
    857             graphicsContext.setFillColor(m_color);
    858             graphicsContext.clearShadow();
    859             graphicsContext.fillRect(shadowInterior);
    860         }
    861     }
    862 
    863     GraphicsContextStateSaver stateSaver(graphicsContext);
    864     graphicsContext.setFillColor(m_color);
    865     graphicsContext.clearShadow();
    866 
    867     // Note that drawing the ImageBuffer is faster than creating a Image and drawing that,
    868     // because ImageBuffer::draw() knows that it doesn't have to copy the image bits.
    869822    FloatRect centerRect(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight);
    870     centerRect = graphicsContext.roundToDevicePixels(centerRect);
    871    
     823
    872824    // Top side.
    873825    FloatRect tileRect = FloatRect(leftSlice, 0, templateSideLength, topSlice);
    874826    FloatRect destRect = FloatRect(centerRect.x(), centerRect.y() - topSlice, centerRect.width(), topSlice);
    875     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
     827    drawImage(*m_layerImage, destRect, tileRect);
    876828
    877829    // Draw the bottom side.
     
    880832    destRect.setY(centerRect.maxY());
    881833    destRect.setHeight(bottomSlice);
    882     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
     834    drawImage(*m_layerImage, destRect, tileRect);
    883835
    884836    // Left side.
    885837    tileRect = FloatRect(0, topSlice, leftSlice, templateSideLength);
    886838    destRect = FloatRect(centerRect.x() - leftSlice, centerRect.y(), leftSlice, centerRect.height());
    887     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
     839    drawImage(*m_layerImage, destRect, tileRect);
    888840
    889841    // Right side.
     
    892844    destRect.setX(centerRect.maxX());
    893845    destRect.setWidth(rightSlice);
    894     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
     846    drawImage(*m_layerImage, destRect, tileRect);
    895847
    896848    // Top left corner.
    897849    tileRect = FloatRect(0, 0, leftSlice, topSlice);
    898850    destRect = FloatRect(centerRect.x() - leftSlice, centerRect.y() - topSlice, leftSlice, topSlice);
    899     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
     851    drawImage(*m_layerImage, destRect, tileRect);
    900852
    901853    // Top right corner.
    902854    tileRect = FloatRect(templateSize.width() - rightSlice, 0, rightSlice, topSlice);
    903855    destRect = FloatRect(centerRect.maxX(), centerRect.y() - topSlice, rightSlice, topSlice);
    904     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
     856    drawImage(*m_layerImage, destRect, tileRect);
    905857
    906858    // Bottom right corner.
    907859    tileRect = FloatRect(templateSize.width() - rightSlice, templateSize.height() - bottomSlice, rightSlice, bottomSlice);
    908860    destRect = FloatRect(centerRect.maxX(), centerRect.maxY(), rightSlice, bottomSlice);
    909     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
     861    drawImage(*m_layerImage, destRect, tileRect);
    910862
    911863    // Bottom left corner.
    912864    tileRect = FloatRect(0, templateSize.height() - bottomSlice, leftSlice, bottomSlice);
    913865    destRect = FloatRect(centerRect.x() - leftSlice, centerRect.maxY(), leftSlice, bottomSlice);
    914     graphicsContext.drawImageBuffer(*m_layerImage, destRect, tileRect);
    915 }
    916 
     866    drawImage(*m_layerImage, destRect, tileRect);
     867}
     868
     869void ShadowBlur::drawLayerPiecesAndFillCenter(const FloatRect& shadowBounds, const FloatRoundedRect::Radii& radii, const IntSize& bufferPadding, const IntSize& templateSize, const DrawImageCallback& drawImage, const FillRectCallback& fillRect)
     870{
     871    const IntSize twiceRadius = IntSize(bufferPadding.width() * 2, bufferPadding.height() * 2);
     872
     873    int leftSlice;
     874    int rightSlice;
     875    int topSlice;
     876    int bottomSlice;
     877    computeSliceSizesFromRadii(twiceRadius, radii, leftSlice, rightSlice, topSlice, bottomSlice);
     878
     879    int centerWidth = shadowBounds.width() - leftSlice - rightSlice;
     880    int centerHeight = shadowBounds.height() - topSlice - bottomSlice;
     881    FloatRect centerRect(shadowBounds.x() + leftSlice, shadowBounds.y() + topSlice, centerWidth, centerHeight);
     882
     883    // Fill center
     884    if (!centerRect.isEmpty())
     885        fillRect(centerRect, m_color);
     886
     887    drawLayerPieces(shadowBounds, radii, bufferPadding, templateSize, drawImage);
     888}
    917889
    918890void ShadowBlur::blurShadowBuffer(const IntSize& templateSize)
     
    963935
    964936    blurAndColorShadowBuffer(expandedIntSize(m_layerSize));
    965     drawBuffer(*layerImage, m_layerOrigin, m_layerSize, m_sourceRect);
     937    drawBuffer(*layerImage, m_layerOrigin, m_layerSize);
    966938}
    967939
  • trunk/Source/WebCore/platform/graphics/ShadowBlur.h

    r228776 r244913  
    2424 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2525 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    2828
    29 #ifndef ShadowBlur_h
    30 #define ShadowBlur_h
     29#pragma once
    3130
    3231#include "Color.h"
     
    6463    void drawInsetShadow(GraphicsContext&, const FloatRect&, const FloatRoundedRect& holeRect);
    6564
    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&);
     65    using DrawBufferCallback = WTF::Function<void(ImageBuffer&, const FloatPoint&, const FloatSize&)>;
     66    using DrawImageCallback = WTF::Function<void(ImageBuffer&, const FloatRect&, const FloatRect&)>;
     67    using FillRectCallback = WTF::Function<void(const FloatRect&, const Color&)>;
     68    using FillRectWithHoleCallback = WTF::Function<void(const FloatRect&, const FloatRect&, const Color&)>;
     69    using DrawShadowCallback = WTF::Function<void(GraphicsContext&)>;
    6970
    70     using DrawShadowCallback = WTF::Function<void(GraphicsContext&)>;
    71     void drawShadowLayer(const AffineTransform&, const IntRect&, const FloatRect&, const DrawShadowCallback&, const DrawBufferCallback&);
     71    // DrawBufferCallback is for drawing shadow without tiling.
     72    // DrawImageCallback and FillRectCallback is for drawing shadow with tiling.
     73    void drawRectShadow(const AffineTransform&, const IntRect& clipBounds, const FloatRoundedRect& shadowedRect, const DrawBufferCallback&, const DrawImageCallback&, const FillRectCallback&);
     74    void drawInsetShadow(const AffineTransform&, const IntRect& clipBounds, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const DrawBufferCallback&, const DrawImageCallback&, const FillRectWithHoleCallback&);
     75    void drawShadowLayer(const AffineTransform&, const IntRect& clipBounds, const FloatRect& layerArea, const DrawShadowCallback&, const DrawBufferCallback&);
    7276
    7377    void blurLayerImage(unsigned char*, const IntSize&, int stride);
     
    8387
    8488    void adjustBlurRadius(const AffineTransform&);
    85    
     89
    8690    enum ShadowDirection {
    8791        OuterShadow,
    8892        InnerShadow
    8993    };
    90    
     94
    9195    IntSize calculateLayerBoundingRect(const AffineTransform&, const FloatRect& layerArea, const IntRect& clipRect);
    9296    IntSize templateSize(const IntSize& blurredEdgeSize, const FloatRoundedRect::Radii&) const;
    9397
    94     void drawRectShadowWithoutTiling(GraphicsContext&, const FloatRoundedRect&, const IntSize& layerSize);
    95     void drawRectShadowWithTiling(GraphicsContext&, const FloatRoundedRect&, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize);
    96 
    97     void drawInsetShadowWithoutTiling(GraphicsContext&, const FloatRect&, const FloatRoundedRect& holeRect, const IntSize& layerSize);
    98     void drawInsetShadowWithTiling(GraphicsContext&, const FloatRect&, const FloatRoundedRect& holeRect, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize);
    99    
    100     void drawLayerPieces(GraphicsContext&, const FloatRect& shadowBounds, const FloatRoundedRect::Radii&, const IntSize& roundedRadius, const IntSize& templateSize, ShadowDirection);
    101    
    10298    void blurShadowBuffer(const IntSize& templateSize);
    10399    void blurAndColorShadowBuffer(const IntSize& templateSize);
    104    
     100
     101    void drawInsetShadowWithoutTiling(const AffineTransform&, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& layerSize, const DrawBufferCallback&);
     102    void drawInsetShadowWithTiling(const AffineTransform&, const FloatRect& fullRect, const FloatRoundedRect& holeRect, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize, const DrawImageCallback&, const FillRectWithHoleCallback&);
     103
     104    void drawRectShadowWithoutTiling(const AffineTransform&, const FloatRoundedRect& shadowedRect, const IntSize& layerSize, const DrawBufferCallback&);
     105    void drawRectShadowWithTiling(const AffineTransform&, const FloatRoundedRect& shadowedRect, const IntSize& shadowTemplateSize, const IntSize& blurredEdgeSize, const DrawImageCallback&, const FillRectCallback&);
     106
     107    void drawLayerPiecesAndFillCenter(const FloatRect& shadowBounds, const FloatRoundedRect::Radii&, const IntSize& roundedRadius, const IntSize& templateSize, const DrawImageCallback&, const FillRectCallback&);
     108    void drawLayerPieces(const FloatRect& shadowBounds, const FloatRoundedRect::Radii&, const IntSize& roundedRadius, const IntSize& templateSize, const DrawImageCallback&);
     109
    105110    IntSize blurredEdgeSize() const;
    106    
    107    
     111
    108112    ShadowType m_type { NoShadow };
    109113
     
    114118    ImageBuffer* m_layerImage { nullptr }; // Buffer to where the temporary shadow will be drawn to.
    115119
    116     FloatRect m_sourceRect; // Sub-rect of m_layerImage that contains the shadow pixels.
     120    FloatSize m_shadowedResultSize; // Size of the result of shadowing which is same as shadowedRect + blurred edges.
    117121    FloatPoint m_layerOrigin; // Top-left corner of the (possibly clipped) bounding rect to draw the shadow to.
    118122    FloatSize m_layerSize; // Size of m_layerImage pixels that need blurring.
     
    123127
    124128} // namespace WebCore
    125 
    126 #endif // ShadowBlur_h
  • trunk/Source/WebCore/platform/graphics/cairo/CairoOperations.cpp

    r237844 r244913  
    185185}
    186186
    187 static void fillShadowBuffer(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect, const ShadowState& shadowState)
     187// FIXME: This is mostly same as drawShadowLayerBuffer, so we should merge two.
     188static void drawShadowImage(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect, const ShadowState& shadowState)
     189{
     190    RefPtr<Image> image = layerImage.copyImage(DontCopyBackingStore);
     191    if (!image)
     192        return;
     193
     194    if (auto surface = image->nativeImageForCurrentFrame()) {
     195        drawNativeImage(platformContext, surface.get(), destRect, srcRect, shadowState.globalCompositeOperator, BlendMode::Normal, ImageOrientation(),
     196            InterpolationDefault, shadowState.globalAlpha, ShadowState());
     197    }
     198}
     199
     200static void fillShadowBuffer(PlatformContextCairo& platformContext, ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const ShadowState& shadowState)
    188201{
    189202    save(platformContext);
     
    198211    fillSource.globalAlpha = shadowState.globalAlpha;
    199212    fillSource.color = shadowState.color;
    200     fillRect(platformContext, FloatRect(layerOrigin, sourceRect.size()), fillSource, ShadowState());
     213    fillRect(platformContext, FloatRect(layerOrigin, expandedIntSize(layerSize)), fillSource, ShadowState());
    201214
    202215    restore(platformContext);
     
    253266            }
    254267        },
    255         [&platformContext, &shadowState, &cairoContext, &path](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
     268        [&platformContext, &shadowState, &cairoContext, &path](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
    256269        {
    257270            // The original path may still be hanging around on the context and endShadowLayer
     
    267280}
    268281
     282
    269283static inline void fillCurrentCairoPath(PlatformContextCairo& platformContext, const FillSource& fillSource)
    270284{
     
    351365            drawGlyphsToContext(shadowContext.platformContext()->cr(), scaledFont, syntheticBoldOffset, glyphs);
    352366        },
    353         [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
     367        [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
    354368        {
    355369            drawShadowLayerBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
     
    691705        ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
    692706        shadow.drawRectShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), FloatRoundedRect(rect),
    693             [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
     707            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
    694708            {
    695                 fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState);
     709                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
     710            },
     711            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect)
     712            {
     713                drawShadowImage(platformContext, layerImage, destRect, srcRect, shadowState);
     714            },
     715            [&platformContext](const FloatRect& rect, const Color& color)
     716            {
     717                fillRectWithColor(platformContext.cr(), rect, color);
    696718            });
    697719    }
     
    714736        ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
    715737        shadow.drawRectShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), rect,
    716             [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
     738            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
    717739            {
    718                 fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState);
     740                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
     741            },
     742            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect)
     743            {
     744                drawShadowImage(platformContext, layerImage, destRect, srcRect, shadowState);
     745            },
     746            [&platformContext](const FloatRect& rect, const Color& color)
     747            {
     748                fillRectWithColor(platformContext.cr(), rect, color);
    719749            });
    720750    }
     
    739769        ShadowBlur shadow({ shadowState.blur, shadowState.blur }, shadowState.offset, shadowState.color, shadowState.ignoreTransforms);
    740770        shadow.drawInsetShadow(State::getCTM(platformContext), State::getClipBounds(platformContext), rect, roundedHoleRect,
    741             [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect& sourceRect)
     771            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
    742772            {
    743                 fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, sourceRect, shadowState);
     773                fillShadowBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
     774            },
     775            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatRect& destRect, const FloatRect& srcRect)
     776            {
     777                drawShadowImage(platformContext, layerImage, destRect, srcRect, shadowState);
     778            },
     779            [&platformContext](const FloatRect& rect, const FloatRect& holeRect, const Color& color)
     780            {
     781                // FIXME: We should use fillRectWithRoundedHole.
     782                cairo_t* cr = platformContext.cr();
     783                cairo_save(cr);
     784                setSourceRGBAFromColor(cr, color);
     785                cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
     786                cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
     787                cairo_rectangle(cr, holeRect.x(), holeRect.y(), holeRect.width(), holeRect.height());
     788                cairo_fill(cr);
     789                cairo_restore(cr);
    744790            });
    745791    }
     
    933979                drawPatternToCairoContext(shadowContext.platformContext()->cr(), pattern.get(), destRect, 1);
    934980            },
    935             [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize, const FloatRect&)
     981            [&platformContext, &shadowState](ImageBuffer& layerImage, const FloatPoint& layerOrigin, const FloatSize& layerSize)
    936982            {
    937983                drawShadowLayerBuffer(platformContext, layerImage, layerOrigin, layerSize, shadowState);
Note: See TracChangeset for help on using the changeset viewer.