diff options
29 files changed, 474 insertions, 189 deletions
@@ -24,6 +24,8 @@ 'checkerboard_draw_quad.cc', 'checkerboard_draw_quad.h', 'completion_event.h', + 'contents_scaling_layer.cc', + 'contents_scaling_layer.h', 'damage_tracker.cc', 'damage_tracker.h', 'debug_border_draw_quad.cc', diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 26fb00a..963f841 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -8,6 +8,7 @@ 'cc_tests_source_files': [ 'hash_pair_unittest.cc', 'active_animation_unittest.cc', + 'contents_scaling_layer_unittest.cc', 'damage_tracker_unittest.cc', 'delay_based_time_source_unittest.cc', 'draw_quad_unittest.cc', diff --git a/cc/contents_scaling_layer.cc b/cc/contents_scaling_layer.cc new file mode 100644 index 0000000..2e041a1 --- /dev/null +++ b/cc/contents_scaling_layer.cc @@ -0,0 +1,38 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" + +#include "cc/contents_scaling_layer.h" + +namespace cc { + +ContentsScalingLayer::ContentsScalingLayer() + : m_contentsScale(1.0) { +} + +ContentsScalingLayer::~ContentsScalingLayer() { +} + +IntSize ContentsScalingLayer::contentBounds() const { + return IntSize(ceil(bounds().width() * contentsScaleX()), + ceil(bounds().height() * contentsScaleY())); +} + +float ContentsScalingLayer::contentsScaleX() const { + return m_contentsScale; +} + +float ContentsScalingLayer::contentsScaleY() const { + return m_contentsScale; +} + +void ContentsScalingLayer::setContentsScale(float contentsScale) { + if (m_contentsScale == contentsScale) + return; + m_contentsScale = contentsScale; + setNeedsDisplay(); +} + +} // namespace cc diff --git a/cc/contents_scaling_layer.h b/cc/contents_scaling_layer.h new file mode 100644 index 0000000..94e83a9 --- /dev/null +++ b/cc/contents_scaling_layer.h @@ -0,0 +1,31 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_CONTENTS_SCALING_LAYER_H +#define CC_CONTENTS_SCALING_LAYER_H + +#include "cc/layer.h" + +namespace cc { + +// Base class for layers that need contents scale. +// The content bounds are determined by bounds and scale of the contents. +class ContentsScalingLayer : public Layer { + public: + virtual IntSize contentBounds() const OVERRIDE; + virtual float contentsScaleX() const OVERRIDE; + virtual float contentsScaleY() const OVERRIDE; + virtual void setContentsScale(float contentsScale) OVERRIDE; + + protected: + ContentsScalingLayer(); + virtual ~ContentsScalingLayer(); + + private: + float m_contentsScale; +}; + +} // namespace cc + +#endif // CC_CONTENTS_SCALING_LAYER_H diff --git a/cc/contents_scaling_layer_unittest.cc b/cc/contents_scaling_layer_unittest.cc new file mode 100644 index 0000000..4c79a90 --- /dev/null +++ b/cc/contents_scaling_layer_unittest.cc @@ -0,0 +1,76 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" + +#include "cc/contents_scaling_layer.h" + +#include "cc/test/geometry_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +using namespace cc; + +class MockContentsScalingLayer : public ContentsScalingLayer { + public: + MockContentsScalingLayer() + : ContentsScalingLayer() { + } + + virtual void setNeedsDisplayRect(const FloatRect& dirtyRect) OVERRIDE { + m_lastNeedsDisplayRect = dirtyRect; + ContentsScalingLayer::setNeedsDisplayRect(dirtyRect); + } + + void resetNeedsDisplay() { + m_needsDisplay = false; + } + + const FloatRect& lastNeedsDisplayRect() const { + return m_lastNeedsDisplayRect; + } + + private: + virtual ~MockContentsScalingLayer() { + } + + FloatRect m_lastNeedsDisplayRect; +}; + +TEST(ContentsScalingLayerTest, checkContentsBounds) { + scoped_refptr<MockContentsScalingLayer> testLayer = + make_scoped_refptr(new MockContentsScalingLayer()); + + testLayer->setBounds(IntSize(320, 240)); + EXPECT_FLOAT_EQ(1.0, testLayer->contentsScaleX()); + EXPECT_FLOAT_EQ(1.0, testLayer->contentsScaleY()); + EXPECT_EQ(320, testLayer->contentBounds().width()); + EXPECT_EQ(240, testLayer->contentBounds().height()); + + testLayer->setContentsScale(2.0f); + EXPECT_EQ(640, testLayer->contentBounds().width()); + EXPECT_EQ(480, testLayer->contentBounds().height()); + + testLayer->setBounds(IntSize(10, 20)); + EXPECT_EQ(20, testLayer->contentBounds().width()); + EXPECT_EQ(40, testLayer->contentBounds().height()); + + testLayer->setContentsScale(1.33f); + EXPECT_EQ(14, testLayer->contentBounds().width()); + EXPECT_EQ(27, testLayer->contentBounds().height()); +} + +TEST(ContentsScalingLayerTest, checkContentsScaleChangeTriggersNeedsDisplay) { + scoped_refptr<MockContentsScalingLayer> testLayer = + make_scoped_refptr(new MockContentsScalingLayer()); + + testLayer->setBounds(IntSize(320, 240)); + + testLayer->resetNeedsDisplay(); + EXPECT_FALSE(testLayer->needsDisplay()); + + testLayer->setContentsScale(testLayer->contentsScaleX() + 1.f); + EXPECT_TRUE(testLayer->needsDisplay()); + EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 320, 240), + testLayer->lastNeedsDisplayRect()); +} diff --git a/cc/damage_tracker.cc b/cc/damage_tracker.cc index 4c27d4d..400fe5f 100644 --- a/cc/damage_tracker.cc +++ b/cc/damage_tracker.cc @@ -265,13 +265,9 @@ void DamageTracker::extendDamageForLayer(LayerImpl* layer, FloatRect& targetDama // Note oldRectInTargetSpace is already in target space. targetDamageRect.uniteIfNonZero(oldRectInTargetSpace); } else if (!layer->updateRect().isEmpty()) { - // If the layer properties havent changed, then the the target surface is only + // If the layer properties haven't changed, then the the target surface is only // affected by the layer's update area, which could be empty. - FloatRect updateContentRect = layer->updateRect(); - float widthScale = layer->contentBounds().width() / static_cast<float>(layer->bounds().width()); - float heightScale = layer->contentBounds().height() / static_cast<float>(layer->bounds().height()); - updateContentRect.scale(widthScale, heightScale); - + FloatRect updateContentRect = layer->layerRectToContentRect(layer->updateRect()); FloatRect updateRectInTargetSpace = MathUtil::mapClippedRect(layer->drawTransform(), updateContentRect); targetDamageRect.uniteIfNonZero(updateRectInTargetSpace); } diff --git a/cc/image_layer.cc b/cc/image_layer.cc index e162007..3c1712e 100644 --- a/cc/image_layer.cc +++ b/cc/image_layer.cc @@ -150,10 +150,18 @@ bool ImageLayer::drawsContent() const return !m_bitmap.isNull() && TiledLayer::drawsContent(); } -bool ImageLayer::needsContentsScale() const +float ImageLayer::contentsScaleX() const { - // Contents scale is not need for image layer because this can be done in compositor more efficiently. - return false; + if (bounds().isEmpty() || contentBounds().isEmpty()) + return 1; + return static_cast<float>(m_bitmap.width()) / bounds().width(); +} + +float ImageLayer::contentsScaleY() const +{ + if (bounds().isEmpty() || contentBounds().isEmpty()) + return 1; + return static_cast<float>(m_bitmap.height()) / bounds().height(); } } diff --git a/cc/image_layer.h b/cc/image_layer.h index fcb3adb..6f25a21 100644 --- a/cc/image_layer.h +++ b/cc/image_layer.h @@ -20,7 +20,8 @@ public: virtual bool drawsContent() const OVERRIDE; virtual void setTexturePriorities(const PriorityCalculator&) OVERRIDE; virtual void update(ResourceUpdateQueue&, const OcclusionTracker*, RenderingStats&) OVERRIDE; - virtual bool needsContentsScale() const OVERRIDE; + virtual float contentsScaleX() const OVERRIDE; + virtual float contentsScaleY() const OVERRIDE; void setBitmap(const SkBitmap& image); diff --git a/cc/layer.cc b/cc/layer.cc index 4c39126..b36589d 100644 --- a/cc/layer.cc +++ b/cc/layer.cc @@ -64,7 +64,6 @@ Layer::Layer() , m_renderTarget(0) , m_drawTransformIsAnimating(false) , m_screenSpaceTransformIsAnimating(false) - , m_contentsScale(1.0) , m_rasterScale(1.0) , m_automaticallyComputeRasterScale(false) , m_boundsContainPageScale(false) @@ -120,13 +119,15 @@ void Layer::setNeedsCommit() m_layerTreeHost->setNeedsCommit(); } -IntRect Layer::layerRectToContentRect(const WebKit::WebRect& layerRect) +IntRect Layer::layerRectToContentRect(const FloatRect& layerRect) const { - float widthScale = static_cast<float>(contentBounds().width()) / bounds().width(); - float heightScale = static_cast<float>(contentBounds().height()) / bounds().height(); - FloatRect contentRect(layerRect.x, layerRect.y, layerRect.width, layerRect.height); - contentRect.scale(widthScale, heightScale); - return enclosingIntRect(contentRect); + FloatRect contentRect(layerRect); + contentRect.scale(contentsScaleX(), contentsScaleY()); + IntRect intContentRect = enclosingIntRect(contentRect); + // Intersect with content rect to avoid the extra pixel because for some + // values x and y, ceil((x / y) * y) may be x + 1. + intContentRect.intersect(IntRect(IntPoint(), contentBounds())); + return intContentRect; } void Layer::setParent(Layer* layer) @@ -557,6 +558,7 @@ void Layer::pushPropertiesTo(LayerImpl* layer) layer->setBackgroundColor(m_backgroundColor); layer->setBounds(m_bounds); layer->setContentBounds(contentBounds()); + layer->setContentsScale(contentsScaleX(), contentsScaleY()); layer->setDebugBorderColor(m_debugBorderColor); layer->setDebugBorderWidth(m_debugBorderWidth); layer->setDebugName(m_debugName); @@ -630,11 +632,6 @@ bool Layer::needMoreUpdates() return false; } -bool Layer::needsContentsScale() const -{ - return false; -} - void Layer::setDebugBorderColor(SkColor color) { m_debugBorderColor = color; @@ -653,13 +650,14 @@ void Layer::setDebugName(const std::string& debugName) setNeedsCommit(); } -void Layer::setContentsScale(float contentsScale) +float Layer::contentsScaleX() const { - if (!needsContentsScale() || m_contentsScale == contentsScale) - return; - m_contentsScale = contentsScale; + return 1.0; +} - setNeedsDisplay(); +float Layer::contentsScaleY() const +{ + return 1.0; } void Layer::setRasterScale(float scale) @@ -189,7 +189,6 @@ public: virtual bool needMoreUpdates(); virtual void setIsMask(bool) { } virtual void bindContentsTexture() { } - virtual bool needsContentsScale() const; void setDebugBorderColor(SkColor); void setDebugBorderWidth(float); @@ -229,8 +228,10 @@ public: // The contentsScale converts from logical, non-page-scaled pixels to target pixels. // The contentsScale is 1 for the root layer as it is already in physical pixels. - float contentsScale() const { return m_contentsScale; } - void setContentsScale(float); + // By default contentsScale is forced to be 1 except for subclasses of ContentsScalingLayer. + virtual float contentsScaleX() const; + virtual float contentsScaleY() const; + virtual void setContentsScale(float contentsScale) { } // The scale at which contents should be rastered, to match the scale at // which they will drawn to the screen. This scale is a component of the @@ -280,6 +281,8 @@ public: virtual ScrollbarLayer* toScrollbarLayer(); + IntRect layerRectToContentRect(const FloatRect& layerRect) const; + protected: friend class LayerImpl; friend class TreeSynchronizer; @@ -289,8 +292,6 @@ protected: void setNeedsCommit(); - IntRect layerRectToContentRect(const WebKit::WebRect& layerRect); - // This flag is set when layer need repainting/updating. bool m_needsDisplay; @@ -390,7 +391,6 @@ private: // Uses target surface space. IntRect m_drawableContentRect; - float m_contentsScale; float m_rasterScale; bool m_automaticallyComputeRasterScale; bool m_boundsContainPageScale; diff --git a/cc/layer_impl.cc b/cc/layer_impl.cc index 3de9483..197e619 100644 --- a/cc/layer_impl.cc +++ b/cc/layer_impl.cc @@ -29,6 +29,8 @@ LayerImpl::LayerImpl(int id) , m_layerTreeHostImpl(0) , m_anchorPoint(0.5, 0.5) , m_anchorPointZ(0) + , m_contentsScaleX(1.0) + , m_contentsScaleY(1.0) , m_scrollable(false) , m_shouldScrollOnMainThread(false) , m_haveWheelEventHandlers(false) @@ -233,13 +235,15 @@ bool LayerImpl::drawCheckerboardForMissingTiles() const return m_drawCheckerboardForMissingTiles && !Settings::backgroundColorInsteadOfCheckerboard(); } -IntRect LayerImpl::layerRectToContentRect(const WebKit::WebRect& layerRect) +IntRect LayerImpl::layerRectToContentRect(const FloatRect& layerRect) const { - float widthScale = static_cast<float>(contentBounds().width()) / bounds().width(); - float heightScale = static_cast<float>(contentBounds().height()) / bounds().height(); - FloatRect contentRect(layerRect.x, layerRect.y, layerRect.width, layerRect.height); - contentRect.scale(widthScale, heightScale); - return enclosingIntRect(contentRect); + FloatRect contentRect(layerRect); + contentRect.scale(contentsScaleX(), contentsScaleY()); + IntRect intContentRect = enclosingIntRect(contentRect); + // Intersect with content rect to avoid the extra pixel because for some + // values x and y, ceil((x / y) * y) may be x + 1. + intContentRect.intersect(IntRect(IntPoint(), contentBounds())); + return intContentRect; } std::string LayerImpl::indentString(int indent) @@ -609,6 +613,16 @@ void LayerImpl::setContentBounds(const IntSize& contentBounds) m_layerPropertyChanged = true; } +void LayerImpl::setContentsScale(float contentsScaleX, float contentsScaleY) +{ + if (m_contentsScaleX == contentsScaleX && m_contentsScaleY == contentsScaleY) + return; + + m_contentsScaleX = contentsScaleX; + m_contentsScaleY = contentsScaleY; + m_layerPropertyChanged = true; +} + void LayerImpl::setScrollPosition(const IntPoint& scrollPosition) { if (m_scrollPosition == scrollPosition) diff --git a/cc/layer_impl.h b/cc/layer_impl.h index 05f3b44..f1fae67 100644 --- a/cc/layer_impl.h +++ b/cc/layer_impl.h @@ -167,11 +167,21 @@ public: LayerImpl* renderTarget() const { DCHECK(!m_renderTarget || m_renderTarget->renderSurface()); return m_renderTarget; } void setRenderTarget(LayerImpl* target) { m_renderTarget = target; } + // The client should be responsible for setting bounds, contentBounds and + // contentsScale to appropriate values. LayerImpl doesn't calculate any of + // them from the other values. + void setBounds(const IntSize&); const IntSize& bounds() const { return m_bounds; } - const IntSize& contentBounds() const { return m_contentBounds; } + // ContentBounds may be [0, 1) pixels larger than bounds * contentsScale. + // Don't calculate scale from it. Use contentsScale instead for accuracy. void setContentBounds(const IntSize&); + IntSize contentBounds() const { return m_contentBounds; } + + float contentsScaleX() const { return m_contentsScaleX; } + float contentsScaleY() const { return m_contentsScaleY; } + void setContentsScale(float contentsScaleX, float contentsScaleY); const IntPoint& scrollPosition() const { return m_scrollPosition; } void setScrollPosition(const IntPoint&); @@ -260,13 +270,13 @@ public: ScrollbarLayerImpl* verticalScrollbarLayer() const; void setVerticalScrollbarLayer(ScrollbarLayerImpl*); + IntRect layerRectToContentRect(const FloatRect& layerRect) const; + protected: explicit LayerImpl(int); void appendDebugBorderQuad(QuadSink&, const SharedQuadState*, AppendQuadsData&) const; - IntRect layerRectToContentRect(const WebKit::WebRect& layerRect); - virtual void dumpLayerProperties(std::string*, int indent) const; static std::string indentString(int indent); @@ -300,6 +310,8 @@ private: float m_anchorPointZ; IntSize m_bounds; IntSize m_contentBounds; + float m_contentsScaleX; + float m_contentsScaleY; IntPoint m_scrollPosition; bool m_scrollable; bool m_shouldScrollOnMainThread; diff --git a/cc/layer_impl_unittest.cc b/cc/layer_impl_unittest.cc index def19a9..3640185 100644 --- a/cc/layer_impl_unittest.cc +++ b/cc/layer_impl_unittest.cc @@ -116,6 +116,7 @@ TEST(LayerImplTest, verifyLayerChangesAreTrackedProperly) // Changing these properties only affects the layer itself. EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setContentBounds(arbitraryIntSize)); + EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setContentsScale(arbitraryNumber, arbitraryNumber)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setDebugBorderColor(arbitraryColor)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setDebugBorderWidth(arbitraryNumber)); EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setDrawsContent(true)); @@ -152,6 +153,7 @@ TEST(LayerImplTest, verifyLayerChangesAreTrackedProperly) EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->setScrollPosition(arbitraryIntPoint)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->setImplTransform(arbitraryTransform)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->setContentBounds(arbitraryIntSize)); + EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->setContentsScale(arbitraryNumber, arbitraryNumber)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->setContentsOpaque(true)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->setOpacity(arbitraryNumber)); EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->setDebugBorderColor(arbitraryColor)); diff --git a/cc/layer_tree_host_common.cc b/cc/layer_tree_host_common.cc index b51fd00..65db168 100644 --- a/cc/layer_tree_host_common.cc +++ b/cc/layer_tree_host_common.cc @@ -525,8 +525,8 @@ static void calculateDrawTransformsInternal(LayerType* layer, const WebTransform WebTransformationMatrix drawTransform = combinedTransform; if (!layer->contentBounds().isEmpty() && !layer->bounds().isEmpty()) { // M[draw] = M[parent] * LT * S[layer2content] - drawTransform.scaleNonUniform(layer->bounds().width() / static_cast<double>(layer->contentBounds().width()), - layer->bounds().height() / static_cast<double>(layer->contentBounds().height())); + drawTransform.scaleNonUniform(1.0 / layer->contentsScaleX(), + 1.0 / layer->contentsScaleY()); } // layerScreenSpaceTransform represents the transform between root layer's "screen space" and local content space. @@ -566,8 +566,8 @@ static void calculateDrawTransformsInternal(LayerType* layer, const WebTransform // The owning layer's draw transform has a scale from content to layer space which we need to undo and // replace with a scale from the surface's subtree into layer space. if (!layer->contentBounds().isEmpty() && !layer->bounds().isEmpty()) { - drawTransform.scaleNonUniform(layer->contentBounds().width() / static_cast<double>(layer->bounds().width()), - layer->contentBounds().height() / static_cast<double>(layer->bounds().height())); + drawTransform.scaleNonUniform(layer->contentsScaleX(), + layer->contentsScaleY()); } drawTransform.scaleNonUniform(1 / renderSurfaceSublayerScale.x(), 1 / renderSurfaceSublayerScale.y()); renderSurface->setDrawTransform(drawTransform); @@ -576,8 +576,8 @@ static void calculateDrawTransformsInternal(LayerType* layer, const WebTransform WebTransformationMatrix layerDrawTransform; layerDrawTransform.scaleNonUniform(renderSurfaceSublayerScale.x(), renderSurfaceSublayerScale.y()); if (!layer->contentBounds().isEmpty() && !layer->bounds().isEmpty()) { - layerDrawTransform.scaleNonUniform(layer->bounds().width() / static_cast<double>(layer->contentBounds().width()), - layer->bounds().height() / static_cast<double>(layer->contentBounds().height())); + layerDrawTransform.scaleNonUniform(1.0 / layer->contentsScaleX(), + 1.0 / layer->contentsScaleY()); } layer->setDrawTransform(layerDrawTransform); @@ -751,8 +751,8 @@ static void calculateDrawTransformsInternal(LayerType* layer, const WebTransform // replace with a scale from the surface's subtree into layer space. WebTransformationMatrix screenSpaceTransform = layer->screenSpaceTransform(); if (!layer->contentBounds().isEmpty() && !layer->bounds().isEmpty()) { - screenSpaceTransform.scaleNonUniform(layer->contentBounds().width() / static_cast<double>(layer->bounds().width()), - layer->contentBounds().height() / static_cast<double>(layer->bounds().height())); + screenSpaceTransform.scaleNonUniform(layer->contentsScaleX(), + layer->contentsScaleY()); } screenSpaceTransform.scaleNonUniform(1 / renderSurfaceSublayerScale.x(), 1 / renderSurfaceSublayerScale.y()); renderSurface->setScreenSpaceTransform(screenSpaceTransform); diff --git a/cc/layer_tree_host_common_unittest.cc b/cc/layer_tree_host_common_unittest.cc index 21b323a..ce08617 100644 --- a/cc/layer_tree_host_common_unittest.cc +++ b/cc/layer_tree_host_common_unittest.cc @@ -142,6 +142,12 @@ scoped_refptr<ContentLayer> createDrawableContentLayer(ContentLayerClient* deleg return toReturn; } +#define EXPECT_CONTENTS_SCALE_EQ(expected, layer) \ + do { \ + EXPECT_FLOAT_EQ(expected, layer->contentsScaleX()); \ + EXPECT_FLOAT_EQ(expected, layer->contentsScaleY()); \ + } while (false) + TEST(LayerTreeHostCommonTest, verifyTransformsForNoOpLayer) { // Sanity check: For layers positioned at zero, with zero size, @@ -2967,8 +2973,9 @@ TEST(LayerTreeHostCommonTest, verifyHitTestingForSingleLayerWithScaledContents) scoped_ptr<LayerImpl> testLayer = LayerImpl::create(12345); setLayerPropertiesForTesting(testLayer.get(), identityMatrix, identityMatrix, anchor, position, bounds, false); - // override contentBounds + // override contentBounds and contentsScale testLayer->setContentBounds(IntSize(100, 100)); + testLayer->setContentsScale(2, 2); testLayer->setDrawsContent(true); root->addChild(testLayer.Pass()); @@ -3461,7 +3468,9 @@ class NoScaleContentLayer : public ContentLayer public: static scoped_refptr<NoScaleContentLayer> create(ContentLayerClient* client) { return make_scoped_refptr(new NoScaleContentLayer(client)); } - virtual bool needsContentsScale() const OVERRIDE { return false; } + virtual IntSize contentBounds() const OVERRIDE { return bounds(); } + virtual float contentsScaleX() const OVERRIDE { return 1.0; } + virtual float contentsScaleY() const OVERRIDE { return 1.0; } protected: explicit NoScaleContentLayer(ContentLayerClient* client) : ContentLayer(client) { } @@ -3501,9 +3510,9 @@ TEST(LayerTreeHostCommonTest, verifyLayerTransformsInHighDPI) LayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent->bounds(), deviceScaleFactor, pageScaleFactor, dummyMaxTextureSize, renderSurfaceLayerList); - EXPECT_EQ(deviceScaleFactor * pageScaleFactor, parent->contentsScale()); - EXPECT_EQ(deviceScaleFactor * pageScaleFactor, child->contentsScale()); - EXPECT_EQ(1, childNoScale->contentsScale()); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor, parent); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor, child); + EXPECT_CONTENTS_SCALE_EQ(1, childNoScale); EXPECT_EQ(1u, renderSurfaceLayerList.size()); @@ -3550,6 +3559,83 @@ TEST(LayerTreeHostCommonTest, verifyLayerTransformsInHighDPI) EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildNoScaleTransform, childNoScale->screenSpaceTransform()); } +TEST(LayerTreeHostCommonTest, verifyLayerTransformsInHighDPIAccurateScaleZeroChildPosition) +{ + // Verify draw and screen space transforms of layers not in a surface. + MockContentLayerClient delegate; + WebTransformationMatrix identityMatrix; + + scoped_refptr<ContentLayer> parent = createDrawableContentLayer(&delegate); + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(133, 133), true); + + scoped_refptr<ContentLayer> child = createDrawableContentLayer(&delegate); + setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(13, 13), true); + + scoped_refptr<NoScaleContentLayer> childNoScale = createNoScaleDrawableContentLayer(&delegate); + setLayerPropertiesForTesting(childNoScale.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(13, 13), true); + + parent->addChild(child); + parent->addChild(childNoScale); + + std::vector<scoped_refptr<Layer> > renderSurfaceLayerList; + int dummyMaxTextureSize = 512; + + const float deviceScaleFactor = 1.7f; + const float pageScaleFactor = 1; + + LayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent->bounds(), deviceScaleFactor, pageScaleFactor, dummyMaxTextureSize, renderSurfaceLayerList); + + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor, parent); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor, child); + EXPECT_CONTENTS_SCALE_EQ(1, childNoScale); + + EXPECT_EQ(1u, renderSurfaceLayerList.size()); + + // Verify parent transforms + WebTransformationMatrix expectedParentTransform; + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedParentTransform, parent->screenSpaceTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedParentTransform, parent->drawTransform()); + + // Verify results of transformed parent rects + FloatRect parentContentBounds(FloatPoint(), FloatSize(parent->contentBounds())); + + FloatRect parentDrawRect = MathUtil::mapClippedRect(parent->drawTransform(), parentContentBounds); + FloatRect parentScreenSpaceRect = MathUtil::mapClippedRect(parent->screenSpaceTransform(), parentContentBounds); + + FloatRect expectedParentDrawRect(FloatPoint(), parent->bounds()); + expectedParentDrawRect.scale(deviceScaleFactor); + expectedParentDrawRect.setWidth(ceil(expectedParentDrawRect.width())); + expectedParentDrawRect.setHeight(ceil(expectedParentDrawRect.height())); + EXPECT_FLOAT_RECT_EQ(expectedParentDrawRect, parentDrawRect); + EXPECT_FLOAT_RECT_EQ(expectedParentDrawRect, parentScreenSpaceRect); + + // Verify child transforms + WebTransformationMatrix expectedChildTransform; + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->drawTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildTransform, child->screenSpaceTransform()); + + // Verify results of transformed child rects + FloatRect childContentBounds(FloatPoint(), FloatSize(child->contentBounds())); + + FloatRect childDrawRect = MathUtil::mapClippedRect(child->drawTransform(), childContentBounds); + FloatRect childScreenSpaceRect = MathUtil::mapClippedRect(child->screenSpaceTransform(), childContentBounds); + + FloatRect expectedChildDrawRect(FloatPoint(), child->bounds()); + expectedChildDrawRect.scale(deviceScaleFactor); + expectedChildDrawRect.setWidth(ceil(expectedChildDrawRect.width())); + expectedChildDrawRect.setHeight(ceil(expectedChildDrawRect.height())); + EXPECT_FLOAT_RECT_EQ(expectedChildDrawRect, childDrawRect); + EXPECT_FLOAT_RECT_EQ(expectedChildDrawRect, childScreenSpaceRect); + + // Verify childNoScale transforms + WebTransformationMatrix expectedChildNoScaleTransform = child->drawTransform(); + // All transforms operate on content rects. The child's content rect + // incorporates device scale, but the childNoScale does not; add it here. + expectedChildNoScaleTransform.scale(deviceScaleFactor); + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildNoScaleTransform, childNoScale->drawTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildNoScaleTransform, childNoScale->screenSpaceTransform()); +} + TEST(LayerTreeHostCommonTest, verifyContentsScale) { MockContentLayerClient delegate; @@ -3600,10 +3686,10 @@ TEST(LayerTreeHostCommonTest, verifyContentsScale) LayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent->bounds(), deviceScaleFactor, pageScaleFactor, dummyMaxTextureSize, renderSurfaceLayerList); - EXPECT_FLOAT_EQ(deviceScaleFactor * initialParentScale, parent->contentsScale()); - EXPECT_FLOAT_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, childScale->contentsScale()); - EXPECT_FLOAT_EQ(1, childNoScale->contentsScale()); - EXPECT_FLOAT_EQ(deviceScaleFactor * pageScaleFactor * fixedRasterScale, childNoAutoScale->contentsScale()); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * initialParentScale, parent); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, childScale); + EXPECT_CONTENTS_SCALE_EQ(1, childNoScale); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * fixedRasterScale, childNoAutoScale); // The parent is scaled up and shouldn't need to scale during draw. The child that can scale its contents should // also not need to scale during draw. The other should. @@ -3623,9 +3709,9 @@ TEST(LayerTreeHostCommonTest, verifyContentsScale) renderSurfaceLayerList.clear(); LayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent->bounds(), deviceScaleFactor, pageScaleFactor, dummyMaxTextureSize, renderSurfaceLayerList); - EXPECT_FLOAT_EQ(deviceScaleFactor * initialParentScale, parent->contentsScale()); - EXPECT_FLOAT_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, childScale->contentsScale()); - EXPECT_FLOAT_EQ(1, childNoScale->contentsScale()); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * initialParentScale, parent); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, childScale); + EXPECT_CONTENTS_SCALE_EQ(1, childNoScale); // But if the deviceScaleFactor or pageScaleFactor changes, then it should be updated, but using the initial transform. deviceScaleFactor = 2.25; @@ -3639,10 +3725,10 @@ TEST(LayerTreeHostCommonTest, verifyContentsScale) renderSurfaceLayerList.clear(); LayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent->bounds(), deviceScaleFactor, pageScaleFactor, dummyMaxTextureSize, renderSurfaceLayerList); - EXPECT_FLOAT_EQ(deviceScaleFactor * initialParentScale, parent->contentsScale()); - EXPECT_FLOAT_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, childScale->contentsScale()); - EXPECT_FLOAT_EQ(1, childNoScale->contentsScale()); - EXPECT_FLOAT_EQ(deviceScaleFactor * pageScaleFactor * fixedRasterScale, childNoAutoScale->contentsScale()); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * initialParentScale, parent); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, childScale); + EXPECT_CONTENTS_SCALE_EQ(1, childNoScale); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * fixedRasterScale, childNoAutoScale); } TEST(LayerTreeHostCommonTest, verifyContentsScaleForSurfaces) @@ -3725,17 +3811,17 @@ TEST(LayerTreeHostCommonTest, verifyContentsScaleForSurfaces) LayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent->bounds(), deviceScaleFactor, pageScaleFactor, dummyMaxTextureSize, renderSurfaceLayerList); - EXPECT_EQ(deviceScaleFactor * initialParentScale, parent->contentsScale()); - EXPECT_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, surfaceScale->contentsScale()); - EXPECT_EQ(1, surfaceNoScale->contentsScale()); - EXPECT_EQ(deviceScaleFactor * pageScaleFactor * fixedRasterScale, surfaceNoAutoScale->contentsScale()); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * initialParentScale, parent); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale, surfaceScale); + EXPECT_CONTENTS_SCALE_EQ(1, surfaceNoScale); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * fixedRasterScale, surfaceNoAutoScale); - EXPECT_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale * initialChildScale, surfaceScaleChildScale->contentsScale()); - EXPECT_EQ(1, surfaceScaleChildNoScale->contentsScale()); - EXPECT_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale * initialChildScale, surfaceNoScaleChildScale->contentsScale()); - EXPECT_EQ(1, surfaceNoScaleChildNoScale->contentsScale()); - EXPECT_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale * initialChildScale, surfaceNoAutoScaleChildScale->contentsScale()); - EXPECT_EQ(1, surfaceNoAutoScaleChildNoScale->contentsScale()); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale * initialChildScale, surfaceScaleChildScale); + EXPECT_CONTENTS_SCALE_EQ(1, surfaceScaleChildNoScale); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale * initialChildScale, surfaceNoScaleChildScale); + EXPECT_CONTENTS_SCALE_EQ(1, surfaceNoScaleChildNoScale); + EXPECT_CONTENTS_SCALE_EQ(deviceScaleFactor * pageScaleFactor * initialParentScale * initialChildScale * initialChildScale, surfaceNoAutoScaleChildScale); + EXPECT_CONTENTS_SCALE_EQ(1, surfaceNoAutoScaleChildNoScale); // The parent is scaled up and shouldn't need to scale during draw. EXPECT_FLOAT_EQ(1, parent->drawTransform().m11()); @@ -3870,6 +3956,71 @@ TEST(LayerTreeHostCommonTest, verifyRenderSurfaceTransformsInHighDPI) expectedReplicaScreenSpaceTransform.setM41(6); expectedReplicaScreenSpaceTransform.setM42(6); EXPECT_TRANSFORMATION_MATRIX_EQ(expectedReplicaScreenSpaceTransform, child->renderSurface()->replicaScreenSpaceTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedReplicaScreenSpaceTransform, child->renderSurface()->replicaScreenSpaceTransform()); +} + +TEST(LayerTreeHostCommonTest, verifyRenderSurfaceTransformsInHighDPIAccurateScaleZeroPosition) +{ + MockContentLayerClient delegate; + WebTransformationMatrix identityMatrix; + + scoped_refptr<ContentLayer> parent = createDrawableContentLayer(&delegate); + setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(33, 31), true); + + scoped_refptr<ContentLayer> child = createDrawableContentLayer(&delegate); + setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(13, 11), true); + + WebTransformationMatrix replicaTransform; + replicaTransform.scaleNonUniform(1, -1); + scoped_refptr<ContentLayer> replica = createDrawableContentLayer(&delegate); + setLayerPropertiesForTesting(replica.get(), replicaTransform, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(13, 11), true); + + // This layer should end up in the same surface as child, with the same draw + // and screen space transforms. + scoped_refptr<ContentLayer> duplicateChildNonOwner = createDrawableContentLayer(&delegate); + setLayerPropertiesForTesting(duplicateChildNonOwner.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(13, 11), true); + + parent->addChild(child); + child->addChild(duplicateChildNonOwner); + child->setReplicaLayer(replica.get()); + + std::vector<scoped_refptr<Layer> > renderSurfaceLayerList; + int dummyMaxTextureSize = 512; + + const float deviceScaleFactor = 1.7f; + parent->setContentsScale(deviceScaleFactor); + child->setContentsScale(deviceScaleFactor); + duplicateChildNonOwner->setContentsScale(deviceScaleFactor); + replica->setContentsScale(deviceScaleFactor); + + LayerTreeHostCommon::calculateDrawTransforms(parent.get(), parent->bounds(), deviceScaleFactor, 1, dummyMaxTextureSize, renderSurfaceLayerList); + + // We should have two render surfaces. The root's render surface and child's + // render surface (it needs one because it has a replica layer). + EXPECT_EQ(2u, renderSurfaceLayerList.size()); + + WebTransformationMatrix identityTransform; + + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, parent->screenSpaceTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, parent->drawTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, child->drawTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, child->screenSpaceTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, duplicateChildNonOwner->drawTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, duplicateChildNonOwner->screenSpaceTransform()); + EXPECT_RECT_EQ(child->drawableContentRect(), duplicateChildNonOwner->drawableContentRect()); + EXPECT_EQ(child->contentBounds(), duplicateChildNonOwner->contentBounds()); + + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, child->renderSurface()->drawTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, child->renderSurface()->drawTransform()); + EXPECT_TRANSFORMATION_MATRIX_EQ(identityTransform, child->renderSurface()->screenSpaceTransform()); + + WebTransformationMatrix expectedReplicaDrawTransform; + expectedReplicaDrawTransform.setM22(-1); + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedReplicaDrawTransform, child->renderSurface()->replicaDrawTransform()); + + WebTransformationMatrix expectedReplicaScreenSpaceTransform; + expectedReplicaScreenSpaceTransform.setM22(-1); + EXPECT_TRANSFORMATION_MATRIX_EQ(expectedReplicaScreenSpaceTransform, child->renderSurface()->replicaScreenSpaceTransform()); } TEST(LayerTreeHostCommonTest, verifySubtreeSearch) diff --git a/cc/layer_tree_host_impl.cc b/cc/layer_tree_host_impl.cc index 581377e..1add8df 100644 --- a/cc/layer_tree_host_impl.cc +++ b/cc/layer_tree_host_impl.cc @@ -1102,12 +1102,8 @@ static FloatSize scrollLayerWithViewportSpaceDelta(PinchZoomViewport* viewport, return FloatSize(); // localStartPoint and localEndPoint are in content space but we want to move them to layer space for scrolling. - float widthScale = 1; - float heightScale = 1; - if (!layerImpl.contentBounds().isEmpty() && !layerImpl.bounds().isEmpty()) { - widthScale = layerImpl.bounds().width() / static_cast<float>(layerImpl.contentBounds().width()); - heightScale = layerImpl.bounds().height() / static_cast<float>(layerImpl.contentBounds().height()); - } + float widthScale = 1.0 / layerImpl.contentsScaleX(); + float heightScale = 1.0 / layerImpl.contentsScaleY(); localStartPoint.scale(widthScale, heightScale); localEndPoint.scale(widthScale, heightScale); diff --git a/cc/layer_tree_host_impl_unittest.cc b/cc/layer_tree_host_impl_unittest.cc index e2ecdce..79bc896 100644 --- a/cc/layer_tree_host_impl_unittest.cc +++ b/cc/layer_tree_host_impl_unittest.cc @@ -1045,6 +1045,7 @@ TEST_P(LayerTreeHostImplTest, scrollNonCompositedRoot) contentLayer->setAnchorPoint(FloatPoint(0, 0)); contentLayer->setBounds(surfaceSize); contentLayer->setContentBounds(IntSize(surfaceSize.width() * 2, surfaceSize.height() * 2)); + contentLayer->setContentsScale(2, 2); scoped_ptr<LayerImpl> scrollLayer = LayerImpl::create(2); scrollLayer->setScrollable(true); diff --git a/cc/layer_tree_host_unittest.cc b/cc/layer_tree_host_unittest.cc index 86be122..1117356 100644 --- a/cc/layer_tree_host_unittest.cc +++ b/cc/layer_tree_host_unittest.cc @@ -1224,7 +1224,9 @@ class NoScaleContentLayer : public ContentLayer { public: static scoped_refptr<NoScaleContentLayer> create(ContentLayerClient* client) { return make_scoped_refptr(new NoScaleContentLayer(client)); } - virtual bool needsContentsScale() const OVERRIDE { return false; } + virtual IntSize contentBounds() const OVERRIDE { return bounds(); } + virtual float contentsScaleX() const OVERRIDE { return 1.0; } + virtual float contentsScaleY() const OVERRIDE { return 1.0; } private: explicit NoScaleContentLayer(ContentLayerClient* client) diff --git a/cc/layer_unittest.cc b/cc/layer_unittest.cc index e2cb6b2..a4a0725 100644 --- a/cc/layer_unittest.cc +++ b/cc/layer_unittest.cc @@ -549,56 +549,6 @@ TEST_F(LayerTest, verifyPushPropertiesAccumulatesUpdateRect) EXPECT_FLOAT_RECT_EQ(FloatRect(FloatPoint(10, 10), FloatSize(5, 5)), implLayer->updateRect()); } -class LayerWithContentScaling : public Layer { -public: - explicit LayerWithContentScaling() - : Layer() - { - } - - virtual bool needsContentsScale() const OVERRIDE - { - return true; - } - - virtual void setNeedsDisplayRect(const FloatRect& dirtyRect) OVERRIDE - { - m_lastNeedsDisplayRect = dirtyRect; - Layer::setNeedsDisplayRect(dirtyRect); - } - - void resetNeedsDisplay() - { - m_needsDisplay = false; - } - - const FloatRect& lastNeedsDisplayRect() const { return m_lastNeedsDisplayRect; } - -private: - virtual ~LayerWithContentScaling() - { - } - - FloatRect m_lastNeedsDisplayRect; -}; - -TEST_F(LayerTest, checkContentsScaleChangeTriggersNeedsDisplay) -{ - scoped_refptr<LayerWithContentScaling> testLayer = make_scoped_refptr(new LayerWithContentScaling()); - testLayer->setIsDrawable(true); - testLayer->setLayerTreeHost(m_layerTreeHost.get()); - - IntSize testBounds = IntSize(320, 240); - EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setBounds(testBounds)); - - testLayer->resetNeedsDisplay(); - EXPECT_FALSE(testLayer->needsDisplay()); - - EXECUTE_AND_VERIFY_SET_NEEDS_COMMIT_BEHAVIOR(1, testLayer->setContentsScale(testLayer->contentsScale() + 1.f)); - EXPECT_TRUE(testLayer->needsDisplay()); - EXPECT_FLOAT_RECT_EQ(FloatRect(0, 0, 320, 240), testLayer->lastNeedsDisplayRect()); -} - class FakeLayerImplTreeHost : public LayerTreeHost { public: static scoped_ptr<FakeLayerImplTreeHost> create() diff --git a/cc/render_surface_impl.cc b/cc/render_surface_impl.cc index ece1d10..40c0dea 100644 --- a/cc/render_surface_impl.cc +++ b/cc/render_surface_impl.cc @@ -236,8 +236,8 @@ void RenderSurfaceImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQ float maskTexCoordOffsetX = 0; float maskTexCoordOffsetY = 0; if (maskLayer) { - maskTexCoordScaleX = static_cast<float>(contentRect().width()) / maskLayer->contentBounds().width(); - maskTexCoordScaleY = static_cast<float>(contentRect().height()) / maskLayer->contentBounds().height(); + maskTexCoordScaleX = contentRect().width() / maskLayer->contentsScaleX() / maskLayer->bounds().width(); + maskTexCoordScaleY = contentRect().height() / maskLayer->contentsScaleY() / maskLayer->bounds().height(); maskTexCoordOffsetX = static_cast<float>(contentRect().x()) / contentRect().width() * maskTexCoordScaleX; maskTexCoordOffsetY = static_cast<float>(contentRect().y()) / contentRect().height() * maskTexCoordScaleY; } diff --git a/cc/scrollbar_layer.cc b/cc/scrollbar_layer.cc index baecc14..87b9e6b 100644 --- a/cc/scrollbar_layer.cc +++ b/cc/scrollbar_layer.cc @@ -43,7 +43,7 @@ ScrollbarLayer::~ScrollbarLayer() void ScrollbarLayer::pushPropertiesTo(LayerImpl* layer) { - Layer::pushPropertiesTo(layer); + ContentsScalingLayer::pushPropertiesTo(layer); ScrollbarLayerImpl* scrollbarLayer = static_cast<ScrollbarLayerImpl*>(layer); @@ -130,16 +130,6 @@ private: DISALLOW_COPY_AND_ASSIGN(ScrollbarBackgroundPainter); }; -bool ScrollbarLayer::needsContentsScale() const -{ - return true; -} - -IntSize ScrollbarLayer::contentBounds() const -{ - return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale())); -} - class ScrollbarThumbPainter : public LayerPainter { public: static scoped_ptr<ScrollbarThumbPainter> create(WebKit::WebScrollbar* scrollbar, WebKit::WebScrollbarThemePainter painter, WebKit::WebScrollbarThemeGeometry* geometry) @@ -182,7 +172,7 @@ void ScrollbarLayer::setLayerTreeHost(LayerTreeHost* host) m_thumb.reset(); } - Layer::setLayerTreeHost(host); + ContentsScalingLayer::setLayerTreeHost(host); } void ScrollbarLayer::createUpdaterIfNeeded() @@ -223,10 +213,8 @@ void ScrollbarLayer::updatePart(CachingBitmapContentLayerUpdater* painter, Layer return; // Paint and upload the entire part. - float widthScale = static_cast<float>(contentBounds().width()) / bounds().width(); - float heightScale = static_cast<float>(contentBounds().height()) / bounds().height(); gfx::Rect paintedOpaqueRect; - painter->prepareToUpdate(rect, rect.size(), widthScale, heightScale, paintedOpaqueRect, stats); + painter->prepareToUpdate(rect, rect.size(), contentsScaleX(), contentsScaleY(), paintedOpaqueRect, stats); if (!painter->pixelsDidChange() && texture->texture()->haveBackingTexture()) { TRACE_EVENT_INSTANT0("cc","ScrollbarLayer::updatePart no texture upload needed"); return; @@ -236,6 +224,14 @@ void ScrollbarLayer::updatePart(CachingBitmapContentLayerUpdater* painter, Layer texture->update(queue, rect, destOffset, false, stats); } +IntRect ScrollbarLayer::scrollbarLayerRectToContentRect(const WebRect& layerRect) const +{ + // Don't intersect with the bounds as in layerRectToContentRect() because + // layerRect here might be in coordinates of the containing layer. + FloatRect contentRect(layerRect.x, layerRect.y, layerRect.width, layerRect.height); + contentRect.scale(contentsScaleX(), contentsScaleY()); + return enclosingIntRect(contentRect); +} void ScrollbarLayer::setTexturePriorities(const PriorityCalculator&) { @@ -254,7 +250,7 @@ void ScrollbarLayer::setTexturePriorities(const PriorityCalculator&) m_foreTrack->texture()->setRequestPriority(PriorityCalculator::uiPriority(drawsToRoot)); } if (m_thumb) { - IntSize thumbSize = layerRectToContentRect(m_geometry->thumbRect(m_scrollbar.get())).size(); + IntSize thumbSize = scrollbarLayerRectToContentRect(m_geometry->thumbRect(m_scrollbar.get())).size(); m_thumb->texture()->setDimensions(thumbSize, m_textureFormat); m_thumb->texture()->setRequestPriority(PriorityCalculator::uiPriority(drawsToRoot)); } @@ -267,15 +263,14 @@ void ScrollbarLayer::update(ResourceUpdateQueue& queue, const OcclusionTracker*, createUpdaterIfNeeded(); - IntPoint scrollbarOrigin(m_scrollbar->location().x, m_scrollbar->location().y); - IntRect contentRect = layerRectToContentRect(WebKit::WebRect(scrollbarOrigin.x(), scrollbarOrigin.y(), bounds().width(), bounds().height())); + IntRect contentRect = scrollbarLayerRectToContentRect(WebRect(m_scrollbar->location().x, m_scrollbar->location().y, bounds().width(), bounds().height())); updatePart(m_backTrackUpdater.get(), m_backTrack.get(), contentRect, queue, stats); if (m_foreTrack && m_foreTrackUpdater) updatePart(m_foreTrackUpdater.get(), m_foreTrack.get(), contentRect, queue, stats); // Consider the thumb to be at the origin when painting. WebKit::WebRect thumbRect = m_geometry->thumbRect(m_scrollbar.get()); - IntRect originThumbRect = layerRectToContentRect(WebKit::WebRect(0, 0, thumbRect.width, thumbRect.height)); + IntRect originThumbRect = scrollbarLayerRectToContentRect(WebRect(0, 0, thumbRect.width, thumbRect.height)); if (!originThumbRect.isEmpty()) updatePart(m_thumbUpdater.get(), m_thumb.get(), originThumbRect, queue, stats); } diff --git a/cc/scrollbar_layer.h b/cc/scrollbar_layer.h index 95847a9..035d3ee 100644 --- a/cc/scrollbar_layer.h +++ b/cc/scrollbar_layer.h @@ -6,8 +6,8 @@ #ifndef ScrollbarLayerChromium_h #define ScrollbarLayerChromium_h -#include "caching_bitmap_content_layer_updater.h" -#include "cc/layer.h" +#include "cc/caching_bitmap_content_layer_updater.h" +#include "cc/contents_scaling_layer.h" #include <public/WebScrollbar.h> #include <public/WebScrollbarThemeGeometry.h> #include <public/WebScrollbarThemePainter.h> @@ -18,15 +18,13 @@ class ResourceUpdateQueue; class Scrollbar; class ScrollbarThemeComposite; -class ScrollbarLayer : public Layer { +class ScrollbarLayer : public ContentsScalingLayer { public: virtual scoped_ptr<LayerImpl> createLayerImpl() OVERRIDE; static scoped_refptr<ScrollbarLayer> create(scoped_ptr<WebKit::WebScrollbar>, WebKit::WebScrollbarThemePainter, scoped_ptr<WebKit::WebScrollbarThemeGeometry>, int scrollLayerId); // Layer interface - virtual bool needsContentsScale() const OVERRIDE; - virtual IntSize contentBounds() const OVERRIDE; virtual void setTexturePriorities(const PriorityCalculator&) OVERRIDE; virtual void update(ResourceUpdateQueue&, const OcclusionTracker*, RenderingStats&) OVERRIDE; virtual void setLayerTreeHost(LayerTreeHost*) OVERRIDE; @@ -44,6 +42,7 @@ protected: private: void updatePart(CachingBitmapContentLayerUpdater*, LayerUpdater::Resource*, const IntRect&, ResourceUpdateQueue&, RenderingStats&); void createUpdaterIfNeeded(); + IntRect scrollbarLayerRectToContentRect(const WebKit::WebRect& layerRect) const; scoped_ptr<WebKit::WebScrollbar> m_scrollbar; WebKit::WebScrollbarThemePainter m_painter; diff --git a/cc/scrollbar_layer_impl.cc b/cc/scrollbar_layer_impl.cc index fcb8f38..180fd82 100644 --- a/cc/scrollbar_layer_impl.cc +++ b/cc/scrollbar_layer_impl.cc @@ -72,6 +72,15 @@ static FloatRect toUVRect(const WebRect& r, const IntRect& bounds) static_cast<float>(r.width) / bounds.width(), static_cast<float>(r.height) / bounds.height()); } +IntRect ScrollbarLayerImpl::scrollbarLayerRectToContentRect(const WebRect& layerRect) const +{ + // Don't intersect with the bounds as in layerRectToContentRect() because + // layerRect here might be in coordinates of the containing layer. + FloatRect contentRect(layerRect.x, layerRect.y, layerRect.width, layerRect.height); + contentRect.scale(contentsScaleX(), contentsScaleY()); + return enclosingIntRect(contentRect); +} + void ScrollbarLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuadsData) { bool premultipledAlpha = false; @@ -89,7 +98,7 @@ void ScrollbarLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& append thumbRect = WebRect(); if (m_thumbResourceId && !thumbRect.isEmpty()) { - scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::create(sharedQuadState, layerRectToContentRect(thumbRect), m_thumbResourceId, premultipledAlpha, uvRect, flipped); + scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::create(sharedQuadState, scrollbarLayerRectToContentRect(thumbRect), m_thumbResourceId, premultipledAlpha, uvRect, flipped); quad->setNeedsBlending(); quadSink.append(quad.PassAs<DrawQuad>(), appendQuadsData); } @@ -99,7 +108,7 @@ void ScrollbarLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& append // We only paint the track in two parts if we were given a texture for the forward track part. if (m_foreTrackResourceId && !foreTrackRect.isEmpty()) - quadSink.append(TextureDrawQuad::create(sharedQuadState, layerRectToContentRect(foreTrackRect), m_foreTrackResourceId, premultipledAlpha, toUVRect(foreTrackRect, boundsRect), flipped).PassAs<DrawQuad>(), appendQuadsData); + quadSink.append(TextureDrawQuad::create(sharedQuadState, scrollbarLayerRectToContentRect(foreTrackRect), m_foreTrackResourceId, premultipledAlpha, toUVRect(foreTrackRect, boundsRect), flipped).PassAs<DrawQuad>(), appendQuadsData); // Order matters here: since the back track texture is being drawn to the entire contents rect, we must append it after the thumb and // fore track quads. The back track texture contains (and displays) the buttons. diff --git a/cc/scrollbar_layer_impl.h b/cc/scrollbar_layer_impl.h index b44770a..5ed2281 100644 --- a/cc/scrollbar_layer_impl.h +++ b/cc/scrollbar_layer_impl.h @@ -77,6 +77,8 @@ private: virtual const char* layerTypeAsString() const OVERRIDE; + IntRect scrollbarLayerRectToContentRect(const WebKit::WebRect& layerRect) const; + Scrollbar m_scrollbar; ResourceProvider::ResourceId m_backTrackResourceId; diff --git a/cc/test/tiled_layer_test_common.cc b/cc/test/tiled_layer_test_common.cc index 9757617..56b3049 100644 --- a/cc/test/tiled_layer_test_common.cc +++ b/cc/test/tiled_layer_test_common.cc @@ -139,4 +139,19 @@ cc::IntSize FakeTiledLayerWithScaledBounds::contentBounds() const return m_forcedContentBounds; } +float FakeTiledLayerWithScaledBounds::contentsScaleX() const +{ + return static_cast<float>(m_forcedContentBounds.width()) / bounds().width(); +} + +float FakeTiledLayerWithScaledBounds::contentsScaleY() const +{ + return static_cast<float>(m_forcedContentBounds.height()) / bounds().height(); +} + +void FakeTiledLayerWithScaledBounds::setContentsScale(float) +{ + NOTREACHED(); +} + } // namespace diff --git a/cc/test/tiled_layer_test_common.h b/cc/test/tiled_layer_test_common.h index 6c77c9d..3dac556 100644 --- a/cc/test/tiled_layer_test_common.h +++ b/cc/test/tiled_layer_test_common.h @@ -116,6 +116,9 @@ public: void setContentBounds(const cc::IntSize& contentBounds) { m_forcedContentBounds = contentBounds; } virtual cc::IntSize contentBounds() const OVERRIDE; + virtual float contentsScaleX() const OVERRIDE; + virtual float contentsScaleY() const OVERRIDE; + virtual void setContentsScale(float) OVERRIDE; protected: virtual ~FakeTiledLayerWithScaledBounds(); diff --git a/cc/tiled_layer.cc b/cc/tiled_layer.cc index b21d911..7232042 100644 --- a/cc/tiled_layer.cc +++ b/cc/tiled_layer.cc @@ -84,7 +84,7 @@ private: }; TiledLayer::TiledLayer() - : Layer() + : ContentsScalingLayer() , m_textureFormat(GL_INVALID_ENUM) , m_skipsDraw(false) , m_failedUpdate(false) @@ -166,7 +166,7 @@ void TiledLayer::setBorderTexelOption(LayerTilingData::BorderTexelOption borderT bool TiledLayer::drawsContent() const { - if (!Layer::drawsContent()) + if (!ContentsScalingLayer::drawsContent()) return false; bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() > 1; @@ -176,16 +176,6 @@ bool TiledLayer::drawsContent() const return true; } -bool TiledLayer::needsContentsScale() const -{ - return true; -} - -IntSize TiledLayer::contentBounds() const -{ - return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale())); -} - void TiledLayer::setTilingOption(TilingOption tilingOption) { m_tilingOption = tilingOption; @@ -198,7 +188,7 @@ void TiledLayer::setIsMask(bool isMask) void TiledLayer::pushPropertiesTo(LayerImpl* layer) { - Layer::pushPropertiesTo(layer); + ContentsScalingLayer::pushPropertiesTo(layer); TiledLayerImpl* tiledLayer = static_cast<TiledLayerImpl*>(layer); @@ -250,7 +240,7 @@ void TiledLayer::setLayerTreeHost(LayerTreeHost* host) tile->managedTexture()->setTextureManager(host->contentsTextureManager()); } } - Layer::setLayerTreeHost(host); + ContentsScalingLayer::setLayerTreeHost(host); } UpdatableTile* TiledLayer::tileAt(int i, int j) const @@ -281,18 +271,13 @@ UpdatableTile* TiledLayer::createTile(int i, int j) void TiledLayer::setNeedsDisplayRect(const FloatRect& dirtyRect) { - float contentsWidthScale = static_cast<float>(contentBounds().width()) / bounds().width(); - float contentsHeightScale = static_cast<float>(contentBounds().height()) / bounds().height(); - FloatRect scaledDirtyRect(dirtyRect); - scaledDirtyRect.scale(contentsWidthScale, contentsHeightScale); - IntRect dirty = enclosingIntRect(scaledDirtyRect); - invalidateContentRect(dirty); - Layer::setNeedsDisplayRect(dirtyRect); + invalidateContentRect(layerRectToContentRect(dirtyRect)); + ContentsScalingLayer::setNeedsDisplayRect(dirtyRect); } void TiledLayer::setUseLCDText(bool useLCDText) { - Layer::setUseLCDText(useLCDText); + ContentsScalingLayer::setUseLCDText(useLCDText); LayerTilingData::BorderTexelOption borderTexelOption; #if OS(ANDROID) diff --git a/cc/tiled_layer.h b/cc/tiled_layer.h index c6cb541..7994d2c 100644 --- a/cc/tiled_layer.h +++ b/cc/tiled_layer.h @@ -5,14 +5,14 @@ #ifndef TiledLayerChromium_h #define TiledLayerChromium_h -#include "cc/layer.h" +#include "cc/contents_scaling_layer.h" #include "cc/layer_updater.h" #include "cc/layer_tiling_data.h" namespace cc { class UpdatableTile; -class TiledLayer : public Layer { +class TiledLayer : public ContentsScalingLayer { public: enum TilingOption { AlwaysTile, NeverTile, AutoTile }; @@ -21,9 +21,6 @@ public: virtual void pushPropertiesTo(LayerImpl*) OVERRIDE; virtual bool drawsContent() const OVERRIDE; - virtual bool needsContentsScale() const OVERRIDE; - - virtual IntSize contentBounds() const OVERRIDE; virtual void setNeedsDisplayRect(const FloatRect&) OVERRIDE; diff --git a/cc/tiled_layer_unittest.cc b/cc/tiled_layer_unittest.cc index d219114..2b5e4bd 100644 --- a/cc/tiled_layer_unittest.cc +++ b/cc/tiled_layer_unittest.cc @@ -1164,9 +1164,10 @@ TEST_F(TiledLayerTest, tilesPaintedWithOcclusionAndScaling) // a different layer space. In this case tiles are scaled to be 200x200 // pixels, which means none should be occluded. layer->setContentsScale(0.5); + EXPECT_FLOAT_EQ(layer->contentsScaleX(), layer->contentsScaleY()); layer->setBounds(IntSize(600, 600)); WebTransformationMatrix drawTransform; - drawTransform.scale(1 / layer->contentsScale()); + drawTransform.scale(1 / layer->contentsScaleX()); layer->setDrawTransform(drawTransform); layer->setScreenSpaceTransform(drawTransform); |