<!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>[203378] 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/203378">203378</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-07-18 15:46:37 -0700 (Mon, 18 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS] PDFDocumentImage should cache only a sub image of the PDF when caching the whole image is expensive
https://bugs.webkit.org/show_bug.cgi?id=158715

Source/WebCore:

Patch by Said Abou-Hallawa &lt;sabouhallawa@apple,com&gt; on 2016-07-18
Reviewed by Dean Jackson.

Test: fast/images/displaced-non-cached-pdf.html

For iOS, we need to ensure the size of the cached PDF images will not
exceed some limit. Also we should be caching only a sub image of the PDF
if caching the whole image will exceed the memory limit.

* page/Settings.cpp:
(WebCore::Settings::Settings):
(WebCore::Settings::setCachedPDFImageEnabled):
* page/Settings.h:
(WebCore::Settings::isCachedPDFImageEnabled):
    Add an option to disable caching the PDF images.

* platform/graphics/cg/PDFDocumentImage.cpp:
(WebCore::PDFDocumentImage::setCachedPDFImageEnabled):
    Allow the caller of draw() to disable caching the PDF images.

(WebCore::PDFDocumentImage::cacheParametersMatch):
    Match the context dirty rectangle with the cached image rectangle.

(WebCore::transformContextForPainting):
    When preparing the context for drawing the PDF, take the location
    of the destination rectangle into account. We do not need to scale
    the location of the source rectangle because we scale the size of
    the rectangle but we don't scale the whole coordinate system.

(WebCore::cachedImageRect):
    Calculate the rectangle of the cached image such that it does not
    exceed the limit. Start from the center of the dirty rectangle and
    then expand around it.

(WebCore::PDFDocumentImage::decodedSizeChanged):
    In addition to notifying the ImageObserver, it keeps track of the size
    of all the cached PDF images.

(WebCore::PDFDocumentImage::updateCachedImageIfNeeded):
    Ensure the size of all the cached images does not exceed the limit

(WebCore::PDFDocumentImage::destroyDecodedData):
* platform/graphics/cg/PDFDocumentImage.h:

* rendering/RenderImage.cpp:
(WebCore::RenderImage::paintIntoRect):
    Pass the option to disable caching the PDF images to PDFDocumentImage.

* testing/InternalSettings.cpp:
(WebCore::InternalSettings::Backup::Backup):
(WebCore::InternalSettings::Backup::restoreTo):
(WebCore::InternalSettings::setCachedPDFImageEnabled):
* testing/InternalSettings.h:
* testing/InternalSettings.idl:
    Add an internal option to disable caching the PDF images.

LayoutTests:

Patch by Said Abou-Hallawa &lt;sabouhallawa@apple.com&gt; on 2016-07-18
Reviewed by Dean Jackson.

Make sure the PDF image will be displayed at the correct position if caching
the PDF image is disabled.

* fast/images/displaced-non-cached-pdf-expected.html: Added.
* fast/images/displaced-non-cached-pdf.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="#trunkSourceWebCorepageSettingscpp">trunk/Source/WebCore/page/Settings.cpp</a></li>
<li><a href="#trunkSourceWebCorepageSettingsh">trunk/Source/WebCore/page/Settings.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgPDFDocumentImagecpp">trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgPDFDocumentImageh">trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderImagecpp">trunk/Source/WebCore/rendering/RenderImage.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalSettingscpp">trunk/Source/WebCore/testing/InternalSettings.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalSettingsh">trunk/Source/WebCore/testing/InternalSettings.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalSettingsidl">trunk/Source/WebCore/testing/InternalSettings.idl</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastimagesdisplacednoncachedpdfexpectedhtml">trunk/LayoutTests/fast/images/displaced-non-cached-pdf-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastimagesdisplacednoncachedpdfhtml">trunk/LayoutTests/fast/images/displaced-non-cached-pdf.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/LayoutTests/ChangeLog        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-07-18  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        [iOS] PDFDocumentImage should cache only a sub image of the PDF when caching the whole image is expensive
+        https://bugs.webkit.org/show_bug.cgi?id=158715
+
+        Reviewed by Dean Jackson.
+        
+        Make sure the PDF image will be displayed at the correct position if caching
+        the PDF image is disabled.
+
+        * fast/images/displaced-non-cached-pdf-expected.html: Added.
+        * fast/images/displaced-non-cached-pdf.html: Added.
+
</ins><span class="cx"> 2016-07-18  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         The 2 first parameters to addEventListener() / removeEventListener() should be mandatory
</span></span></pre></div>
<a id="trunkLayoutTestsfastimagesdisplacednoncachedpdfexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/images/displaced-non-cached-pdf-expected.html (0 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/images/displaced-non-cached-pdf-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/images/displaced-non-cached-pdf-expected.html        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+&lt;!DOCTYPE HTML&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        div {
+            width: 100px;
+            height: 100px;
+            display: inline-block;
+            background-color: rgb(0, 143, 0);
+        }
+    &lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div&gt;&lt;/div&gt;
+    &lt;div&gt;&lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastimagesdisplacednoncachedpdfhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/images/displaced-non-cached-pdf.html (0 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/images/displaced-non-cached-pdf.html                                (rev 0)
+++ trunk/LayoutTests/fast/images/displaced-non-cached-pdf.html        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+&lt;!DOCTYPE HTML&gt;
+&lt;html&gt;
+&lt;body&gt;
+    &lt;script&gt;
+        if (window.testRunner &amp;&amp; window.internals)
+            window.internals.settings.setCachedPDFImageEnabled(false);
+    &lt;/script&gt;
+    &lt;img src=&quot;resources/green_rectangle.pdf&quot;&gt;
+    &lt;img src=&quot;resources/green_rectangle.pdf&quot;&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/ChangeLog        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2016-07-18  Said Abou-Hallawa  &lt;sabouhallawa@apple,com&gt;
+
+        [iOS] PDFDocumentImage should cache only a sub image of the PDF when caching the whole image is expensive
+        https://bugs.webkit.org/show_bug.cgi?id=158715
+
+        Reviewed by Dean Jackson.
+
+        Test: fast/images/displaced-non-cached-pdf.html
+
+        For iOS, we need to ensure the size of the cached PDF images will not
+        exceed some limit. Also we should be caching only a sub image of the PDF
+        if caching the whole image will exceed the memory limit.
+
+        * page/Settings.cpp:
+        (WebCore::Settings::Settings):
+        (WebCore::Settings::setCachedPDFImageEnabled):
+        * page/Settings.h:
+        (WebCore::Settings::isCachedPDFImageEnabled):
+            Add an option to disable caching the PDF images.
+
+        * platform/graphics/cg/PDFDocumentImage.cpp:
+        (WebCore::PDFDocumentImage::setCachedPDFImageEnabled):
+            Allow the caller of draw() to disable caching the PDF images.
+        
+        (WebCore::PDFDocumentImage::cacheParametersMatch):
+            Match the context dirty rectangle with the cached image rectangle.
+        
+        (WebCore::transformContextForPainting):
+            When preparing the context for drawing the PDF, take the location 
+            of the destination rectangle into account. We do not need to scale
+            the location of the source rectangle because we scale the size of
+            the rectangle but we don't scale the whole coordinate system.
+
+        (WebCore::cachedImageRect):
+            Calculate the rectangle of the cached image such that it does not
+            exceed the limit. Start from the center of the dirty rectangle and
+            then expand around it.
+            
+        (WebCore::PDFDocumentImage::decodedSizeChanged):
+            In addition to notifying the ImageObserver, it keeps track of the size
+            of all the cached PDF images.
+
+        (WebCore::PDFDocumentImage::updateCachedImageIfNeeded):
+            Ensure the size of all the cached images does not exceed the limit
+            
+        (WebCore::PDFDocumentImage::destroyDecodedData):
+        * platform/graphics/cg/PDFDocumentImage.h:
+
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::paintIntoRect):
+            Pass the option to disable caching the PDF images to PDFDocumentImage.
+
+        * testing/InternalSettings.cpp:
+        (WebCore::InternalSettings::Backup::Backup):
+        (WebCore::InternalSettings::Backup::restoreTo):
+        (WebCore::InternalSettings::setCachedPDFImageEnabled):
+        * testing/InternalSettings.h:
+        * testing/InternalSettings.idl:
+            Add an internal option to disable caching the PDF images.
+
</ins><span class="cx"> 2016-07-18  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         The 2 first parameters to addEventListener() / removeEventListener() should be mandatory
</span></span></pre></div>
<a id="trunkSourceWebCorepageSettingscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Settings.cpp (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Settings.cpp        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/page/Settings.cpp        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -193,6 +193,7 @@
</span><span class="cx">     , m_loadsImagesAutomatically(false)
</span><span class="cx">     , m_areImagesEnabled(true)
</span><span class="cx">     , m_preferMIMETypeForImages(false)
</span><ins>+    , m_isCachedPDFImageEnabled(true)
</ins><span class="cx">     , m_arePluginsEnabled(false)
</span><span class="cx">     , m_isScriptEnabled(false)
</span><span class="cx">     , m_needsAdobeFrameReloadingQuirk(false)
</span><span class="lines">@@ -425,6 +426,11 @@
</span><span class="cx">     m_preferMIMETypeForImages = preferMIMETypeForImages;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Settings::setCachedPDFImageEnabled(bool isCachedPDFImageEnabled)
+{
+    m_isCachedPDFImageEnabled = isCachedPDFImageEnabled;
+}
+
</ins><span class="cx"> void Settings::setForcePendingWebGLPolicy(bool forced)
</span><span class="cx"> {
</span><span class="cx">     m_forcePendingWebGLPolicy = forced;
</span></span></pre></div>
<a id="trunkSourceWebCorepageSettingsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Settings.h (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Settings.h        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/page/Settings.h        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -146,6 +146,9 @@
</span><span class="cx">     WEBCORE_EXPORT void setPreferMIMETypeForImages(bool);
</span><span class="cx">     bool preferMIMETypeForImages() const { return m_preferMIMETypeForImages; }
</span><span class="cx"> 
</span><ins>+    WEBCORE_EXPORT void setCachedPDFImageEnabled(bool);
+    bool isCachedPDFImageEnabled() const { return m_isCachedPDFImageEnabled; }
+
</ins><span class="cx">     WEBCORE_EXPORT void setPluginsEnabled(bool);
</span><span class="cx">     bool arePluginsEnabled() const { return m_arePluginsEnabled; }
</span><span class="cx"> 
</span><span class="lines">@@ -328,6 +331,7 @@
</span><span class="cx">     bool m_loadsImagesAutomatically : 1;
</span><span class="cx">     bool m_areImagesEnabled : 1;
</span><span class="cx">     bool m_preferMIMETypeForImages : 1;
</span><ins>+    bool m_isCachedPDFImageEnabled : 1;
</ins><span class="cx">     bool m_arePluginsEnabled : 1;
</span><span class="cx">     bool m_isScriptEnabled : 1;
</span><span class="cx">     bool m_needsAdobeFrameReloadingQuirk : 1;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgPDFDocumentImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -100,6 +100,15 @@
</span><span class="cx">     return m_document; // Return true if size is available.
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PDFDocumentImage::setCachedPDFImageEnabled(bool enabled)
+{
+    if (m_isCachedPDFImageEnabled == enabled)
+        return;
+
+    if (!(m_isCachedPDFImageEnabled = enabled))
+        destroyDecodedData();
+}
+
</ins><span class="cx"> bool PDFDocumentImage::cacheParametersMatch(GraphicsContext&amp; context, const FloatRect&amp; dstRect, const FloatRect&amp; srcRect) const
</span><span class="cx"> {
</span><span class="cx">     if (dstRect.size() != m_cachedDestinationSize)
</span><span class="lines">@@ -108,6 +117,9 @@
</span><span class="cx">     if (srcRect != m_cachedSourceRect)
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><ins>+    if (!m_cachedImageRect.contains(context.clipBounds()))
+        return false;
+
</ins><span class="cx">     AffineTransform::DecomposedType decomposedTransform;
</span><span class="cx">     context.getCTM(GraphicsContext::DefinitelyIncludeDeviceScale).decompose(decomposedTransform);
</span><span class="cx"> 
</span><span class="lines">@@ -137,23 +149,59 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    context.translate(srcRect.x() * hScale, srcRect.y() * vScale);
</del><ins>+    // drawPDFPage() relies on drawing the whole PDF into a context starting at (0, 0). We need
+    // to transform the destination context such that srcRect of the source context will be drawn
+    // in dstRect of destination context.
+    context.translate(dstRect.x() - srcRect.x(), dstRect.y() - srcRect.y());
</ins><span class="cx">     context.scale(FloatSize(hScale, -vScale));
</span><span class="cx">     context.translate(0, -srcRect.height());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if PLATFORM(IOS)
+// To avoid the jetsam on iOS, we are going to limit the size of all the PDF cachedImages to be 64MB.
+static const size_t s_maxCachedImageSide = 4 * 1024;
+static const size_t s_maxCachedImageArea = s_maxCachedImageSide * s_maxCachedImageSide;
+
+static const size_t s_maxDecodedDataSize = s_maxCachedImageArea * 4;
+static size_t s_allDecodedDataSize = 0;
+
+static FloatRect cachedImageRect(GraphicsContext&amp; context, const FloatRect&amp; dstRect)
+{
+    FloatSize maxSize = s_maxCachedImageSide / context.scaleFactor();
+
+    // Expand from the center of the dirty rectangle.
+    FloatRect rect = context.clipBounds();
+    rect.setX(std::max(rect.center().x() - maxSize.width() / 2, dstRect.x()));
+    rect.setY(std::max(rect.center().y() - maxSize.height() / 2, dstRect.y()));
+
+    // Cover as much as we could from the dstRect.
+    rect.setWidth(std::min(maxSize.width(), dstRect.width()));
+    rect.setHeight(std::min(maxSize.height(), dstRect.height()));
+    return rect;
+}
+#endif
+
+void PDFDocumentImage::decodedSizeChanged(size_t newCachedBytes)
+{
+    if (!m_cachedBytes &amp;&amp; !newCachedBytes)
+        return;
+
+    if (imageObserver())
+        imageObserver()-&gt;decodedSizeChanged(this, -safeCast&lt;int&gt;(m_cachedBytes) + newCachedBytes);
+
+#if PLATFORM(IOS)
+    ASSERT(s_allDecodedDataSize &gt;= m_cachedBytes);
+    // Update with the difference in two steps to avoid unsigned underflow subtraction.
+    s_allDecodedDataSize -= m_cachedBytes;
+    s_allDecodedDataSize += newCachedBytes;
+#endif
+
+    m_cachedBytes = newCachedBytes;
+}
+
</ins><span class="cx"> void PDFDocumentImage::updateCachedImageIfNeeded(GraphicsContext&amp; context, const FloatRect&amp; dstRect, const FloatRect&amp; srcRect)
</span><span class="cx"> {
</span><span class="cx"> #if PLATFORM(IOS)
</span><del>-    // On iOS, if the physical memory is less than 1GB, do not allocate more than 16MB for the PDF cachedImage.
-    const size_t memoryThreshold = WTF::GB;
-    const size_t maxArea = 16 * WTF::MB / 4; // 16 MB maximum size, divided by a rough cost of 4 bytes per pixel of area.
-    
-    if (ramSize() &lt;= memoryThreshold &amp;&amp; ImageBuffer::compatibleBufferSize(dstRect.size(), context).area() &gt;= maxArea) {
-        m_cachedImageBuffer = nullptr;
-        return;
-    }
-
</del><span class="cx">     // On iOS, some clients use low-quality image interpolation always, which throws off this optimization,
</span><span class="cx">     // as we never get the subsequent high-quality paint. Since live resize is rare on iOS, disable the optimization.
</span><span class="cx">     // FIXME (136593): It's also possible to do the wrong thing here if CSS specifies low-quality interpolation via the &quot;image-rendering&quot;
</span><span class="lines">@@ -167,15 +215,30 @@
</span><span class="cx">     bool repaintIfNecessary = interpolationQuality != InterpolationNone &amp;&amp; interpolationQuality != InterpolationLow;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    if (m_cachedImageBuffer &amp;&amp; (!repaintIfNecessary || cacheParametersMatch(context, dstRect, srcRect)))
</del><ins>+    if (!m_isCachedPDFImageEnabled || (m_cachedImageBuffer &amp;&amp; (!repaintIfNecessary || cacheParametersMatch(context, dstRect, srcRect))))
</ins><span class="cx">         return;
</span><del>-    
-    m_cachedImageBuffer = ImageBuffer::createCompatibleBuffer(FloatRect(enclosingIntRect(dstRect)).size(), context);
-    if (!m_cachedImageBuffer)
</del><ins>+
+#if PLATFORM(IOS)
+    m_cachedImageRect = cachedImageRect(context, dstRect);
+
+    // Cache the PDF image only if the size of the new image won't exceed the limit.
+    if (s_allDecodedDataSize + m_cachedImageRect.size().area() * 4 - m_cachedBytes &gt; s_maxDecodedDataSize) {
+        destroyDecodedData();
</ins><span class="cx">         return;
</span><ins>+    }
+#else
+    m_cachedImageRect = dstRect;
+#endif
+
+    m_cachedImageBuffer = ImageBuffer::createCompatibleBuffer(FloatRect(enclosingIntRect(m_cachedImageRect)).size(), context);
+    if (!m_cachedImageBuffer) {
+        destroyDecodedData();
+        return;
+    }
+
</ins><span class="cx">     auto&amp; bufferContext = m_cachedImageBuffer-&gt;context();
</span><del>-
-    transformContextForPainting(bufferContext, dstRect, srcRect);
</del><ins>+    // The PDF cachedImage should be drawn at (0, 0) always.
+    transformContextForPainting(bufferContext, FloatRect({ }, dstRect.size()), srcRect);
</ins><span class="cx">     drawPDFPage(bufferContext);
</span><span class="cx"> 
</span><span class="cx">     m_cachedTransform = context.getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
</span><span class="lines">@@ -183,11 +246,7 @@
</span><span class="cx">     m_cachedSourceRect = srcRect;
</span><span class="cx"> 
</span><span class="cx">     IntSize internalSize = m_cachedImageBuffer-&gt;internalSize();
</span><del>-    size_t oldCachedBytes = m_cachedBytes;
-    m_cachedBytes = safeCast&lt;size_t&gt;(internalSize.width()) * internalSize.height() * 4;
-
-    if (imageObserver())
-        imageObserver()-&gt;decodedSizeChanged(this, safeCast&lt;int&gt;(m_cachedBytes) - safeCast&lt;int&gt;(oldCachedBytes));
</del><ins>+    decodedSizeChanged(safeCast&lt;size_t&gt;(internalSize.width()) * internalSize.height() * 4);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void PDFDocumentImage::draw(GraphicsContext&amp; context, const FloatRect&amp; dstRect, const FloatRect&amp; srcRect, CompositeOperator op, BlendMode, ImageOrientationDescription)
</span><span class="lines">@@ -216,11 +275,8 @@
</span><span class="cx"> void PDFDocumentImage::destroyDecodedData(bool)
</span><span class="cx"> {
</span><span class="cx">     m_cachedImageBuffer = nullptr;
</span><del>-
-    if (imageObserver())
-        imageObserver()-&gt;decodedSizeChanged(this, -safeCast&lt;int&gt;(m_cachedBytes));
-
-    m_cachedBytes = 0;
</del><ins>+    m_cachedImageRect = FloatRect();
+    decodedSizeChanged(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if !USE(PDFKIT_FOR_PDFDOCUMENTIMAGE)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgPDFDocumentImageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -52,6 +52,8 @@
</span><span class="cx">         return adoptRef(new PDFDocumentImage(observer));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void setCachedPDFImageEnabled(bool);
+
</ins><span class="cx"> private:
</span><span class="cx">     PDFDocumentImage(ImageObserver*);
</span><span class="cx">     virtual ~PDFDocumentImage();
</span><span class="lines">@@ -81,9 +83,12 @@
</span><span class="cx">     unsigned pageCount() const;
</span><span class="cx">     void drawPDFPage(GraphicsContext&amp;);
</span><span class="cx"> 
</span><ins>+    void decodedSizeChanged(size_t newCachedBytes);
</ins><span class="cx">     void updateCachedImageIfNeeded(GraphicsContext&amp;, const FloatRect&amp; dstRect, const FloatRect&amp; srcRect);
</span><span class="cx">     bool cacheParametersMatch(GraphicsContext&amp;, const FloatRect&amp; dstRect, const FloatRect&amp; srcRect) const;
</span><span class="cx"> 
</span><ins>+    bool m_isCachedPDFImageEnabled { true };
+
</ins><span class="cx"> #if USE(PDFKIT_FOR_PDFDOCUMENTIMAGE)
</span><span class="cx">     RetainPtr&lt;PDFDocument&gt; m_document;
</span><span class="cx"> #else
</span><span class="lines">@@ -91,6 +96,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     std::unique_ptr&lt;ImageBuffer&gt; m_cachedImageBuffer;
</span><ins>+    FloatRect m_cachedImageRect;
</ins><span class="cx">     AffineTransform m_cachedTransform;
</span><span class="cx">     FloatSize m_cachedDestinationSize;
</span><span class="cx">     FloatRect m_cachedSourceRect;
</span><span class="lines">@@ -103,6 +109,8 @@
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+SPECIALIZE_TYPE_TRAITS_IMAGE(PDFDocumentImage)
+
</ins><span class="cx"> #endif // USE(CG)
</span><span class="cx"> 
</span><span class="cx"> #endif // PDFDocumentImage_h
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderImage.cpp        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -58,6 +58,11 @@
</span><span class="cx"> #include &quot;SelectionRect.h&quot;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if USE(CG)
+#include &quot;PDFDocumentImage.h&quot;
+#include &quot;Settings.h&quot;
+#endif
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="lines">@@ -545,6 +550,11 @@
</span><span class="cx">     Image* image = imageResource().image().get();
</span><span class="cx">     InterpolationQuality interpolation = image ? chooseInterpolationQuality(context, *image, image, LayoutSize(rect.size())) : InterpolationDefault;
</span><span class="cx"> 
</span><ins>+#if USE(CG)
+    if (is&lt;PDFDocumentImage&gt;(image))
+        downcast&lt;PDFDocumentImage&gt;(*image).setCachedPDFImageEnabled(frame().settings().isCachedPDFImageEnabled());
+#endif
+
</ins><span class="cx">     ImageOrientationDescription orientationDescription(shouldRespectImageOrientation(), style().imageOrientation());
</span><span class="cx">     context.drawImage(*img, rect, ImagePaintingOptions(compositeOperator, BlendModeNormal, orientationDescription, interpolation));
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalSettingscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/InternalSettings.cpp (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/InternalSettings.cpp        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/testing/InternalSettings.cpp        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -80,6 +80,7 @@
</span><span class="cx">     , m_langAttributeAwareFormControlUIEnabled(RuntimeEnabledFeatures::sharedFeatures().langAttributeAwareFormControlUIEnabled())
</span><span class="cx">     , m_imagesEnabled(settings.areImagesEnabled())
</span><span class="cx">     , m_preferMIMETypeForImages(settings.preferMIMETypeForImages())
</span><ins>+    , m_cachedPDFImageEnabled(settings.isCachedPDFImageEnabled())
</ins><span class="cx">     , m_minimumTimerInterval(settings.minimumDOMTimerInterval())
</span><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><span class="cx">     , m_shouldDisplaySubtitles(settings.shouldDisplaySubtitles())
</span><span class="lines">@@ -159,6 +160,7 @@
</span><span class="cx">     RuntimeEnabledFeatures::sharedFeatures().setLangAttributeAwareFormControlUIEnabled(m_langAttributeAwareFormControlUIEnabled);
</span><span class="cx">     settings.setImagesEnabled(m_imagesEnabled);
</span><span class="cx">     settings.setPreferMIMETypeForImages(m_preferMIMETypeForImages);
</span><ins>+    settings.setCachedPDFImageEnabled(m_cachedPDFImageEnabled);
</ins><span class="cx">     settings.setMinimumDOMTimerInterval(m_minimumTimerInterval);
</span><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><span class="cx">     settings.setShouldDisplaySubtitles(m_shouldDisplaySubtitles);
</span><span class="lines">@@ -483,6 +485,12 @@
</span><span class="cx">     settings()-&gt;setImagesEnabled(enabled);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void InternalSettings::setCachedPDFImageEnabled(bool enabled, ExceptionCode&amp; ec)
+{
+    InternalSettingsGuardForSettings();
+    settings()-&gt;setCachedPDFImageEnabled(enabled);
+}
+
</ins><span class="cx"> void InternalSettings::setMinimumTimerInterval(double intervalInSeconds, ExceptionCode&amp; ec)
</span><span class="cx"> {
</span><span class="cx">     InternalSettingsGuardForSettings();
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalSettingsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/InternalSettings.h (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/InternalSettings.h        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/testing/InternalSettings.h        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -80,6 +80,7 @@
</span><span class="cx">         bool m_langAttributeAwareFormControlUIEnabled;
</span><span class="cx">         bool m_imagesEnabled;
</span><span class="cx">         bool m_preferMIMETypeForImages;
</span><ins>+        bool m_cachedPDFImageEnabled;
</ins><span class="cx">         std::chrono::milliseconds m_minimumTimerInterval;
</span><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><span class="cx">         bool m_shouldDisplaySubtitles;
</span><span class="lines">@@ -141,6 +142,7 @@
</span><span class="cx">     void setAllowsAirPlayForMediaPlayback(bool);
</span><span class="cx">     void setEditingBehavior(const String&amp;, ExceptionCode&amp;);
</span><span class="cx">     void setPreferMIMETypeForImages(bool, ExceptionCode&amp;);
</span><ins>+    void setCachedPDFImageEnabled(bool, ExceptionCode&amp;);
</ins><span class="cx">     void setShouldDisplayTrackKind(const String&amp; kind, bool enabled, ExceptionCode&amp;);
</span><span class="cx">     bool shouldDisplayTrackKind(const String&amp; kind, ExceptionCode&amp;);
</span><span class="cx">     void setStorageBlockingPolicy(const String&amp;, ExceptionCode&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalSettingsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/InternalSettings.idl (203377 => 203378)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/InternalSettings.idl        2016-07-18 22:33:32 UTC (rev 203377)
+++ trunk/Source/WebCore/testing/InternalSettings.idl        2016-07-18 22:46:37 UTC (rev 203378)
</span><span class="lines">@@ -68,6 +68,7 @@
</span><span class="cx">     // Other switches
</span><span class="cx">     [RaisesException] void setStorageBlockingPolicy(DOMString policy);
</span><span class="cx">     [RaisesException] void setImagesEnabled(boolean enabled);
</span><ins>+    [RaisesException] void setCachedPDFImageEnabled(boolean enabled);
</ins><span class="cx">     [RaisesException] void setUseLegacyBackgroundSizeShorthandBehavior(boolean enabled);
</span><span class="cx">     [RaisesException] void setAutoscrollForDragAndDropEnabled(boolean enabled);
</span><span class="cx">     [RaisesException] void setBackgroundShouldExtendBeyondPage(boolean hasExtendedBackground);
</span></span></pre>
</div>
</div>

</body>
</html>