| /* |
| * Copyright (C) 2012 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "platform/graphics/GraphicsLayer.h" |
| |
| #include "platform/RuntimeEnabledFeatures.h" |
| #include "platform/animation/CompositorAnimationPlayer.h" |
| #include "platform/animation/CompositorAnimationPlayerClient.h" |
| #include "platform/animation/CompositorAnimationTimeline.h" |
| #include "platform/animation/CompositorFloatAnimationCurve.h" |
| #include "platform/graphics/CompositorFactory.h" |
| #include "platform/scroll/ScrollableArea.h" |
| #include "platform/testing/FakeGraphicsLayer.h" |
| #include "platform/testing/WebLayerTreeViewImplForTesting.h" |
| #include "platform/transforms/Matrix3DTransformOperation.h" |
| #include "platform/transforms/RotateTransformOperation.h" |
| #include "platform/transforms/TranslateTransformOperation.h" |
| #include "public/platform/Platform.h" |
| #include "public/platform/WebCompositorSupport.h" |
| #include "public/platform/WebGraphicsContext3D.h" |
| #include "public/platform/WebLayer.h" |
| #include "public/platform/WebLayerTreeView.h" |
| #include "public/platform/WebUnitTestSupport.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "wtf/PassOwnPtr.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| class MockGraphicsLayerClient : public GraphicsLayerClient { |
| public: |
| bool needsRepaint(const GraphicsLayer&) const { return true; } |
| IntRect computeInterestRect(const GraphicsLayer*, const IntRect&) const { return IntRect(); } |
| void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&) const override { } |
| String debugName(const GraphicsLayer*) const override { return String(); } |
| }; |
| |
| } // anonymous namespace |
| |
| class GraphicsLayerTest : public testing::Test { |
| public: |
| GraphicsLayerTest() |
| { |
| m_clipLayer = adoptPtr(new FakeGraphicsLayer(&m_client)); |
| m_scrollElasticityLayer = adoptPtr(new FakeGraphicsLayer(&m_client)); |
| m_graphicsLayer = adoptPtr(new FakeGraphicsLayer(&m_client)); |
| m_clipLayer->addChild(m_scrollElasticityLayer.get()); |
| m_scrollElasticityLayer->addChild(m_graphicsLayer.get()); |
| m_graphicsLayer->platformLayer()->setScrollClipLayer( |
| m_clipLayer->platformLayer()); |
| m_platformLayer = m_graphicsLayer->platformLayer(); |
| m_layerTreeView = adoptPtr(new WebLayerTreeViewImplForTesting); |
| ASSERT(m_layerTreeView); |
| m_layerTreeView->setRootLayer(*m_clipLayer->platformLayer()); |
| m_layerTreeView->registerViewportLayers( |
| m_scrollElasticityLayer->platformLayer(), m_clipLayer->platformLayer(), m_graphicsLayer->platformLayer(), 0); |
| m_layerTreeView->setViewportSize(WebSize(1, 1)); |
| } |
| |
| ~GraphicsLayerTest() override |
| { |
| m_graphicsLayer.clear(); |
| m_layerTreeView.clear(); |
| } |
| |
| WebLayerTreeView* layerTreeView() { return m_layerTreeView.get(); } |
| |
| protected: |
| WebLayer* m_platformLayer; |
| OwnPtr<FakeGraphicsLayer> m_graphicsLayer; |
| OwnPtr<FakeGraphicsLayer> m_scrollElasticityLayer; |
| OwnPtr<FakeGraphicsLayer> m_clipLayer; |
| |
| private: |
| OwnPtr<WebLayerTreeView> m_layerTreeView; |
| MockGraphicsLayerClient m_client; |
| }; |
| |
| class AnimationPlayerForTesting : public CompositorAnimationPlayerClient { |
| public: |
| AnimationPlayerForTesting() |
| { |
| m_compositorPlayer = adoptPtr(CompositorFactory::current().createAnimationPlayer()); |
| } |
| |
| CompositorAnimationPlayer* compositorPlayer() const override |
| { |
| return m_compositorPlayer.get(); |
| } |
| |
| OwnPtr<CompositorAnimationPlayer> m_compositorPlayer; |
| }; |
| |
| TEST_F(GraphicsLayerTest, updateLayerShouldFlattenTransformWithAnimations) |
| { |
| ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting()); |
| |
| OwnPtr<CompositorFloatAnimationCurve> curve = adoptPtr(CompositorFactory::current().createFloatAnimationCurve()); |
| curve->add(CompositorFloatKeyframe(0.0, 0.0)); |
| OwnPtr<CompositorAnimation> floatAnimation(adoptPtr(CompositorFactory::current().createAnimation(*curve, CompositorTargetProperty::OPACITY))); |
| int animationId = floatAnimation->id(); |
| |
| OwnPtr<CompositorAnimationTimeline> compositorTimeline = adoptPtr(CompositorFactory::current().createAnimationTimeline()); |
| AnimationPlayerForTesting player; |
| |
| layerTreeView()->attachCompositorAnimationTimeline(compositorTimeline->animationTimeline()); |
| compositorTimeline->playerAttached(player); |
| |
| player.compositorPlayer()->attachLayer(m_platformLayer); |
| ASSERT_TRUE(player.compositorPlayer()->isLayerAttached()); |
| |
| player.compositorPlayer()->addAnimation(floatAnimation.leakPtr()); |
| |
| ASSERT_TRUE(m_platformLayer->hasActiveAnimationForTesting()); |
| |
| m_graphicsLayer->setShouldFlattenTransform(false); |
| |
| m_platformLayer = m_graphicsLayer->platformLayer(); |
| ASSERT_TRUE(m_platformLayer); |
| |
| ASSERT_TRUE(m_platformLayer->hasActiveAnimationForTesting()); |
| player.compositorPlayer()->removeAnimation(animationId); |
| ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting()); |
| |
| m_graphicsLayer->setShouldFlattenTransform(true); |
| |
| m_platformLayer = m_graphicsLayer->platformLayer(); |
| ASSERT_TRUE(m_platformLayer); |
| |
| ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting()); |
| |
| player.compositorPlayer()->detachLayer(); |
| ASSERT_FALSE(player.compositorPlayer()->isLayerAttached()); |
| |
| compositorTimeline->playerDestroyed(player); |
| layerTreeView()->detachCompositorAnimationTimeline(compositorTimeline->animationTimeline()); |
| } |
| |
| class FakeScrollableArea : public GarbageCollectedFinalized<FakeScrollableArea>, public ScrollableArea { |
| USING_GARBAGE_COLLECTED_MIXIN(FakeScrollableArea); |
| public: |
| static FakeScrollableArea* create() |
| { |
| return new FakeScrollableArea; |
| } |
| |
| LayoutRect visualRectForScrollbarParts() const override { return LayoutRect(); } |
| bool isActive() const override { return false; } |
| int scrollSize(ScrollbarOrientation) const override { return 100; } |
| bool isScrollCornerVisible() const override { return false; } |
| IntRect scrollCornerRect() const override { return IntRect(); } |
| int visibleWidth() const override { return 10; } |
| int visibleHeight() const override { return 10; } |
| IntSize contentsSize() const override { return IntSize(100, 100); } |
| bool scrollbarsCanBeActive() const override { return false; } |
| IntRect scrollableAreaBoundingBox() const override { return IntRect(); } |
| void scrollControlWasSetNeedsPaintInvalidation() override { } |
| bool userInputScrollable(ScrollbarOrientation) const override { return true; } |
| bool shouldPlaceVerticalScrollbarOnLeft() const override { return false; } |
| int pageStep(ScrollbarOrientation) const override { return 0; } |
| IntPoint minimumScrollPosition() const override { return IntPoint(); } |
| IntPoint maximumScrollPosition() const override |
| { |
| return IntPoint(contentsSize().width() - visibleWidth(), contentsSize().height() - visibleHeight()); |
| } |
| |
| void setScrollOffset(const DoublePoint& scrollOffset, ScrollType) override { m_scrollPosition = scrollOffset; } |
| DoublePoint scrollPositionDouble() const override { return m_scrollPosition; } |
| IntPoint scrollPosition() const override { return flooredIntPoint(m_scrollPosition); } |
| |
| DEFINE_INLINE_VIRTUAL_TRACE() |
| { |
| ScrollableArea::trace(visitor); |
| } |
| |
| private: |
| DoublePoint m_scrollPosition; |
| }; |
| |
| TEST_F(GraphicsLayerTest, applyScrollToScrollableArea) |
| { |
| FakeScrollableArea* scrollableArea = FakeScrollableArea::create(); |
| m_graphicsLayer->setScrollableArea(scrollableArea, false); |
| |
| WebDoublePoint scrollPosition(7, 9); |
| m_platformLayer->setScrollPositionDouble(scrollPosition); |
| m_graphicsLayer->didScroll(); |
| |
| EXPECT_FLOAT_EQ(scrollPosition.x, scrollableArea->scrollPositionDouble().x()); |
| EXPECT_FLOAT_EQ(scrollPosition.y, scrollableArea->scrollPositionDouble().y()); |
| } |
| |
| } // namespace blink |