<!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>[179335] 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/179335">179335</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-01-28 21:23:28 -0800 (Wed, 28 Jan 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Poor performance on IE's Chalkboard benchmark.
https://bugs.webkit.org/show_bug.cgi?id=140753.

Patch by Said Abou-Hallawa &lt;sabouhallawa@apple.com&gt; on 2015-01-28
Reviewed by Zalan Bujtas.

PerformanceTests:

* SVG/UnderTheSeeBenchmark.html: Added
* SVG/WorldcupBenchmark.html: Added.
* SVG/resources/RenderAnimator.css: Added.
* SVG/resources/RenderAnimator.js: Added.
These are benchmarks for the SVG rendering. Mainly we want to measure how fast
the SVG rendering will be when only a small part of it is drawn.

Source/WebCore:

Test: PerformanceTests/SVG/UnderTheSeeBenchmark.html
      PerformanceTests/SVG/WorldcupBenchmark.html

The SVG rendering code was not skipping the SVG elements which are outside the
clipping rectangle. We were drawing all the SVG elements even if some of them
are completely outside the clipping rectangle. The fix is to pass the correct
dirty rectangle to the ScrollView which then gets propagated to the SVG renderers.

* svg/graphics/SVGImage.cpp:
(WebCore::SVGImage::draw):
SVGImage::draw() needs to pass the intersection of 'srcRect' and context-&gt;clipBounds(),
to ScrollView::paint(). This will ensure RenderSVGShape::paint() gets the correct
clipping rectangle. If there is no intersection between the boundingBox of the
RenderSVGShape and the clipping rectangle, the RenderSVGShape will not be drawn.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoresvggraphicsSVGImagecpp">trunk/Source/WebCore/svg/graphics/SVGImage.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsSVGUnderTheSeeBenchmarkhtml">trunk/PerformanceTests/SVG/UnderTheSeeBenchmark.html</a></li>
<li><a href="#trunkPerformanceTestsSVGWorldcupBenchmarkhtml">trunk/PerformanceTests/SVG/WorldcupBenchmark.html</a></li>
<li><a href="#trunkPerformanceTestsSVGresourcesRenderAnimatorcss">trunk/PerformanceTests/SVG/resources/RenderAnimator.css</a></li>
<li><a href="#trunkPerformanceTestsSVGresourcesRenderAnimatorjs">trunk/PerformanceTests/SVG/resources/RenderAnimator.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (179334 => 179335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2015-01-29 04:45:39 UTC (rev 179334)
+++ trunk/PerformanceTests/ChangeLog        2015-01-29 05:23:28 UTC (rev 179335)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2015-01-28  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        Poor performance on IE's Chalkboard benchmark.
+        https://bugs.webkit.org/show_bug.cgi?id=140753.
+
+        Reviewed by Zalan Bujtas.
+
+        * SVG/UnderTheSeeBenchmark.html: Added
+        * SVG/WorldcupBenchmark.html: Added.
+        * SVG/resources/RenderAnimator.css: Added.
+        * SVG/resources/RenderAnimator.js: Added.
+        These are benchmarks for the SVG rendering. Mainly we want to measure how fast
+        the SVG rendering will be when only a small part of it is drawn.
+        
</ins><span class="cx"> 2015-01-21  Geoffrey Garen  &lt;ggaren@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         bmalloc: support aligned allocation
</span></span></pre></div>
<a id="trunkPerformanceTestsSVGUnderTheSeeBenchmarkhtml"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/SVG/UnderTheSeeBenchmark.html (0 => 179335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/SVG/UnderTheSeeBenchmark.html                                (rev 0)
+++ trunk/PerformanceTests/SVG/UnderTheSeeBenchmark.html        2015-01-29 05:23:28 UTC (rev 179335)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+  &lt;head&gt;
+    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;resources/RenderAnimator.css&quot;&gt;
+    &lt;script src=&quot;../resources/runner.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;resources/RenderAnimator.js&quot;&gt;&lt;/script&gt;
+  &lt;/head&gt;
+  &lt;body&gt;
+    &lt;img class=&quot;Benchmark&quot; src=&quot;resources/UnderTheSee.svg&quot; style=&quot;visibility: hidden;&quot;&gt;
+  &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkPerformanceTestsSVGWorldcupBenchmarkhtml"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/SVG/WorldcupBenchmark.html (0 => 179335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/SVG/WorldcupBenchmark.html                                (rev 0)
+++ trunk/PerformanceTests/SVG/WorldcupBenchmark.html        2015-01-29 05:23:28 UTC (rev 179335)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+  &lt;head&gt;
+    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;resources/RenderAnimator.css&quot;&gt;
+    &lt;script src=&quot;../resources/runner.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;resources/RenderAnimator.js&quot;&gt;&lt;/script&gt;
+  &lt;/head&gt;
+  &lt;body&gt;
+    &lt;img class=&quot;Benchmark&quot; src=&quot;resources/Worldcup.svg&quot; style=&quot;visibility: hidden;&quot;&gt;
+  &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkPerformanceTestsSVGresourcesRenderAnimatorcss"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/SVG/resources/RenderAnimator.css (0 => 179335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/SVG/resources/RenderAnimator.css                                (rev 0)
+++ trunk/PerformanceTests/SVG/resources/RenderAnimator.css        2015-01-29 05:23:28 UTC (rev 179335)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+.Benchmark {
+    position: fixed;
+    visibility: hidden;
+    transition: opacity 1.2s;
+}
+
+.Timer {
+    position: absolute;
+    right: 0px;
+    bottom: 0px;
+    margin: 0px 40px 14px 0px;
+    font-family: Garamond;
+    font-size: 18pt;
+    transition: opacity 1.2s;
+}
</ins></span></pre></div>
<a id="trunkPerformanceTestsSVGresourcesRenderAnimatorjs"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/SVG/resources/RenderAnimator.js (0 => 179335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/SVG/resources/RenderAnimator.js                                (rev 0)
+++ trunk/PerformanceTests/SVG/resources/RenderAnimator.js        2015-01-29 05:23:28 UTC (rev 179335)
</span><span class="lines">@@ -0,0 +1,233 @@
</span><ins>+//
+// To use this script, the HTML has to have only one element and this element's className
+// should be equal to &quot;Benchmark&quot;.
+//
+// This script forces rendering the HTML element many times by changing its position and its
+// size. The size can be very big to test the case of displaying only a small portion of the
+// element and measure how fast the display will be in this case.
+//
+
+function Point(x, y) {
+    this.x = x;
+    this.y = y;
+}
+
+Point.prototype = {
+    scale : function(other) {
+        return new Point(this.x * other.x, this.y * other.y);
+    },
+    add : function(other) {
+        return new Point(this.x + other.x, this.y + other.y);
+    },
+    subtract : function(other) {
+        return new Point(this.x - other.x, this.y - other.y);
+    },
+    isAlmostEqual : function(other, threshold) {
+        return Math.abs(this.x - other.x) &lt; threshold &amp;&amp;  Math.abs(this.y - other.y) &lt; threshold;
+    }
+}
+
+function Rectangle(position, size) {
+    this.position = position;
+    this.size = size;
+}
+
+Rectangle.prototype = {
+    left : function() {
+        return this.position.x;
+    },
+    top : function() {
+        return this.position.y;
+    },
+    width : function() {
+        return this.size.x;
+    },
+    height : function() {
+        return this.size.y;
+    },
+    isAlmostEqual : function(other, threshold) {
+        return this.position.isAlmostEqual(other.position, threshold) &amp;&amp; this.size.isAlmostEqual(other.size, threshold);
+    }
+}
+
+function ElapsedTime() {
+    this._startTime = PerfTestRunner.now();
+    this._stopTime = this._startTime;
+}
+
+ElapsedTime.prototype = {
+    
+    start : function() {
+        this._startTime = this._stopTime = PerfTestRunner.now();
+    },
+
+    stop : function() {
+        this._stopTime = PerfTestRunner.now();
+    },
+
+    isActive : function() {
+        return this._startTime == this._stopTime;
+    },
+
+    elapsed : function() {
+        return (this.isActive() ? PerfTestRunner.now() : this._stopTime) - this._startTime;
+    },
+
+    elapsedString : function() {
+        var tenths = this.elapsed() / 1000;
+        return tenths.toFixed(2) + &quot; Seconds&quot;;
+    }
+}
+
+function AnimateMove(offset, zoomFactor, animateFactor) {
+    this.offset = offset;
+    this.zoomFactor = zoomFactor;
+    this.animateFactor = animateFactor;
+}
+
+AnimateMove.centerFactor = new Point(0.5, 0.5);
+
+AnimateMove.prototype = {
+    
+    targetRect : function(windowSize, sourceSize) {
+        var offset = this.offset.scale(this.zoomFactor);
+        var size = sourceSize.scale(this.zoomFactor);
+        var position = windowSize.subtract(size).scale(AnimateMove.centerFactor).subtract(offset);
+        return new Rectangle(position, size);
+    },
+
+    nextAnimateRect : function(targetRect, animateRect) {
+        var deltaPosition = targetRect.position.subtract(animateRect.position).scale(this.animateFactor);
+        var deltaSize = targetRect.size.subtract(animateRect.size).scale(this.animateFactor);
+        return new Rectangle(animateRect.position.add(deltaPosition), animateRect.size.add(deltaSize));
+    }
+}
+
+function ElementAnimator(element, windowSize, sourceSize) {
+    this._element = element;
+    this._windowSize = windowSize;
+    this._sourceSize = sourceSize;
+
+    this._animateMoves = [
+        new AnimateMove(new Point(   0,    0), new Point( 0.7,  0.7), new Point(1.00, 1.00)),
+        new AnimateMove(new Point(-500, -300), new Point(12.0, 12.0), new Point(0.50, 0.50)),
+        new AnimateMove(new Point( 100, -200), new Point( 0.1,  0.1), new Point(0.50, 0.50)),
+        new AnimateMove(new Point(-100, -300), new Point( 5.0,  5.0), new Point(0.20, 0.20)),
+        new AnimateMove(new Point(   0,    0), new Point( 0.7,  0.7), new Point(0.50, 0.50))
+    ];
+
+    this._animateMoveIndex = 0;
+    this.nextTargetRect();
+    this._animateRect = this._targetRect;
+    this.moveToAnimateRect();
+}
+
+ElementAnimator.prototype = {
+    
+    nextTargetRect : function() {
+        if (this._animateMoveIndex &gt;= this._animateMoves.length)
+            return false;
+
+        this._targetRect = this._animateMoves[this._animateMoveIndex++].targetRect(this._windowSize, this._sourceSize);
+        return true;
+    },
+    
+    nextAnimateRect : function() {
+        if (this._animateRect.isAlmostEqual(this._targetRect, 0.1))
+            return false;
+
+        this._animateRect = this._animateMoves[this._animateMoveIndex - 1].nextAnimateRect(this._targetRect, this._animateRect);
+        return true;
+    },
+    
+    moveToAnimateRect : function() {
+        this._element.style.width = this._animateRect.width() + &quot;px&quot;;
+        this._element.style.left = this._animateRect.left() + &quot;px&quot;;
+        this._element.style.top = this._animateRect.top() + &quot;px&quot;;
+    }
+}
+
+function RenderAnimator() {
+    this.element = document.getElementsByClassName(&quot;Benchmark&quot;)[0];
+    this.sourceSize = new Point(this.element.width, this.element.height);
+    
+    // Tiling causes the rendering to slow down when the window width &gt; 2000
+    this.windowSize = new Point(3000, 1500);
+    
+    this.timer = document.createElement(&quot;span&quot;);
+    this.timer.className = &quot;Timer&quot;;
+    document.body.appendChild(this.timer);
+    
+    this.timeoutDelay = window.testRunner ? 0 : 500;
+    this.elapsedTime = new ElapsedTime();
+    this.elementAnimator = null;
+}
+
+RenderAnimator.prototype = {    
+
+    nextRun : function() {
+        this.showElements(true);
+        this.elementAnimator = new ElementAnimator(this.element, this.windowSize, this.sourceSize);
+        
+        var self = this;
+        setTimeout(function () {
+            self.elapsedTime.start();
+            self.moveToNextTargetRect();
+        }, this.timeoutDelay);
+    },
+
+    moveToNextTargetRect : function() {
+        if (this.elementAnimator.nextTargetRect())
+            setTimeout(this.moveToNextAnimateRect.bind(this), 0);
+        else {
+            this.elapsedTime.stop();
+            setTimeout(this.finishRun.bind(this), this.timeoutDelay);
+        }
+    },
+    
+    moveToNextAnimateRect : function() {
+        this.timer.innerHTML = this.elapsedTime.elapsedString();
+        
+        if (this.elementAnimator.nextAnimateRect())
+            window.requestAnimationFrame(this.moveToNextAnimateRect.bind(this));
+        else
+            this.moveToNextTargetRect();
+
+        this.elementAnimator.moveToAnimateRect();
+    },
+    
+    finishRun : function() {
+        this.showElements(false);
+        
+        var finishedTest = !PerfTestRunner.measureValueAsync(this.elapsedTime.elapsed());
+        PerfTestRunner.gc();
+        
+        if (!finishedTest)
+            setTimeout(this.nextRun.bind(this), this.timeoutDelay * 2);
+    },
+
+    showElements : function(show) {
+        this.element.style.visibility = &quot;visible&quot;;
+        this.element.style.opacity = show ? 1 : 0;
+        this.timer.style.opacity = show ? 1 : 0;
+    },
+    
+    removeElements : function() {
+        this.element.parentNode.removeChild(this.element);
+        this.timer.parentNode.removeChild(this.timer);
+        this.element = null;
+        this.timer = null;
+    }
+}
+
+window.addEventListener(&quot;load&quot;, function() {
+    window.renderAnimator = new RenderAnimator();
+    window.renderAnimator.nextRun();
+});
+
+PerfTestRunner.prepareToMeasureValuesAsync({
+    unit: 'ms',
+    done: function () {
+        window.renderAnimator.removeElements();
+    }
+});
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (179334 => 179335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-01-29 04:45:39 UTC (rev 179334)
+++ trunk/Source/WebCore/ChangeLog        2015-01-29 05:23:28 UTC (rev 179335)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2015-01-28  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
+
+        Poor performance on IE's Chalkboard benchmark.
+        https://bugs.webkit.org/show_bug.cgi?id=140753.
+
+        Reviewed by Zalan Bujtas.
+
+        Test: PerformanceTests/SVG/UnderTheSeeBenchmark.html
+              PerformanceTests/SVG/WorldcupBenchmark.html
+              
+        The SVG rendering code was not skipping the SVG elements which are outside the
+        clipping rectangle. We were drawing all the SVG elements even if some of them
+        are completely outside the clipping rectangle. The fix is to pass the correct
+        dirty rectangle to the ScrollView which then gets propagated to the SVG renderers.
+
+        * svg/graphics/SVGImage.cpp:
+        (WebCore::SVGImage::draw):
+        SVGImage::draw() needs to pass the intersection of 'srcRect' and context-&gt;clipBounds(),
+        to ScrollView::paint(). This will ensure RenderSVGShape::paint() gets the correct
+        clipping rectangle. If there is no intersection between the boundingBox of the
+        RenderSVGShape and the clipping rectangle, the RenderSVGShape will not be drawn.
+
</ins><span class="cx"> 2015-01-28  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Scroll snap points do not work in the vertical direction
</span></span></pre></div>
<a id="trunkSourceWebCoresvggraphicsSVGImagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/graphics/SVGImage.cpp (179334 => 179335)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/graphics/SVGImage.cpp        2015-01-29 04:45:39 UTC (rev 179334)
+++ trunk/Source/WebCore/svg/graphics/SVGImage.cpp        2015-01-29 05:23:28 UTC (rev 179335)
</span><span class="lines">@@ -249,7 +249,7 @@
</span><span class="cx">     if (view-&gt;needsLayout())
</span><span class="cx">         view-&gt;layout();
</span><span class="cx"> 
</span><del>-    view-&gt;paint(context, enclosingIntRect(srcRect));
</del><ins>+    view-&gt;paint(context, intersection(context-&gt;clipBounds(), enclosingIntRect(srcRect)));
</ins><span class="cx"> 
</span><span class="cx">     if (compositingRequiresTransparencyLayer)
</span><span class="cx">         context-&gt;endTransparencyLayer();
</span></span></pre>
</div>
</div>

</body>
</html>