<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[288076] trunk/Source</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/288076">288076</a></dd>
<dt>Author</dt> <dd>heycam@apple.com</dd>
<dt>Date</dt> <dd>2022-01-16 14:10:02 -0800 (Sun, 16 Jan 2022)</dd>
</dl>

<h3>Log Message</h3>
<pre>Ensure in flight layer transactions don't accumulate further canvas drawing
https://bugs.webkit.org/show_bug.cgi?id=231163
<rdar://problem/83863292>

Reviewed by Simon Fraser.

Source/WebCore:

When UI side compositing is enabled (as it is on iOS), we build a
layer tree transaction in RemoteLayerTreeDrawingArea::updateRendering to
send off to the UI process. At a high level, updateRendering does this:

1. Run any requestAnimationFrame callbacks
2. Iterate over the composited layers to draw their contents into the
   layer backing stores
3. Dispatch a task to a different thread to flush the contexts of the
   layer backing stores and then send the transaction to the UI
   process

Step 3 is done off a separate task as an optimization, to get the
drawing work queued up by step 2 happening in parallel to any work the
page may day once updateRendering is finished. This can be a problem
when:

- GPU process canvas rendering is enabled (but DOM rendering is
  disabled)
- we have accelerated ImageBuffers for both layer backing stores and
  canvas backing stores
- the page does canvas drawing between steps 2 and 3, which affects
  the contents of a canvas backing store IOSurface that was drawn into
  a layer backing store IOSurface while building the transaction

The way we draw the canvas contents into the layer is by creating a
CGImage from the canvas backing store ImageBuffer's IOSurface.
Normally, if we draw into an IOSurface that has been wrapped by a
CGImage, this will cause the CGImage to obtain a unique copy of the
IOSurface's pixels, rather than continue holding on to the IOSurface
itself.

When the drawing of this CGImage on to the layer backing store
IOSurface happens, the "draw image" command is queued up to be
processed later. It's only when the flush happens in step 3 above that
the drawing occurs. This means that the CGImage wrapping the IOSurface
exists until that flush.

But while the CGImage does exist, it's in the Web process, and the
canvas drawing on to the same IOSurface happens in the GPU process.
Since QuartzCore doesn't know of its existence, it doesn't cause the
copy-on-write to occur. The effect of this is that subsequent page
drawing on to the canvas can make its way into the layer transaction
unexpectedly.

This patch induces the copy-on-write in the Web process when needed,
by tracking whether a canvas has been drawn into a layer backing
store and the layer transaction flush hasn't happened yet. Just before
we do any more drawing on the canvas, if we are in this state, we
perform a no-op drawing command on the IOSurface, then flush, to make
the CGImage copy the IOSurface data out.

* html/HTMLCanvasElement.cpp:
(WebCore::imageDrawingRequiresGuardAgainstUseByPendingLayerTransaction):
We only need to induce the CGImage copy-on-write behavior if both the
layer and canvas backing stores are accelerated, the canvas
ImageBuffer is remote, and the layer ImageBuffer is not remote.
(WebCore::HTMLCanvasElement::paint):
(WebCore::HTMLCanvasElement::drawingContext const):
Use drawingContext as a convenient single place to check whether we
are performing the first drawing command before the layer tree
transaction flush has happened.
* html/HTMLCanvasElement.h:
* page/Page.h:
(WebCore::Page::setIsAwaitingLayerTreeTransactionFlush):
(WebCore::Page::isAwaitingLayerTreeTransactionFlush const):
* platform/graphics/ImageBufferBackend.h:
(WebCore::ImageBufferBackend::ensureNativeImagesHaveCopiedBackingStore):
* platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp:
(WebCore::ImageBufferIOSurfaceBackend::ensureNativeImagesHaveCopiedBackingStore):
The flush is needed since the CGImage wrapping the IOSurface will only
copy the pixel data out once the no-op drawing command is processed.
* platform/graphics/cg/ImageBufferIOSurfaceBackend.h:

Source/WebKit:

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::willCommitLayerTree):
(WebKit::WebPage::didFlushLayerTreeAtTime):
Inform the WebCore::Page about the state of the layer tree transaction
building.
* WebProcess/WebPage/WebPage.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLCanvasElementcpp">trunk/Source/WebCore/html/HTMLCanvasElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLCanvasElementh">trunk/Source/WebCore/html/HTMLCanvasElement.h</a></li>
<li><a href="#trunkSourceWebCorepagePageh">trunk/Source/WebCore/page/Page.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsImageBufferBackendh">trunk/Source/WebCore/platform/graphics/ImageBufferBackend.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageBufferIOSurfaceBackendcpp">trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgImageBufferIOSurfaceBackendh">trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.h</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebPageWebPagecpp">trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebCore/ChangeLog      2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -1,3 +1,84 @@
</span><ins>+2022-01-16  Cameron McCormack  <heycam@apple.com>
+
+        Ensure in flight layer transactions don't accumulate further canvas drawing
+        https://bugs.webkit.org/show_bug.cgi?id=231163
+        <rdar://problem/83863292>
+
+        Reviewed by Simon Fraser.
+
+        When UI side compositing is enabled (as it is on iOS), we build a
+        layer tree transaction in RemoteLayerTreeDrawingArea::updateRendering to
+        send off to the UI process. At a high level, updateRendering does this:
+
+        1. Run any requestAnimationFrame callbacks
+        2. Iterate over the composited layers to draw their contents into the
+           layer backing stores
+        3. Dispatch a task to a different thread to flush the contexts of the
+           layer backing stores and then send the transaction to the UI
+           process
+
+        Step 3 is done off a separate task as an optimization, to get the
+        drawing work queued up by step 2 happening in parallel to any work the
+        page may day once updateRendering is finished. This can be a problem
+        when:
+
+        - GPU process canvas rendering is enabled (but DOM rendering is
+          disabled)
+        - we have accelerated ImageBuffers for both layer backing stores and
+          canvas backing stores
+        - the page does canvas drawing between steps 2 and 3, which affects
+          the contents of a canvas backing store IOSurface that was drawn into
+          a layer backing store IOSurface while building the transaction
+
+        The way we draw the canvas contents into the layer is by creating a
+        CGImage from the canvas backing store ImageBuffer's IOSurface.
+        Normally, if we draw into an IOSurface that has been wrapped by a
+        CGImage, this will cause the CGImage to obtain a unique copy of the
+        IOSurface's pixels, rather than continue holding on to the IOSurface
+        itself.
+
+        When the drawing of this CGImage on to the layer backing store
+        IOSurface happens, the "draw image" command is queued up to be
+        processed later. It's only when the flush happens in step 3 above that
+        the drawing occurs. This means that the CGImage wrapping the IOSurface
+        exists until that flush.
+
+        But while the CGImage does exist, it's in the Web process, and the
+        canvas drawing on to the same IOSurface happens in the GPU process.
+        Since QuartzCore doesn't know of its existence, it doesn't cause the
+        copy-on-write to occur. The effect of this is that subsequent page
+        drawing on to the canvas can make its way into the layer transaction
+        unexpectedly.
+
+        This patch induces the copy-on-write in the Web process when needed,
+        by tracking whether a canvas has been drawn into a layer backing
+        store and the layer transaction flush hasn't happened yet. Just before
+        we do any more drawing on the canvas, if we are in this state, we
+        perform a no-op drawing command on the IOSurface, then flush, to make
+        the CGImage copy the IOSurface data out.
+
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::imageDrawingRequiresGuardAgainstUseByPendingLayerTransaction):
+        We only need to induce the CGImage copy-on-write behavior if both the
+        layer and canvas backing stores are accelerated, the canvas
+        ImageBuffer is remote, and the layer ImageBuffer is not remote.
+        (WebCore::HTMLCanvasElement::paint):
+        (WebCore::HTMLCanvasElement::drawingContext const):
+        Use drawingContext as a convenient single place to check whether we
+        are performing the first drawing command before the layer tree
+        transaction flush has happened.
+        * html/HTMLCanvasElement.h:
+        * page/Page.h:
+        (WebCore::Page::setIsAwaitingLayerTreeTransactionFlush):
+        (WebCore::Page::isAwaitingLayerTreeTransactionFlush const):
+        * platform/graphics/ImageBufferBackend.h:
+        (WebCore::ImageBufferBackend::ensureNativeImagesHaveCopiedBackingStore):
+        * platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp:
+        (WebCore::ImageBufferIOSurfaceBackend::ensureNativeImagesHaveCopiedBackingStore):
+        The flush is needed since the CGImage wrapping the IOSurface will only
+        copy the pixel data out once the no-op drawing command is processed.
+        * platform/graphics/cg/ImageBufferIOSurfaceBackend.h:
+
</ins><span class="cx"> 2022-01-15  Sam Weinig  <weinig@apple.com>
</span><span class="cx"> 
</span><span class="cx">         CSS Gradients: interpolation mode should default to OKLab if any non-legacy color syntax colors are used in the stops
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLCanvasElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp  2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp     2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -601,7 +601,19 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if PLATFORM(COCOA)
+static bool imageDrawingRequiresGuardAgainstUseByPendingLayerTransaction(GraphicsContext& context, const ImageBuffer& imageBuffer)
+{
+    if (context.renderingMode() != RenderingMode::Accelerated || !context.hasPlatformContext())
+        return false;
</ins><span class="cx"> 
</span><ins>+    if (imageBuffer.renderingMode() != RenderingMode::Accelerated || imageBuffer.context().hasPlatformContext())
+        return false;
+
+    return true;
+}
+#endif
+
</ins><span class="cx"> void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r)
</span><span class="cx"> {
</span><span class="cx">     if (m_context)
</span><span class="lines">@@ -620,8 +632,12 @@
</span><span class="cx"> 
</span><span class="cx">         if (shouldPaint) {
</span><span class="cx">             if (hasCreatedImageBuffer()) {
</span><del>-                if (ImageBuffer* imageBuffer = buffer())
</del><ins>+                if (ImageBuffer* imageBuffer = buffer()) {
</ins><span class="cx">                     context.drawImageBuffer(*imageBuffer, snappedIntRect(r));
</span><ins>+#if PLATFORM(COCOA)
+                    m_mustGuardAgainstUseByPendingLayerTransaction |= imageDrawingRequiresGuardAgainstUseByPendingLayerTransaction(context, *imageBuffer);
+#endif
+                }
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1040,4 +1056,25 @@
</span><span class="cx">     return m_context && m_context->isPlaceholder();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if PLATFORM(COCOA)
+GraphicsContext* HTMLCanvasElement::drawingContext() const
+{
+    auto context = CanvasBase::drawingContext();
+    if (!context)
+        return nullptr;
+
+    if (m_mustGuardAgainstUseByPendingLayerTransaction) {
+        if (auto page = document().page()) {
+            if (page->isAwaitingLayerTreeTransactionFlush()) {
+                if (auto backend = buffer()->backend())
+                    backend->ensureNativeImagesHaveCopiedBackingStore();
+            }
+        }
+        m_mustGuardAgainstUseByPendingLayerTransaction = false;
+    }
+
+    return context;
</ins><span class="cx"> }
</span><ins>+#endif
+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLCanvasElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLCanvasElement.h (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLCanvasElement.h    2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.h       2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -139,6 +139,10 @@
</span><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT static size_t maxActivePixelMemory();
</span><span class="cx"> 
</span><ins>+#if PLATFORM(COCOA)
+    GraphicsContext* drawingContext() const final;
+#endif
+
</ins><span class="cx"> private:
</span><span class="cx">     HTMLCanvasElement(const QualifiedName&, Document&);
</span><span class="cx"> 
</span><span class="lines">@@ -192,6 +196,9 @@
</span><span class="cx">     bool m_hasRelevantWebGLEventListener { false };
</span><span class="cx"> #endif
</span><span class="cx">     bool m_isSnapshotting { false };
</span><ins>+#if PLATFORM(COCOA)
+    mutable bool m_mustGuardAgainstUseByPendingLayerTransaction { false };
+#endif
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorepagePageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Page.h (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Page.h 2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebCore/page/Page.h    2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -927,6 +927,11 @@
</span><span class="cx">     void setAccessibilityRootObject(AccessibilityRootAtspi* rootObject) { m_accessibilityRootObject = rootObject; }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if PLATFORM(COCOA)
+    void setIsAwaitingLayerTreeTransactionFlush(bool isAwaiting) { m_isAwaitingLayerTreeTransactionFlush = isAwaiting; }
+    bool isAwaitingLayerTreeTransactionFlush() const { return m_isAwaitingLayerTreeTransactionFlush; }
+#endif
+
</ins><span class="cx"> private:
</span><span class="cx">     struct Navigation {
</span><span class="cx">         RegistrableDomain domain;
</span><span class="lines">@@ -1188,6 +1193,10 @@
</span><span class="cx">     bool m_isEditableRegionEnabled { false };
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if PLATFORM(COCOA)
+    bool m_isAwaitingLayerTreeTransactionFlush { false };
+#endif
+
</ins><span class="cx">     Vector<OptionSet<RenderingUpdateStep>, 2> m_renderingUpdateRemainingSteps;
</span><span class="cx">     OptionSet<RenderingUpdateStep> m_unfulfilledRequestedSteps;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsImageBufferBackendh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ImageBufferBackend.h (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ImageBufferBackend.h      2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebCore/platform/graphics/ImageBufferBackend.h 2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -129,6 +129,8 @@
</span><span class="cx">     static constexpr bool canMapBackingStore = true;
</span><span class="cx">     static constexpr RenderingMode renderingMode = RenderingMode::Unaccelerated;
</span><span class="cx"> 
</span><ins>+    virtual void ensureNativeImagesHaveCopiedBackingStore() { }
+
</ins><span class="cx"> protected:
</span><span class="cx">     WEBCORE_EXPORT ImageBufferBackend(const Parameters&);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageBufferIOSurfaceBackendcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp        2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp   2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -244,6 +244,12 @@
</span><span class="cx">     IOSurface::moveToPool(WTFMove(m_surface));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ImageBufferIOSurfaceBackend::ensureNativeImagesHaveCopiedBackingStore()
+{
+    invalidateCachedNativeImage();
+    flushContext();
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // HAVE(IOSURFACE)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgImageBufferIOSurfaceBackendh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.h (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.h  2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.h     2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -69,6 +69,8 @@
</span><span class="cx">     VolatilityState setVolatile(bool) override;
</span><span class="cx">     void releaseBufferToPool() override;
</span><span class="cx"> 
</span><ins>+    void ensureNativeImagesHaveCopiedBackingStore() final;
+
</ins><span class="cx">     static constexpr RenderingMode renderingMode = RenderingMode::Accelerated;
</span><span class="cx"> 
</span><span class="cx"> protected:
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebKit/ChangeLog       2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2022-01-16  Cameron McCormack  <heycam@apple.com>
+
+        Ensure in flight layer transactions don't accumulate further canvas drawing
+        https://bugs.webkit.org/show_bug.cgi?id=231163
+        <rdar://problem/83863292>
+
+        Reviewed by Simon Fraser.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::willCommitLayerTree):
+        (WebKit::WebPage::didFlushLayerTreeAtTime):
+        Inform the WebCore::Page about the state of the layer tree transaction
+        building.
+        * WebProcess/WebPage/WebPage.h:
+
</ins><span class="cx"> 2022-01-15  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Introduce dynamicDowncast<>() for convenience
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebPageWebPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (288075 => 288076)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp       2022-01-16 21:44:55 UTC (rev 288075)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp  2022-01-16 22:10:02 UTC (rev 288076)
</span><span class="lines">@@ -4170,6 +4170,8 @@
</span><span class="cx">     if (!frameView)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    corePage()->setIsAwaitingLayerTreeTransactionFlush(true);
+
</ins><span class="cx">     layerTransaction.setContentsSize(frameView->contentsSize());
</span><span class="cx">     layerTransaction.setScrollOrigin(frameView->scrollOrigin());
</span><span class="cx">     layerTransaction.setPageScaleFactor(corePage()->pageScaleFactor());
</span><span class="lines">@@ -4227,6 +4229,7 @@
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(timestamp);
</span><span class="cx"> #endif
</span><ins>+    corePage()->setIsAwaitingLayerTreeTransactionFlush(false);
</ins><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>