diff options
author | wangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-06 09:01:20 +0000 |
---|---|---|
committer | wangxianzhu@chromium.org <wangxianzhu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-06 09:01:20 +0000 |
commit | 657b24c95f9adf0b96d36a7824d9d0cd6a1b9ea6 (patch) | |
tree | 414df6bffc5528167e21a6ad52f5b4ab96bf3df9 /cc | |
parent | 6fe251999983d4f338c6a954dbab0c11270e389f (diff) | |
download | chromium_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.cc | 12 | ||||
-rw-r--r-- | cc/layer_tree_host_common_unittest.cc | 52 | ||||
-rw-r--r-- | cc/math_util.h | 5 |
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 |