<!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>[169309] 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/169309">169309</a></dd>
<dt>Author</dt> <dd>zalan@apple.com</dd>
<dt>Date</dt> <dd>2014-05-24 07:50:42 -0700 (Sat, 24 May 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Subpixel rendering: Non-compositing transforms with subpixel coordinates paint to wrong position.
https://bugs.webkit.org/show_bug.cgi?id=133184
<rdar://problem/16745606>
Reviewed by Simon Fraser.
Snapping relative negative coordinate values should produce the same position as if they were
positive absolute coordinates.
When a child box gets positioned off of its containers towards top/left, its relative coordinates
become negative. Pixel snapping those negative values should produce the same
final painting position as if the child box was fixed positioned with positive coordinates.
Since halfway values always round away from zero, negative and positive halfway values
produce opposite rounding direction.
This patch ensures that negative halfway values round to the direction as if they were positive.
Source/WebCore:
Test: fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.html
* platform/LayoutUnit.h:
(WebCore::roundToDevicePixel):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::paintLayerByApplyingTransform):
LayoutTests:
* fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction-expected.html: Added.
* fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.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="#trunkSourceWebCoreplatformLayoutUnith">trunk/Source/WebCore/platform/LayoutUnit.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderLayercpp">trunk/Source/WebCore/rendering/RenderLayer.cpp</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastlayershidpifloornegativecoordinatevaluestomaintainroundingdirectionexpectedhtml">trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastlayershidpifloornegativecoordinatevaluestomaintainroundingdirectionhtml">trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (169308 => 169309)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-05-24 11:49:40 UTC (rev 169308)
+++ trunk/LayoutTests/ChangeLog        2014-05-24 14:50:42 UTC (rev 169309)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2014-05-24 Zalan Bujtas <zalan@apple.com>
+
+ Subpixel rendering: Non-compositing transforms with subpixel coordinates paint to wrong position.
+ https://bugs.webkit.org/show_bug.cgi?id=133184
+ <rdar://problem/16745606>
+
+ Reviewed by Simon Fraser.
+
+ Snapping relative negative coordinate values should produce the same position as if they were
+ positive absolute coordinates.
+ When a child box gets positioned off of its containers towards top/left, its relative coordinates
+ become negative. Pixel snapping those negative values should produce the same
+ final painting position as if the child box was fixed positioned with positive coordinates.
+ Since halfway values always round away from zero, negative and positive halfway values
+ produce opposite rounding direction.
+ This patch ensures that negative halfway values round to the direction as if they were positive.
+
+ * fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction-expected.html: Added.
+ * fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.html: Added.
+
</ins><span class="cx"> 2014-05-24 Frédéric Wang <fred.wang@free.fr>
</span><span class="cx">
</span><span class="cx"> Update GTK references for some tests after bug 130322.
</span></span></pre></div>
<a id="trunkLayoutTestsfastlayershidpifloornegativecoordinatevaluestomaintainroundingdirectionexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction-expected.html (0 => 169309)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction-expected.html         (rev 0)
+++ trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction-expected.html        2014-05-24 14:50:42 UTC (rev 169309)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests if negative coordinate values round to the same position as if they were positive.</title>
+<style>
+ .inner {
+ position: relative;
+ top: 0px;
+ left: 0px;
+ width: 2px;
+ height: 2px;
+ border: solid black 0.5px;
+ }
+
+ .outer {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ }
+</style>
+</head>
+<body>
+<p id="container"></p>
+<script>
+ var container = document.getElementById("container");
+ for (i = 0; i < 40; ++i) {
+ adjustment = 0;
+ for (j = 0; j < 40; ++j) {
+ var outer = document.createElement("div");
+ outer.style.top = 7 * (i + j * adjustment) + "px";
+ outer.style.left = 7 * (j + i * adjustment) + "px";
+ outer.className = "outer";
+
+ var inner = document.createElement("div");
+ inner.style.top = (-adjustment) + "px";
+ inner.style.left = (-adjustment) + "px";
+ inner.className = "inner";
+ adjustment += 0.01;
+
+ outer.appendChild(inner);
+ container.appendChild(outer);
+ }
+ }
+</script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastlayershidpifloornegativecoordinatevaluestomaintainroundingdirectionhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.html (0 => 169309)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.html         (rev 0)
+++ trunk/LayoutTests/fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.html        2014-05-24 14:50:42 UTC (rev 169309)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests if negative coordinate values round to the same position as if they were positive.</title>
+<style>
+ .inner {
+ position: relative;
+ top: 0px;
+ left: 0px;
+ width: 2px;
+ height: 2px;
+ border: solid black 0.5px;
+ }
+
+ .outer {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ -webkit-transform: translateX(0px);
+ }
+</style>
+</head>
+<body>
+<p id="container"></p>
+<script>
+ var container = document.getElementById("container");
+ for (i = 0; i < 40; ++i) {
+ adjustment = 0;
+ for (j = 0; j < 40; ++j) {
+ var outer = document.createElement("div");
+ outer.style.top = 7 * (i + j * adjustment) + "px";
+ outer.style.left = 7 * (j + i * adjustment) + "px";
+ outer.className = "outer";
+
+ var inner = document.createElement("div");
+ inner.style.top = (-adjustment) + "px";
+ inner.style.left = (-adjustment) + "px";
+ inner.className = "inner";
+ adjustment += 0.01;
+
+ outer.appendChild(inner);
+ container.appendChild(outer);
+ }
+ }
+</script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (169308 => 169309)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-05-24 11:49:40 UTC (rev 169308)
+++ trunk/Source/WebCore/ChangeLog        2014-05-24 14:50:42 UTC (rev 169309)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2014-05-24 Zalan Bujtas <zalan@apple.com>
+
+ Subpixel rendering: Non-compositing transforms with subpixel coordinates paint to wrong position.
+ https://bugs.webkit.org/show_bug.cgi?id=133184
+ <rdar://problem/16745606>
+
+ Reviewed by Simon Fraser.
+
+ Snapping relative negative coordinate values should produce the same position as if they were
+ positive absolute coordinates.
+ When a child box gets positioned off of its containers towards top/left, its relative coordinates
+ become negative. Pixel snapping those negative values should produce the same
+ final painting position as if the child box was fixed positioned with positive coordinates.
+ Since halfway values always round away from zero, negative and positive halfway values
+ produce opposite rounding direction.
+ This patch ensures that negative halfway values round to the direction as if they were positive.
+
+ Test: fast/layers/hidpi-floor-negative-coordinate-values-to-maintain-rounding-direction.html
+
+ * platform/LayoutUnit.h:
+ (WebCore::roundToDevicePixel):
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::paintLayerByApplyingTransform):
+
</ins><span class="cx"> 2014-05-24 Frédéric Wang <fred.wang@free.fr>
</span><span class="cx">
</span><span class="cx"> Use size variants and glyph assembly from the MATH data.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformLayoutUnith"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/LayoutUnit.h (169308 => 169309)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/LayoutUnit.h        2014-05-24 11:49:40 UTC (rev 169308)
+++ trunk/Source/WebCore/platform/LayoutUnit.h        2014-05-24 14:50:42 UTC (rev 169309)
</span><span class="lines">@@ -935,9 +935,18 @@
</span><span class="cx"> return value.floor();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-inline float roundToDevicePixel(LayoutUnit value, float pixelSnappingFactor, bool needsDirectionalRounding = false)
</del><ins>+inline float roundToDevicePixel(LayoutUnit value, const float pixelSnappingFactor, bool needsDirectionalRounding = false)
</ins><span class="cx"> {
</span><del>- return roundf(((value.rawValue() - (needsDirectionalRounding ? LayoutUnit::epsilon() / 2.0f : 0)) * pixelSnappingFactor) / kEffectiveFixedPointDenominator) / pixelSnappingFactor;
</del><ins>+ auto roundInternal = [&] (float valueToRound) { return roundf((valueToRound * pixelSnappingFactor) / kEffectiveFixedPointDenominator) / pixelSnappingFactor; };
+
+ float adjustedValue = value.rawValue() - (needsDirectionalRounding ? LayoutUnit::epsilon() / 2.0f : 0);
+ if (adjustedValue >= 0)
+ return roundInternal(adjustedValue);
+
+ // This adjusts directional rounding on negative halfway values. It produces the same direction for both negative and positive values.
+ // It helps snapping relative negative coordinates to the same position as if they were positive absolute coordinates.
+ float translateOrigin = fabsf(adjustedValue - LayoutUnit::fromPixel(1));
+ return roundInternal(adjustedValue + (translateOrigin * kEffectiveFixedPointDenominator)) - translateOrigin;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> inline float floorToDevicePixel(LayoutUnit value, float pixelSnappingFactor)
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (169308 => 169309)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.cpp        2014-05-24 11:49:40 UTC (rev 169308)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp        2014-05-24 14:50:42 UTC (rev 169309)
</span><span class="lines">@@ -4135,13 +4135,13 @@
</span><span class="cx"> convertToLayerCoords(paintingInfo.rootLayer, offsetFromParent);
</span><span class="cx"> offsetFromParent.moveBy(translationOffset);
</span><span class="cx"> TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
</span><del>- FloatPoint devicePixelFlooredOffsetFromParent = flooredForPainting(offsetFromParent, deviceScaleFactor);
</del><ins>+ FloatPoint devicePixelSnappedOffsetFromParent = roundedForPainting(offsetFromParent, deviceScaleFactor);
</ins><span class="cx"> // Translate the graphics context to the snapping position to avoid off-device-pixel positing.
</span><del>- transform.translateRight(devicePixelFlooredOffsetFromParent.x(), devicePixelFlooredOffsetFromParent.y());
</del><ins>+ transform.translateRight(devicePixelSnappedOffsetFromParent.x(), devicePixelSnappedOffsetFromParent.y());
</ins><span class="cx"> // We handle accumulated subpixels through nested layers here. Since the context gets translated to device pixels,
</span><span class="cx"> // all we need to do is add the delta to the accumulated pixels coming from ancestor layers. With deep nesting of subpixel positioned
</span><span class="cx"> // boxes, this could grow to a relatively large number, but the translateRight() balances it.
</span><del>- FloatSize delta = offsetFromParent - devicePixelFlooredOffsetFromParent;
</del><ins>+ FloatSize delta = offsetFromParent - devicePixelSnappedOffsetFromParent;
</ins><span class="cx"> LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + LayoutSize(delta);
</span><span class="cx"> // Apply the transform.
</span><span class="cx"> GraphicsContextStateSaver stateSaver(*context);
</span></span></pre>
</div>
</div>
</body>
</html>