Title: [267742] trunk/Source/WebCore
Revision
267742
Author
wenson_hs...@apple.com
Date
2020-09-29 09:41:49 -0700 (Tue, 29 Sep 2020)

Log Message

[GPU Process] Several layout tests in fast/canvas crash under GraphicsContext::clipToImageBuffer
https://bugs.webkit.org/show_bug.cgi?id=217026
<rdar://problem/69663834>

Reviewed by Simon Fraser.

When using the GPU Process for rendering, calling `GraphicsContext::clipToImageBuffer` currently results in a
crash, due to the platform `CGContextRef` being null. This causes the following 4 canvas-related tests to fail:
- fast/canvas/2d.fillText.gradient.html
- fast/canvas/2d.text.draw.fill.maxWidth.gradient.html
- fast/canvas/canvas-text-alignment.html
- fast/canvas/gradient-text-with-shadow.html

In all four of these tests, the `clipToImageBuffer` call comes from `CanvasRenderingContext2D::drawTextInternal`
method, while creating the image used to provide the mask when there is a gradient or pattern fill. This is
tricky to support when using the GPU process with display list items, since `ImageBuffer`s cannot be generally
sent to the GPU process through IPC. Instead of painting an `ImageBuffer` and sending it over IPC, we can
introduce a new `GraphicsContext` method that clips to an image that is painted via a `WTF::Function` that is
passed in, and receives a `GraphicsContext&`. When using a display-list-backed `GraphicsContext`, we can create
a new `DisplayList` recording context and use the given `Function` to populate the display list with items,
which can then be sent to the GPU process through IPC. When using a platform `CGContextRef`-backed
`GraphicsContext`, we instead create a new `ImageBuffer` compatible with the current context, and then use this
`ImageBuffer` to call `clipToImageBuffer`. We then refactor `drawTextInternal` so that it uses this new
`GraphicsContext` method. See below for more details.

* html/canvas/CanvasRenderingContext2D.cpp:
(WebCore::CanvasRenderingContext2D::drawTextInternal):

Refactor this to use `clipToDrawingCommands` instead of `clipToImageBuffer`.

* platform/graphics/GraphicsContext.cpp:
(WebCore::GraphicsContext::clipToDrawingCommands):

Introduce a new `GraphicsContext` method that takes a function which draws into a given `GraphicsContext`. When
there is no `GraphicsContextImpl` present, we create a new `ImageBuffer` compatible with this `GraphicsContext`,
paint into it using the given `Function`, and lastly pass this painted `ImageBuffer` into `clipToImageBuffer`.

* platform/graphics/GraphicsContext.h:
* platform/graphics/GraphicsContextImpl.h:
* platform/graphics/cairo/GraphicsContextImplCairo.cpp:
(WebCore::GraphicsContextImplCairo::clipToDrawingCommands):

Add an unimplemented method stub. Since the only call site of `GraphicsContext::clipToDrawingCommands` is behind
a `USE(CG)` guard, leaving this unimplemented for the time being won't result in any regression in behavior.

* platform/graphics/cairo/GraphicsContextImplCairo.h:
* platform/graphics/cg/GraphicsContextCG.cpp:
(WebCore::GraphicsContext::clipToImageBuffer):

It's not strictly necessary to fix these layout tests, but we should still add a check for `clipToImageBuffer`
here with a call to `GraphicsContextImpl::clipToImageBuffer` even though `clipToImageBuffer` is unimplemented,
to ensure that we at least avoid crashing if anything calls into this codepath.

* platform/graphics/displaylists/DisplayList.h:
* platform/graphics/displaylists/DisplayListDrawingContext.h:
(WebCore::DisplayList::DrawingContext::takeDisplayList):

Add a helper function to extract the `DisplayList` out of a `DisplayList::DrawingContext`.

* platform/graphics/displaylists/DisplayListItems.cpp:
(WebCore::DisplayList::ClipToDrawingCommands::ClipToDrawingCommands):
(WebCore::DisplayList::ClipToDrawingCommands::apply const):

Apply the `ClipToDrawingCommands` item by using `DisplayList::Replayer` to replay the given display list items
back in a new platform CG-backed image buffer in the GPU process.

(WebCore::DisplayList::operator<<):
* platform/graphics/displaylists/DisplayListItems.h:
(WebCore::DisplayList::ClipToDrawingCommands::create):
(WebCore::DisplayList::ClipToDrawingCommands::destination const):
(WebCore::DisplayList::ClipToDrawingCommands::colorSpace const):
(WebCore::DisplayList::ClipToDrawingCommands::drawingCommands const):
(WebCore::DisplayList::ClipToDrawingCommands::encode const):
(WebCore::DisplayList::ClipToDrawingCommands::decode):
(WebCore::DisplayList::Item::encode const):
(WebCore::DisplayList::Item::decode):

Add a new `ClipToDrawingCommands` display list item, with support for IPC encoding and decoding.

* platform/graphics/displaylists/DisplayListRecorder.cpp:
(WebCore::DisplayList::Recorder::clipToDrawingCommands):

Implement the display-list-backed `clipToDrawingCommands` method by creating a new `DisplayList::DrawingContext`
and playing the given drawing function back into the `DrawingContext`. This populates the recording context with
a display list, which we can use to create a serializable display list item.

* platform/graphics/displaylists/DisplayListRecorder.h:
* platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.cpp:
(Nicosia::CairoOperationRecorder::clipToDrawingCommands):

Add another unimplemented method stub.

* platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.h:
* platform/graphics/win/GraphicsContextImplDirect2D.cpp:
(WebCore::GraphicsContextImplDirect2D::clipToDrawingCommands):

Add another unimplemented method stub.

* platform/graphics/win/GraphicsContextImplDirect2D.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (267741 => 267742)


--- trunk/Source/WebCore/ChangeLog	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/ChangeLog	2020-09-29 16:41:49 UTC (rev 267742)
@@ -1,3 +1,105 @@
+2020-09-29  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [GPU Process] Several layout tests in fast/canvas crash under GraphicsContext::clipToImageBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=217026
+        <rdar://problem/69663834>
+
+        Reviewed by Simon Fraser.
+
+        When using the GPU Process for rendering, calling `GraphicsContext::clipToImageBuffer` currently results in a
+        crash, due to the platform `CGContextRef` being null. This causes the following 4 canvas-related tests to fail:
+        - fast/canvas/2d.fillText.gradient.html
+        - fast/canvas/2d.text.draw.fill.maxWidth.gradient.html
+        - fast/canvas/canvas-text-alignment.html
+        - fast/canvas/gradient-text-with-shadow.html
+
+        In all four of these tests, the `clipToImageBuffer` call comes from `CanvasRenderingContext2D::drawTextInternal`
+        method, while creating the image used to provide the mask when there is a gradient or pattern fill. This is
+        tricky to support when using the GPU process with display list items, since `ImageBuffer`s cannot be generally
+        sent to the GPU process through IPC. Instead of painting an `ImageBuffer` and sending it over IPC, we can
+        introduce a new `GraphicsContext` method that clips to an image that is painted via a `WTF::Function` that is
+        passed in, and receives a `GraphicsContext&`. When using a display-list-backed `GraphicsContext`, we can create
+        a new `DisplayList` recording context and use the given `Function` to populate the display list with items,
+        which can then be sent to the GPU process through IPC. When using a platform `CGContextRef`-backed
+        `GraphicsContext`, we instead create a new `ImageBuffer` compatible with the current context, and then use this
+        `ImageBuffer` to call `clipToImageBuffer`. We then refactor `drawTextInternal` so that it uses this new
+        `GraphicsContext` method. See below for more details.
+
+        * html/canvas/CanvasRenderingContext2D.cpp:
+        (WebCore::CanvasRenderingContext2D::drawTextInternal):
+
+        Refactor this to use `clipToDrawingCommands` instead of `clipToImageBuffer`.
+
+        * platform/graphics/GraphicsContext.cpp:
+        (WebCore::GraphicsContext::clipToDrawingCommands):
+
+        Introduce a new `GraphicsContext` method that takes a function which draws into a given `GraphicsContext`. When
+        there is no `GraphicsContextImpl` present, we create a new `ImageBuffer` compatible with this `GraphicsContext`,
+        paint into it using the given `Function`, and lastly pass this painted `ImageBuffer` into `clipToImageBuffer`.
+
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/GraphicsContextImpl.h:
+        * platform/graphics/cairo/GraphicsContextImplCairo.cpp:
+        (WebCore::GraphicsContextImplCairo::clipToDrawingCommands):
+
+        Add an unimplemented method stub. Since the only call site of `GraphicsContext::clipToDrawingCommands` is behind
+        a `USE(CG)` guard, leaving this unimplemented for the time being won't result in any regression in behavior.
+
+        * platform/graphics/cairo/GraphicsContextImplCairo.h:
+        * platform/graphics/cg/GraphicsContextCG.cpp:
+        (WebCore::GraphicsContext::clipToImageBuffer):
+
+        It's not strictly necessary to fix these layout tests, but we should still add a check for `clipToImageBuffer`
+        here with a call to `GraphicsContextImpl::clipToImageBuffer` even though `clipToImageBuffer` is unimplemented,
+        to ensure that we at least avoid crashing if anything calls into this codepath.
+
+        * platform/graphics/displaylists/DisplayList.h:
+        * platform/graphics/displaylists/DisplayListDrawingContext.h:
+        (WebCore::DisplayList::DrawingContext::takeDisplayList):
+
+        Add a helper function to extract the `DisplayList` out of a `DisplayList::DrawingContext`.
+
+        * platform/graphics/displaylists/DisplayListItems.cpp:
+        (WebCore::DisplayList::ClipToDrawingCommands::ClipToDrawingCommands):
+        (WebCore::DisplayList::ClipToDrawingCommands::apply const):
+
+        Apply the `ClipToDrawingCommands` item by using `DisplayList::Replayer` to replay the given display list items
+        back in a new platform CG-backed image buffer in the GPU process.
+
+        (WebCore::DisplayList::operator<<):
+        * platform/graphics/displaylists/DisplayListItems.h:
+        (WebCore::DisplayList::ClipToDrawingCommands::create):
+        (WebCore::DisplayList::ClipToDrawingCommands::destination const):
+        (WebCore::DisplayList::ClipToDrawingCommands::colorSpace const):
+        (WebCore::DisplayList::ClipToDrawingCommands::drawingCommands const):
+        (WebCore::DisplayList::ClipToDrawingCommands::encode const):
+        (WebCore::DisplayList::ClipToDrawingCommands::decode):
+        (WebCore::DisplayList::Item::encode const):
+        (WebCore::DisplayList::Item::decode):
+
+        Add a new `ClipToDrawingCommands` display list item, with support for IPC encoding and decoding.
+
+        * platform/graphics/displaylists/DisplayListRecorder.cpp:
+        (WebCore::DisplayList::Recorder::clipToDrawingCommands):
+
+        Implement the display-list-backed `clipToDrawingCommands` method by creating a new `DisplayList::DrawingContext`
+        and playing the given drawing function back into the `DrawingContext`. This populates the recording context with
+        a display list, which we can use to create a serializable display list item.
+
+        * platform/graphics/displaylists/DisplayListRecorder.h:
+        * platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.cpp:
+        (Nicosia::CairoOperationRecorder::clipToDrawingCommands):
+
+        Add another unimplemented method stub.
+
+        * platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.h:
+        * platform/graphics/win/GraphicsContextImplDirect2D.cpp:
+        (WebCore::GraphicsContextImplDirect2D::clipToDrawingCommands):
+
+        Add another unimplemented method stub.
+
+        * platform/graphics/win/GraphicsContextImplDirect2D.h:
+
 2020-09-29  Peng Liu  <peng.l...@apple.com>
 
         [Media in GPU Process] Use VideoLayerManager to manage layers of MediaPlayerPrivateRemote

Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp (267741 => 267742)


--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -546,33 +546,32 @@
             fontProxy.drawBidiText(*c, textRun, location + offset, FontCascade::UseFallbackIfFontNotReady);
         }
 
-        auto maskImage = ImageBuffer::createCompatibleBuffer(maskRect.size(), ColorSpace::SRGB, *c);
-        if (!maskImage)
-            return;
+        GraphicsContextStateSaver stateSaver(*c);
 
-        auto& maskImageContext = maskImage->context();
+        auto paintMaskImage = [&] (GraphicsContext& maskImageContext) {
+            if (fill)
+                maskImageContext.setFillColor(Color::black);
+            else {
+                maskImageContext.setStrokeColor(Color::black);
+                maskImageContext.setStrokeThickness(c->strokeThickness());
+            }
 
-        if (fill)
-            maskImageContext.setFillColor(Color::black);
-        else {
-            maskImageContext.setStrokeColor(Color::black);
-            maskImageContext.setStrokeThickness(c->strokeThickness());
-        }
+            maskImageContext.setTextDrawingMode(fill ? TextDrawingMode::Fill : TextDrawingMode::Stroke);
 
-        maskImageContext.setTextDrawingMode(fill ? TextDrawingMode::Fill : TextDrawingMode::Stroke);
+            if (useMaxWidth) {
+                maskImageContext.translate(location - maskRect.location());
+                // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
+                maskImageContext.scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
+                fontProxy.drawBidiText(maskImageContext, textRun, FloatPoint(0, 0), FontCascade::UseFallbackIfFontNotReady);
+            } else {
+                maskImageContext.translate(-maskRect.location());
+                fontProxy.drawBidiText(maskImageContext, textRun, location, FontCascade::UseFallbackIfFontNotReady);
+            }
+        };
 
-        if (useMaxWidth) {
-            maskImageContext.translate(location - maskRect.location());
-            // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
-            maskImageContext.scale(FloatSize((fontWidth > 0 ? (width / fontWidth) : 0), 1));
-            fontProxy.drawBidiText(maskImageContext, textRun, FloatPoint(0, 0), FontCascade::UseFallbackIfFontNotReady);
-        } else {
-            maskImageContext.translate(-maskRect.location());
-            fontProxy.drawBidiText(maskImageContext, textRun, location, FontCascade::UseFallbackIfFontNotReady);
-        }
+        if (c->clipToDrawingCommands(maskRect, ColorSpace::SRGB, WTFMove(paintMaskImage)) == GraphicsContext::ClipToDrawingCommandsResult::FailedToCreateImageBuffer)
+            return;
 
-        GraphicsContextStateSaver stateSaver(*c);
-        c->clipToImageBuffer(*maskImage, maskRect);
         drawStyle.applyFillColor(*c);
         c->fillRect(maskRect);
         return;

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -851,6 +851,25 @@
     clipOut(path);
 }
 
+GraphicsContext::ClipToDrawingCommandsResult GraphicsContext::clipToDrawingCommands(const FloatRect& destination, ColorSpace colorSpace, Function<void(GraphicsContext&)>&& drawingFunction)
+{
+    if (paintingDisabled())
+        return ClipToDrawingCommandsResult::Success;
+
+    if (m_impl) {
+        m_impl->clipToDrawingCommands(destination, colorSpace, WTFMove(drawingFunction));
+        return ClipToDrawingCommandsResult::Success;
+    }
+
+    auto imageBuffer = ImageBuffer::createCompatibleBuffer(destination.size(), colorSpace, *this);
+    if (!imageBuffer)
+        return ClipToDrawingCommandsResult::FailedToCreateImageBuffer;
+
+    drawingFunction(imageBuffer->context());
+    clipToImageBuffer(*imageBuffer, destination);
+    return ClipToDrawingCommandsResult::Success;
+}
+
 #if !USE(CG) && !USE(DIRECT2D) && !USE(CAIRO)
 IntRect GraphicsContext::clipBounds() const
 {

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -26,6 +26,7 @@
 
 #pragma once
 
+#include "ColorSpace.h"
 #include "DashArray.h"
 #include "FloatRect.h"
 #include "FontCascade.h"
@@ -408,6 +409,9 @@
     void clipOutRoundedRect(const FloatRoundedRect&);
     void clipPath(const Path&, WindRule = WindRule::EvenOdd);
     void clipToImageBuffer(ImageBuffer&, const FloatRect&);
+
+    enum class ClipToDrawingCommandsResult : bool { Success, FailedToCreateImageBuffer };
+    ClipToDrawingCommandsResult clipToDrawingCommands(const FloatRect& destination, ColorSpace, Function<void(GraphicsContext&)>&&);
     
     IntRect clipBounds() const;
 

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContextImpl.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/GraphicsContextImpl.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContextImpl.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -106,6 +106,7 @@
     virtual void clipPath(const Path&, WindRule) = 0;
     virtual IntRect clipBounds() = 0;
     virtual void clipToImageBuffer(ImageBuffer&, const FloatRect&) = 0;
+    virtual void clipToDrawingCommands(const FloatRect& destination, ColorSpace, Function<void(GraphicsContext&)>&& drawingFunction) = 0;
     
     virtual void applyDeviceScaleFactor(float) = 0;
 

Modified: trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextImplCairo.cpp (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextImplCairo.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextImplCairo.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -427,6 +427,11 @@
     return Cairo::State::roundToDevicePixels(m_platformContext, rect);
 }
 
+void GraphicsContextImplCairo::clipToDrawingCommands(const FloatRect&, ColorSpace, Function<void(GraphicsContext&)>&&)
+{
+    // FIXME: Not implemented.
+}
+
 } // namespace WebCore
 
 #endif // USE(CAIRO)

Modified: trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextImplCairo.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextImplCairo.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextImplCairo.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -106,6 +106,7 @@
     void clipPath(const Path&, WindRule) override;
     IntRect clipBounds() override;
     void clipToImageBuffer(ImageBuffer&, const FloatRect&) override;
+    void clipToDrawingCommands(const FloatRect& destination, ColorSpace, Function<void(GraphicsContext&)>&&) override;
     
     void applyDeviceScaleFactor(float) override;
 

Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -510,22 +510,27 @@
     }
 }
 
-void GraphicsContext::clipToImageBuffer(ImageBuffer& buffer, const FloatRect& destRect)
+void GraphicsContext::clipToImageBuffer(ImageBuffer& buffer, const FloatRect& destinationRect)
 {
     if (paintingDisabled())
         return;
 
-    FloatSize bufferDestinationSize = destRect.size();
+    if (m_impl) {
+        m_impl->clipToImageBuffer(buffer, destinationRect);
+        return;
+    }
+
+    FloatSize bufferDestinationSize = destinationRect.size();
     RetainPtr<CGImageRef> image = buffer.copyNativeImage(DontCopyBackingStore);
 
     CGContextRef context = platformContext();
     // FIXME: This image needs to be grayscale to be used as an alpha mask here.
-    CGContextTranslateCTM(context, destRect.x(), destRect.y() + bufferDestinationSize.height());
+    CGContextTranslateCTM(context, destinationRect.x(), destinationRect.y() + bufferDestinationSize.height());
     CGContextScaleCTM(context, 1, -1);
-    CGContextClipToRect(context, FloatRect(FloatPoint(0, bufferDestinationSize.height() - destRect.height()), destRect.size()));
+    CGContextClipToRect(context, FloatRect(FloatPoint(0, bufferDestinationSize.height() - destinationRect.height()), destinationRect.size()));
     CGContextClipToMask(context, FloatRect(FloatPoint(), bufferDestinationSize), image.get());
     CGContextScaleCTM(context, 1, -1);
-    CGContextTranslateCTM(context, -destRect.x(), -destRect.y() - destRect.height());
+    CGContextTranslateCTM(context, -destinationRect.x(), -destinationRect.y() - destinationRect.height());
 }
 
 // Draws a filled rectangle with a stroked border.

Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayList.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayList.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayList.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -57,6 +57,7 @@
     ClipOut,
     ClipOutToPath,
     ClipPath,
+    ClipToDrawingCommands,
     DrawGlyphs,
     DrawImage,
     DrawTiledImage,

Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawingContext.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawingContext.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawingContext.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -39,6 +39,7 @@
 
     GraphicsContext& context() const { return const_cast<DrawingContext&>(*this).m_context; }
     WEBCORE_EXPORT Recorder& recorder();
+    DisplayList takeDisplayList() { return WTFMove(m_displayList); }
     DisplayList& displayList() { return m_displayList; }
     const DisplayList& displayList() const { return m_displayList; }
     const DisplayList* replayedDisplayList() const { return m_replayedDisplayList.get(); }

Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.cpp (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -94,6 +94,8 @@
         return sizeof(downcast<ClipOutToPath>(item));
     case ItemType::ClipPath:
         return sizeof(downcast<ClipPath>(item));
+    case ItemType::ClipToDrawingCommands:
+        return sizeof(downcast<ClipToDrawingCommands>(item));
     case ItemType::DrawGlyphs:
         return sizeof(downcast<DrawGlyphs>(item));
     case ItemType::DrawImage:
@@ -510,6 +512,32 @@
     return ts;
 }
 
+ClipToDrawingCommands::ClipToDrawingCommands(const FloatRect& destination, ColorSpace colorSpace, DisplayList&& drawingCommands)
+    : Item(ItemType::ClipToDrawingCommands)
+    , m_destination(destination)
+    , m_colorSpace(colorSpace)
+    , m_drawingCommands(WTFMove(drawingCommands))
+{
+}
+
+ClipToDrawingCommands::~ClipToDrawingCommands() = default;
+
+void ClipToDrawingCommands::apply(GraphicsContext& context) const
+{
+    context.clipToDrawingCommands(m_destination, m_colorSpace, [&] (GraphicsContext& clippingContext) {
+        Replayer replayer { clippingContext, m_drawingCommands };
+        replayer.replay();
+    });
+}
+
+static TextStream& operator<<(TextStream& ts, const ClipToDrawingCommands& item)
+{
+    ts.dumpProperty("destination", item.destination());
+    ts.dumpProperty("color-space", item.colorSpace());
+    ts.dumpProperty("drawing-commands-count", item.drawingCommands().itemCount());
+    return ts;
+}
+
 DrawGlyphs::DrawGlyphs(const Font& font, Vector<GlyphBufferGlyph, 128>&& glyphs, Vector<GlyphBufferAdvance, 128>&& advances, const FloatPoint& blockLocation, const FloatSize& localAnchor, FontSmoothingMode smoothingMode)
     : DrawingItem(ItemType::DrawGlyphs)
     , m_font(const_cast<Font&>(font))
@@ -1393,6 +1421,7 @@
     case ItemType::ClipOut: ts << "clip-out"; break;
     case ItemType::ClipOutToPath: ts << "clip-out-to-path"; break;
     case ItemType::ClipPath: ts << "clip-path"; break;
+    case ItemType::ClipToDrawingCommands: ts << "clip-to-image-buffer"; break;
     case ItemType::DrawGlyphs: ts << "draw-glyphs"; break;
     case ItemType::DrawImage: ts << "draw-image"; break;
     case ItemType::DrawTiledImage: ts << "draw-tiled-image"; break;
@@ -1483,6 +1512,9 @@
     case ItemType::ClipPath:
         ts << downcast<ClipPath>(item);
         break;
+    case ItemType::ClipToDrawingCommands:
+        ts << downcast<ClipToDrawingCommands>(item);
+        break;
     case ItemType::DrawGlyphs:
         ts << downcast<DrawGlyphs>(item);
         break;

Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -1043,6 +1043,61 @@
     return ClipPath::create(*path, *windRule);
 }
 
+class ClipToDrawingCommands : public Item {
+public:
+    static Ref<ClipToDrawingCommands> create(const FloatRect& destination, ColorSpace colorSpace, DisplayList&& drawingCommands)
+    {
+        return adoptRef(*new ClipToDrawingCommands(destination, colorSpace, WTFMove(drawingCommands)));
+    }
+
+    WEBCORE_EXPORT ~ClipToDrawingCommands();
+
+    const FloatRect& destination() const { return m_destination; }
+    ColorSpace colorSpace() const { return m_colorSpace; }
+    const DisplayList& drawingCommands() const { return m_drawingCommands; }
+
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static Optional<Ref<ClipToDrawingCommands>> decode(Decoder&);
+
+private:
+    WEBCORE_EXPORT ClipToDrawingCommands(const FloatRect& destination, ColorSpace, DisplayList&& drawingCommands);
+
+    void apply(GraphicsContext&) const override;
+
+    FloatRect m_destination;
+    ColorSpace m_colorSpace;
+    DisplayList m_drawingCommands;
+};
+
+template<class Encoder>
+void ClipToDrawingCommands::encode(Encoder& encoder) const
+{
+    encoder << m_destination;
+    encoder << m_colorSpace;
+    encoder << m_drawingCommands;
+}
+
+template<class Decoder>
+Optional<Ref<ClipToDrawingCommands>> ClipToDrawingCommands::decode(Decoder& decoder)
+{
+    Optional<FloatRect> destination;
+    decoder >> destination;
+    if (!destination)
+        return WTF::nullopt;
+
+    Optional<ColorSpace> colorSpace;
+    decoder >> colorSpace;
+    if (!colorSpace)
+        return WTF::nullopt;
+
+    Optional<DisplayList> drawingCommands;
+    decoder >> drawingCommands;
+    if (!drawingCommands)
+        return WTF::nullopt;
+
+    return ClipToDrawingCommands::create(*destination, *colorSpace, WTFMove(*drawingCommands));
+}
+
 class DrawGlyphs : public DrawingItem {
 public:
     static Ref<DrawGlyphs> create(const Font& font, const GlyphBufferGlyph* glyphs, const GlyphBufferAdvance* advances, unsigned count, const FloatPoint& blockLocation, const FloatSize& localAnchor, FontSmoothingMode smoothingMode)
@@ -2856,6 +2911,9 @@
     case ItemType::ClipPath:
         encoder << downcast<ClipPath>(*this);
         break;
+    case ItemType::ClipToDrawingCommands:
+        encoder << downcast<ClipToDrawingCommands>(*this);
+        break;
     case ItemType::DrawGlyphs:
         encoder << downcast<DrawGlyphs>(*this);
         break;
@@ -3036,6 +3094,10 @@
         if (auto item = ClipPath::decode(decoder))
             return static_reference_cast<Item>(WTFMove(*item));
         break;
+    case ItemType::ClipToDrawingCommands:
+        if (auto item = ClipToDrawingCommands::decode(decoder))
+            return static_reference_cast<Item>(WTFMove(*item));
+        break;
     case ItemType::DrawGlyphs:
         if (auto item = DrawGlyphs::decode(decoder))
             return static_reference_cast<Item>(WTFMove(*item));
@@ -3205,6 +3267,7 @@
 SPECIALIZE_TYPE_TRAITS_DISPLAYLIST_ITEM(ClipOut)
 SPECIALIZE_TYPE_TRAITS_DISPLAYLIST_ITEM(ClipOutToPath)
 SPECIALIZE_TYPE_TRAITS_DISPLAYLIST_ITEM(ClipPath)
+SPECIALIZE_TYPE_TRAITS_DISPLAYLIST_ITEM(ClipToDrawingCommands)
 SPECIALIZE_TYPE_TRAITS_DISPLAYLIST_ITEM(DrawGlyphs)
 SPECIALIZE_TYPE_TRAITS_DISPLAYLIST_ITEM(DrawImage)
 SPECIALIZE_TYPE_TRAITS_DISPLAYLIST_ITEM(DrawTiledImage)
@@ -3265,6 +3328,7 @@
     WebCore::DisplayList::ItemType::ClipOut,
     WebCore::DisplayList::ItemType::ClipOutToPath,
     WebCore::DisplayList::ItemType::ClipPath,
+    WebCore::DisplayList::ItemType::ClipToDrawingCommands,
     WebCore::DisplayList::ItemType::DrawGlyphs,
     WebCore::DisplayList::ItemType::DrawImage,
     WebCore::DisplayList::ItemType::DrawTiledImage,

Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -381,6 +381,13 @@
     WTFLogAlways("GraphicsContext::clipToImageBuffer is not compatible with DisplayList::Recorder.");
 }
 
+void Recorder::clipToDrawingCommands(const FloatRect& destination, ColorSpace colorSpace, Function<void(GraphicsContext&)>&& drawingFunction)
+{
+    auto recordingContext = makeUnique<DrawingContext>(destination.size());
+    drawingFunction(recordingContext->context());
+    appendItem(ClipToDrawingCommands::create(destination, colorSpace, recordingContext->takeDisplayList()));
+}
+
 void Recorder::applyDeviceScaleFactor(float deviceScaleFactor)
 {
     // FIXME: this changes the baseCTM, which will invalidate all of our cached extents.

Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -136,6 +136,7 @@
     void clipPath(const Path&, WindRule) override;
     IntRect clipBounds() override;
     void clipToImageBuffer(WebCore::ImageBuffer&, const FloatRect&) override;
+    void clipToDrawingCommands(const FloatRect& destination, ColorSpace, Function<void(GraphicsContext&)>&&) override;
     
     void applyDeviceScaleFactor(float) override;
 

Modified: trunk/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.cpp (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -1090,4 +1090,9 @@
     m_commandList.append(WTFMove(command));
 }
 
+void CairoOperationRecorder::clipToDrawingCommands(const FloatRect&, ColorSpace, Function<void(GraphicsContext&)>&&)
+{
+    // FIXME: Not implemented.
+}
+
 } // namespace Nicosia

Modified: trunk/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/nicosia/cairo/NicosiaCairoOperationRecorder.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -99,6 +99,7 @@
     void clipPath(const WebCore::Path&, WebCore::WindRule) override;
     WebCore::IntRect clipBounds() override;
     void clipToImageBuffer(WebCore::ImageBuffer&, const WebCore::FloatRect&) override;
+    void clipToDrawingCommands(const WebCore::FloatRect& destination, WebCore::ColorSpace, Function<void(WebCore::GraphicsContext&)>&&) override;
 
     void applyDeviceScaleFactor(float) override;
 

Modified: trunk/Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.cpp (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.cpp	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.cpp	2020-09-29 16:41:49 UTC (rev 267742)
@@ -436,6 +436,11 @@
     return Direct2D::State::roundToDevicePixels(m_platformContext, rect);
 }
 
+void GraphicsContextImplDirect2D::clipToDrawingCommands(const FloatRect&, ColorSpace, Function<void(GraphicsContext&)>&&)
+{
+    // FIXME: Not implemented.
+}
+
 } // namespace WebCore
 
 #endif // USE(DIRECT2D)

Modified: trunk/Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.h (267741 => 267742)


--- trunk/Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.h	2020-09-29 16:34:53 UTC (rev 267741)
+++ trunk/Source/WebCore/platform/graphics/win/GraphicsContextImplDirect2D.h	2020-09-29 16:41:49 UTC (rev 267742)
@@ -103,6 +103,7 @@
     void clipPath(const Path&, WindRule) override;
     IntRect clipBounds() override;
     void clipToImageBuffer(ImageBuffer&, const FloatRect&) override;
+    void clipToDrawingCommands(const FloatRect& destination, ColorSpace, Function<void(GraphicsContext&)>&&) override;
     
     void applyDeviceScaleFactor(float) override;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to