<!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>[279741] trunk</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/279741">279741</a></dd>
<dt>Author</dt> <dd>mmaxfield@apple.com</dd>
<dt>Date</dt> <dd>2021-07-08 12:11:05 -0700 (Thu, 08 Jul 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Source/WebCore:
[GPU Process] Draw PDFs using an intermediate ImageBuffer when using the GPU process
https://bugs.webkit.org/show_bug.cgi?id=227550

Reviewed by Tim Horton.

When drawing PDFs, we usually already have a cached ImageBuffer of the contents of the PDF.
However, in the situation where we don't have this cached ImageBuffer, we can't just draw
the PDF into the platformContext when we're using the GPU Process. So, instead, we need to
draw the PDF into an intermediate ImageBuffer and then send that to the GPU Process.

When we have a fully functional custom CGContext, we can use that to send all the PDF drawing
commands to the GPU Process, and this patch should then be reverted.

Test: fast/images/pdf-in-canvas.html

* platform/graphics/cg/PDFDocumentImage.cpp:
(WebCore::PDFDocumentImage::draw):
* platform/mac/LocalCurrentGraphicsContextMac.mm:
(WebCore::LocalCurrentGraphicsContext::LocalCurrentGraphicsContext):

LayoutTests:
[GPU Process] Temporarily disable drawing large PDFs in display list drawing
https://bugs.webkit.org/show_bug.cgi?id=227550

Reviewed by Tim Horton.

* fast/images/pdf-in-canvas-expected.html: Added.
* fast/images/pdf-in-canvas.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgPDFDocumentImagecpp">trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmacLocalCurrentGraphicsContextMacmm">trunk/Source/WebCore/platform/mac/LocalCurrentGraphicsContextMac.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastimagespdfincanvasexpectedhtml">trunk/LayoutTests/fast/images/pdf-in-canvas-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastimagespdfincanvashtml">trunk/LayoutTests/fast/images/pdf-in-canvas.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (279740 => 279741)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2021-07-08 18:54:16 UTC (rev 279740)
+++ trunk/LayoutTests/ChangeLog 2021-07-08 19:11:05 UTC (rev 279741)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2021-07-08  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [GPU Process] Temporarily disable drawing large PDFs in display list drawing
+        https://bugs.webkit.org/show_bug.cgi?id=227550
+
+        Reviewed by Tim Horton.
+
+        * fast/images/pdf-in-canvas-expected.html: Added.
+        * fast/images/pdf-in-canvas.html: Added.
+
</ins><span class="cx"> 2021-07-08  Ayumi Kojima  <ayumi_kojima@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Mac wk2 Debug] fast/canvas/canvas-composite-image.html is a flaky crash.
</span></span></pre></div>
<a id="trunkLayoutTestsfastimagespdfincanvasexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/images/pdf-in-canvas-expected.html (0 => 279741)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/images/pdf-in-canvas-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/images/pdf-in-canvas-expected.html   2021-07-08 19:11:05 UTC (rev 279741)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<p>This test passes if you see a green box below (possibly with a green border).</p>
+<div style="position: relative;">
+    <div style="position: absolute; left: 0px; top: 0px; width: 100px; height: 100px; background: #008E00;"></div>
+    <div style="position: absolute; left: -3px; top: -3px; width: 6px; height: 106px; background: green;"></div>
+    <div style="position: absolute; left: 97px; top: -3px; width: 6px; height: 106px; background: green;"></div>
+    <div style="position: absolute; left: -3px; top: -3px; width: 106px; height: 6px; background: green;"></div>
+    <div style="position: absolute; left: -3px; top: 97px; width: 106px; height: 6px; background: green;"></div
+</div>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastimagespdfincanvashtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/images/pdf-in-canvas.html (0 => 279741)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/images/pdf-in-canvas.html                         (rev 0)
+++ trunk/LayoutTests/fast/images/pdf-in-canvas.html    2021-07-08 19:11:05 UTC (rev 279741)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<p>This test passes if you see a green box below (possibly with a green border).</p>
+<img id="image">
+<div style="position: relative;">
+    <canvas id="canvas" width="100" height="100"></canvas>
+    <div style="position: absolute; left: -3px; top: -3px; width: 6px; height: 106px; background: green;"></div>
+    <div style="position: absolute; left: 97px; top: -3px; width: 6px; height: 106px; background: green;"></div>
+    <div style="position: absolute; left: -3px; top: -3px; width: 106px; height: 6px; background: green;"></div>
+    <div style="position: absolute; left: -3px; top: 97px; width: 106px; height: 6px; background: green;"></div
+</div>
+<script>
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+}
+// Emulate a big PDF on iOS (which has the PDFImageCachingPolicy set to BelowMemoryLimit).
+if (window.internals)
+    internals.settings.setPDFImageCachingPolicy("Disabled");
+let canvas = document.getElementById("canvas");
+let context = canvas.getContext("2d");
+let image = document.getElementById("image");
+image.addEventListener("load", function() {
+    var state = 0;
+    function tick() {
+        context.drawImage(image, 0, 0, 100, 100);
+        if (state < 10) {
+            context.fillRect(0, 0, 100, 100);
+            ++state;
+            requestAnimationFrame(tick);
+        } else {
+            image.style.display = "none";
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+    }
+    requestAnimationFrame(tick);
+});
+image.src = "resources/green_rectangle.pdf";
+</script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (279740 => 279741)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-07-08 18:54:16 UTC (rev 279740)
+++ trunk/Source/WebCore/ChangeLog      2021-07-08 19:11:05 UTC (rev 279741)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2021-07-08  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [GPU Process] Draw PDFs using an intermediate ImageBuffer when using the GPU process
+        https://bugs.webkit.org/show_bug.cgi?id=227550
+
+        Reviewed by Tim Horton.
+
+        When drawing PDFs, we usually already have a cached ImageBuffer of the contents of the PDF.
+        However, in the situation where we don't have this cached ImageBuffer, we can't just draw
+        the PDF into the platformContext when we're using the GPU Process. So, instead, we need to
+        draw the PDF into an intermediate ImageBuffer and then send that to the GPU Process.
+
+        When we have a fully functional custom CGContext, we can use that to send all the PDF drawing
+        commands to the GPU Process, and this patch should then be reverted.
+
+        Test: fast/images/pdf-in-canvas.html
+
+        * platform/graphics/cg/PDFDocumentImage.cpp:
+        (WebCore::PDFDocumentImage::draw):
+        * platform/mac/LocalCurrentGraphicsContextMac.mm:
+        (WebCore::LocalCurrentGraphicsContext::LocalCurrentGraphicsContext):
+
</ins><span class="cx"> 2021-07-08  Yusuke Suzuki  <ysuzuki@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Use JSC::Yarr::flagsString to get string representation of RegExp flags
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgPDFDocumentImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp (279740 => 279741)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp   2021-07-08 18:54:16 UTC (rev 279740)
+++ trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp      2021-07-08 19:11:05 UTC (rev 279741)
</span><span class="lines">@@ -161,6 +161,9 @@
</span><span class="cx">     context.translate(dstRect.location() - srcRect.location());
</span><span class="cx">     context.scale(FloatSize(hScale, -vScale));
</span><span class="cx">     context.translate(0, -srcRect.height());
</span><ins>+
+    // FIXME https://bugs.webkit.org/show_bug.cgi?id=227808: Surely there needs to be a clip operation here,
+    // if the srcRect is smaller than the whole PDF.
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // To avoid the jetsam on iOS, we are going to limit the size of all the PDF cachedImages to be 64MB.
</span><span class="lines">@@ -246,6 +249,8 @@
</span><span class="cx">     // We need to transform the coordinate system such that top-left of m_cachedImageRect will be mapped to the
</span><span class="cx">     // top-left of dstRect. Although only m_cachedImageRect.size() of the image copied, the sizes of srcRect
</span><span class="cx">     // and dstRect should be passed to this function because they are used to calculate the image scaling.
</span><ins>+    // FIXME https://bugs.webkit.org/show_bug.cgi?id=227809: Passing in m_cachedImageRect.location() for the
+    // source rect position doesn't seem correct here.
</ins><span class="cx">     transformContextForPainting(bufferContext, dstRect, FloatRect(m_cachedImageRect.location(), srcRect.size()));
</span><span class="cx">     drawPDFPage(bufferContext);
</span><span class="cx"> 
</span><span class="lines">@@ -275,10 +280,25 @@
</span><span class="cx">             // of the source PDF was copied to 'm_cachedImageBuffer', the sizes of the source
</span><span class="cx">             // and the destination rectangles will be equal and no scaling will be needed here.
</span><span class="cx">             context.drawImageBuffer(*m_cachedImageBuffer, m_cachedImageRect);
</span><del>-        }
-        else {
</del><ins>+        } else if (context.hasPlatformContext()) {
</ins><span class="cx">             transformContextForPainting(context, dstRect, srcRect);
</span><span class="cx">             drawPDFPage(context);
</span><ins>+        } else {
+            // We can't draw the PDF directly because we have no platform context (probably because we're doing display list drawing).
+            // We also need to be careful about not getting terminated due to memory pressure.
+            //
+            // (scalar * width) * (scalar * height) = max number of pixels
+            // Solve for scalar...
+            // scalar = sqrt(max number of pixels / (width * height))
+            auto scalar = std::min(1.f, std::sqrt(static_cast<float>(s_maxCachedImageArea) / (dstRect.width() * dstRect.height())));
+            FloatRect localDestinationRect(FloatPoint(), dstRect.size() * scalar);
+            if (auto imageBuffer = ImageBuffer::createCompatibleBuffer(localDestinationRect.size(), context)) {
+                auto& bufferContext = imageBuffer->context();
+                transformContextForPainting(bufferContext, localDestinationRect, srcRect);
+                drawPDFPage(bufferContext);
+                context.drawImageBuffer(*imageBuffer, dstRect);
+            } else
+                return ImageDrawResult::DidNothing;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmacLocalCurrentGraphicsContextMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mac/LocalCurrentGraphicsContextMac.mm (279740 => 279741)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/LocalCurrentGraphicsContextMac.mm      2021-07-08 18:54:16 UTC (rev 279740)
+++ trunk/Source/WebCore/platform/mac/LocalCurrentGraphicsContextMac.mm 2021-07-08 19:11:05 UTC (rev 279741)
</span><span class="lines">@@ -32,7 +32,8 @@
</span><span class="cx">     m_savedGraphicsContext.save();
</span><span class="cx"> 
</span><span class="cx">     if (!m_savedGraphicsContext.hasPlatformContext()) {
</span><del>-        WTFLogAlways("LocalCurrentGraphicsContext is not setting the global context because the provided GraphicsContext does not have a platform context (likely display list recording)");
</del><ins>+        WTFLogAlways("LocalCurrentGraphicsContext is setting the global context to nil because the provided GraphicsContext does not have a platform context (likely display list recording)");
+        [NSGraphicsContext setCurrentContext:nil];
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>