summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorwangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-06 09:01:20 +0000
committerwangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-06 09:01:20 +0000
commit657b24c95f9adf0b96d36a7824d9d0cd6a1b9ea6 (patch)
tree414df6bffc5528167e21a6ad52f5b4ab96bf3df9 /cc
parent6fe251999983d4f338c6a954dbab0c11270e389f (diff)
downloadchromium_src-657b24c95f9adf0b96d36a7824d9d0cd6a1b9ea6.zip
chromium_src-657b24c95f9adf0b96d36a7824d9d0cd6a1b9ea6.tar.gz
chromium_src-657b24c95f9adf0b96d36a7824d9d0cd6a1b9ea6.tar.bz2
Align physical pixels of scrolled layers
Non-integral position of scrolled layers causes blurry content. If a layer has simple transform and the translations in the transform are merely caused by scroll offsets, round the translations to align the pixels. BUG=174699 Review URL: https://chromiumcodereview.appspot.com/12407002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@186377 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r--cc/layer_tree_host_common.cc12
-rw-r--r--cc/layer_tree_host_common_unittest.cc52
-rw-r--r--cc/math_util.h5
3 files changed, 69 insertions, 0 deletions
diff --git a/cc/layer_tree_host_common.cc b/cc/layer_tree_host_common.cc
index 3d06aa4..c28db40 100644
--- a/cc/layer_tree_host_common.cc
+++ b/cc/layer_tree_host_common.cc
@@ -540,6 +540,12 @@ static void preCalculateMetaInformation(LayerType* layer)
layer->drawProperties().descendants_can_clip_selves = descendantsCanClipSelves;
}
+static void roundTranslationComponents(gfx::Transform* transform)
+{
+ transform->matrix().setDouble(0, 3, MathUtil::Round(transform->matrix().getDouble(0, 3)));
+ transform->matrix().setDouble(1, 3, MathUtil::Round(transform->matrix().getDouble(1, 3)));
+}
+
// Recursively walks the layer tree starting at the given node and computes all the
// necessary transformations, clipRects, render surfaces, etc.
template<typename LayerType, typename LayerList, typename RenderSurfaceType>
@@ -694,6 +700,12 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
// Note carefully: this is Concat, not Preconcat (implTransform * combinedTransform).
combinedTransform.ConcatTransform(layer->implTransform());
+ if (!animatingTransformToTarget && layer->scrollable() && combinedTransform.IsScaleOrTranslation()) {
+ // Align the scrollable layer's position to screen space pixels to avoid blurriness.
+ // To avoid side-effects, do this only if the transform is simple.
+ roundTranslationComponents(&combinedTransform);
+ }
+
if (layer->fixedToContainerLayer()) {
// Special case: this layer is a composited fixed-position layer; we need to
// explicitly compensate for all ancestors' nonzero scrollDeltas to keep this layer
diff --git a/cc/layer_tree_host_common_unittest.cc b/cc/layer_tree_host_common_unittest.cc
index 655bbaf..926ae2b 100644
--- a/cc/layer_tree_host_common_unittest.cc
+++ b/cc/layer_tree_host_common_unittest.cc
@@ -258,6 +258,58 @@ TEST(LayerTreeHostCommonTest, verifyTransformsForSingleLayer)
EXPECT_TRANSFORMATION_MATRIX_EQ(expectedResult, layer->screenSpaceTransform());
}
+TEST(LayerTreeHostCommonTest, verifyTransformsAboutScrollOffset)
+{
+ const gfx::Vector2d kScrollOffset(50, 100);
+ const gfx::Vector2dF kScrollDelta(2.34f, 5.67f);
+ const gfx::PointF kScrollLayerPosition(-kScrollOffset.x(), -kScrollOffset.y());
+ const float kPageScale = 0.888f;
+ const float kDeviceScale = 1.666f;
+
+ FakeImplProxy proxy;
+ FakeLayerTreeHostImpl hostImpl(&proxy);
+
+ gfx::Transform identityMatrix;
+ scoped_ptr<LayerImpl> sublayerScopedPtr(LayerImpl::create(hostImpl.activeTree(), 1));
+ LayerImpl* sublayer = sublayerScopedPtr.get();
+ sublayer->setContentsScale(kPageScale * kDeviceScale, kPageScale * kDeviceScale);
+ setLayerPropertiesForTesting(sublayer, identityMatrix, identityMatrix, gfx::Point(0, 0), gfx::PointF(0, 0), gfx::Size(500, 500), false);
+
+ scoped_ptr<LayerImpl> scrollLayerScopedPtr(LayerImpl::create(hostImpl.activeTree(), 2));
+ LayerImpl* scrollLayer = scrollLayerScopedPtr.get();
+ setLayerPropertiesForTesting(scrollLayer, identityMatrix, identityMatrix, gfx::PointF(0, 0), kScrollLayerPosition, gfx::Size(10, 20), false);
+ scrollLayer->setScrollable(true);
+ scrollLayer->setScrollOffset(kScrollOffset);
+ scrollLayer->setScrollDelta(kScrollDelta);
+ gfx::Transform implTransform;
+ implTransform.Scale(kPageScale, kPageScale);
+ scrollLayer->setImplTransform(implTransform);
+ scrollLayer->addChild(sublayerScopedPtr.Pass());
+
+ scoped_ptr<LayerImpl> root(LayerImpl::create(hostImpl.activeTree(), 3));
+ setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, gfx::PointF(0, 0), gfx::PointF(0, 0), gfx::Size(3, 4), false);
+ root->addChild(scrollLayerScopedPtr.Pass());
+
+ executeCalculateDrawProperties(root.get(), kDeviceScale, kPageScale);
+ gfx::Transform expectedTransform = identityMatrix;
+ gfx::PointF subLayerScreenPosition = kScrollLayerPosition - kScrollDelta;
+ subLayerScreenPosition.Scale(kPageScale * kDeviceScale);
+ expectedTransform.Translate(MathUtil::Round(subLayerScreenPosition.x()), MathUtil::Round(subLayerScreenPosition.y()));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedTransform, sublayer->drawTransform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedTransform, sublayer->screenSpaceTransform());
+
+ gfx::Transform arbitraryTranslate;
+ const float kTranslateX = 10.6f;
+ const float kTranslateY = 20.6f;
+ arbitraryTranslate.Translate(kTranslateX, kTranslateY);
+ setLayerPropertiesForTesting(scrollLayer, arbitraryTranslate, identityMatrix, gfx::PointF(0, 0), kScrollLayerPosition, gfx::Size(10, 20), false);
+ executeCalculateDrawProperties(root.get(), kDeviceScale, kPageScale);
+ expectedTransform.MakeIdentity();
+ expectedTransform.Translate(MathUtil::Round(kTranslateX * kPageScale * kDeviceScale + subLayerScreenPosition.x()),
+ MathUtil::Round(kTranslateY * kPageScale * kDeviceScale + subLayerScreenPosition.y()));
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expectedTransform, sublayer->drawTransform());
+}
+
TEST(LayerTreeHostCommonTest, verifyTransformsForSimpleHierarchy)
{
gfx::Transform identityMatrix;
diff --git a/cc/math_util.h b/cc/math_util.h
index 8c1ca88..24a155d 100644
--- a/cc/math_util.h
+++ b/cc/math_util.h
@@ -5,6 +5,8 @@
#ifndef CC_MATH_UTIL_H_
#define CC_MATH_UTIL_H_
+#include <cmath>
+
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "cc/cc_export.h"
@@ -81,6 +83,9 @@ public:
static float Deg2Rad(float deg) { return deg * PI_FLOAT / 180; }
static float Rad2Deg(float rad) { return rad * 180 / PI_FLOAT; }
+ static float Round(float f) { return (f > 0.f) ? std::floor(f + 0.5f) : std::ceil(f - 0.5f); }
+ static double Round(double d) { return (d > 0.0) ? std::floor(d + 0.5) : std::ceil(d - 0.5); }
+
// Background: Existing transform code does not do the right thing in
// mapRect / mapQuad / projectQuad when there is a perspective projection that causes
// one of the transformed vertices to go to w < 0. In those cases, it is necessary to