TEST_P(CompositorWorkerTest, noProxies) {
  // This case is identical to compositor-proxy-basic, but no proxies have
  // actually been created.
  registerMockedHttpURLLoad("compositor-proxy-plumbing-no-proxies.html");
  navigateTo(m_baseURL + "compositor-proxy-plumbing-no-proxies.html");

  forceFullCompositingUpdate();

  Document* document = frame()->document();

  Element* tallElement = document->getElementById("tall");
  WebLayer* tallLayer = webLayerFromElement(tallElement);
  EXPECT_TRUE(!tallLayer);

  Element* proxiedElement = document->getElementById("proxied");
  WebLayer* proxiedLayer = webLayerFromElement(proxiedElement);
  EXPECT_TRUE(!proxiedLayer);

  // Note: we presume the existance of mutable properties implies that the the
  // element has a corresponding compositor proxy. Element ids (which are also
  // used by animations) do not have this implication, so we do not check for
  // them here.
  Element* scrollElement = document->getElementById("proxied-scroller");
  WebLayer* scrollLayer = scrollingWebLayerFromElement(scrollElement);
  EXPECT_FALSE(!!scrollLayer->compositorMutableProperties());

  WebLayer* rootScrollLayer = getRootScrollLayer();
  EXPECT_FALSE(!!rootScrollLayer->compositorMutableProperties());
}
TEST_P(CompositorWorkerTest, disconnectedProxies) {
  // This case is identical to compositor-proxy-basic, but the proxies are
  // disconnected (the result should be the same as
  // compositor-proxy-plumbing-no-proxies).
  registerMockedHttpURLLoad("compositor-proxy-basic-disconnected.html");
  navigateTo(m_baseURL + "compositor-proxy-basic-disconnected.html");

  forceFullCompositingUpdate();

  Document* document = frame()->document();

  Element* tallElement = document->getElementById("tall");
  WebLayer* tallLayer = webLayerFromElement(tallElement);
  EXPECT_TRUE(!tallLayer);

  Element* proxiedElement = document->getElementById("proxied");
  WebLayer* proxiedLayer = webLayerFromElement(proxiedElement);
  EXPECT_TRUE(!proxiedLayer);

  Element* scrollElement = document->getElementById("proxied-scroller");
  WebLayer* scrollLayer = scrollingWebLayerFromElement(scrollElement);
  EXPECT_FALSE(!!scrollLayer->compositorMutableProperties());

  WebLayer* rootScrollLayer = getRootScrollLayer();
  EXPECT_FALSE(!!rootScrollLayer->compositorMutableProperties());
}
TEST_F(ProgrammaticScrollTest, RestoreScrollPositionAndViewStateWithScale)
{
    registerMockedHttpURLLoad("long_scroll.html");

    FrameTestHelpers::WebViewHelper webViewHelper;
    WebView* webView = webViewHelper.initializeAndLoad(m_baseURL + "long_scroll.html", true, 0, 0);
    webView->resize(WebSize(1000, 1000));
    webView->updateAllLifecyclePhases();

    WebViewImpl* webViewImpl = toWebViewImpl(webView);
    FrameLoader& loader = webViewImpl->mainFrameImpl()->frame()->loader();
    loader.setLoadType(FrameLoadTypeBackForward);

    webViewImpl->setPageScaleFactor(3.0f);
    webViewImpl->mainFrame()->setScrollOffset(WebSize(0, 500));
    loader.documentLoader()->initialScrollState().wasScrolledByUser = false;
    loader.currentItem()->setPageScaleFactor(2);
    loader.currentItem()->setScrollPoint(WebPoint(0, 200));

    // Flip back the wasScrolledByUser flag which was set to true by setPageScaleFactor
    // because otherwise FrameLoader::restoreScrollPositionAndViewState does nothing.
    loader.documentLoader()->initialScrollState().wasScrolledByUser = false;
    loader.restoreScrollPositionAndViewState();

    // Expect that both scroll and scale were restored.
    EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
    EXPECT_EQ(200, webViewImpl->mainFrameImpl()->scrollOffset().height);
}
TEST_F(ScrollingCoordinatorTest, fastFractionalScrollingDiv)
{
    registerMockedHttpURLLoad("fractional-scroll-div.html");
    navigateTo(m_baseURL + "fractional-scroll-div.html");
    forceFullCompositingUpdate();

    Document* document = frame()->document();
    Element* scrollableElement = document->getElementById("scroller");
    ASSERT(scrollableElement);

    scrollableElement->setScrollTop(1.0);
    scrollableElement->setScrollLeft(1.0);
    forceFullCompositingUpdate();

    // Make sure the fractional scroll offset change 1.0 -> 1.2 gets propagated
    // to compositor.
    scrollableElement->setScrollTop(1.2);
    scrollableElement->setScrollLeft(1.2);
    forceFullCompositingUpdate();

    LayoutObject* layoutObject = scrollableElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    LayoutBox* box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->usesCompositedScrolling());
    CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
    ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    ASSERT(compositedLayerMapping->scrollingContentsLayer());
    WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    ASSERT_TRUE(webScrollLayer);
    ASSERT_NEAR(1.2, webScrollLayer->scrollPositionDouble().x, 0.01);
    ASSERT_NEAR(1.2, webScrollLayer->scrollPositionDouble().y, 0.01);
}
TEST_F(ProgrammaticScrollTest, RestoreScrollPositionAndViewStateWithoutScale)
{
    registerMockedHttpURLLoad("long_scroll.html");

    FrameTestHelpers::WebViewHelper webViewHelper;
    WebView* webView = webViewHelper.initializeAndLoad(m_baseURL + "long_scroll.html", true, 0, 0);
    webView->resize(WebSize(1000, 1000));
    webView->updateAllLifecyclePhases();

    WebViewImpl* webViewImpl = toWebViewImpl(webView);
    FrameLoader& loader = webViewImpl->mainFrameImpl()->frame()->loader();
    loader.setLoadType(FrameLoadTypeBackForward);

    webViewImpl->setPageScaleFactor(3.0f);
    webViewImpl->mainFrame()->setScrollOffset(WebSize(0, 500));
    loader.documentLoader()->initialScrollState().wasScrolledByUser = false;
    loader.currentItem()->setPageScaleFactor(0);
    loader.currentItem()->setScrollPoint(WebPoint(0, 400));

    // FrameLoader::restoreScrollPositionAndViewState flows differently if scale is zero.
    loader.restoreScrollPositionAndViewState();

    // Expect that only the scroll position was restored.
    EXPECT_EQ(3.0f, webViewImpl->pageScaleFactor());
    EXPECT_EQ(400, webViewImpl->mainFrameImpl()->scrollOffset().height);
}
TEST_P(CompositorWorkerTest, applyingMutationsMultipleElements) {
  registerMockedHttpURLLoad("compositor-proxy-basic.html");
  navigateTo(m_baseURL + "compositor-proxy-basic.html");

  Document* document = frame()->document();

  {
    forceFullCompositingUpdate();

    Element* proxiedElement = document->getElementById("proxied-transform");
    WebLayer* proxiedLayer = webLayerFromElement(proxiedElement);
    EXPECT_TRUE(proxiedLayer->compositorMutableProperties() &
                CompositorMutableProperty::kTransform);
    EXPECT_FALSE(proxiedLayer->compositorMutableProperties() &
                 (CompositorMutableProperty::kScrollLeft |
                  CompositorMutableProperty::kScrollTop |
                  CompositorMutableProperty::kOpacity));
    EXPECT_TRUE(proxiedLayer->elementId());

    TransformationMatrix transformMatrix(11, 12, 13, 14, 21, 22, 23, 24, 31, 32,
                                         33, 34, 41, 42, 43, 44);
    CompositorMutation mutation;
    mutation.setTransform(TransformationMatrix::toSkMatrix44(transformMatrix));

    proxiedElement->updateFromCompositorMutation(mutation);

    forceFullCompositingUpdate();
    const String& cssValue =
        document->domWindow()
            ->getComputedStyle(proxiedElement, String())
            ->getPropertyValueInternal(CSSPropertyTransform);
    EXPECT_EQ(
        "matrix3d(11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, "
        "44)",
        cssValue);
  }
  {
    Element* proxiedElement = document->getElementById("proxied-opacity");
    WebLayer* proxiedLayer = webLayerFromElement(proxiedElement);
    EXPECT_TRUE(proxiedLayer->compositorMutableProperties() &
                CompositorMutableProperty::kOpacity);
    EXPECT_FALSE(proxiedLayer->compositorMutableProperties() &
                 (CompositorMutableProperty::kScrollLeft |
                  CompositorMutableProperty::kScrollTop |
                  CompositorMutableProperty::kTransform));
    EXPECT_TRUE(proxiedLayer->elementId());

    CompositorMutation mutation;
    mutation.setOpacity(0.5);

    proxiedElement->updateFromCompositorMutation(mutation);

    forceFullCompositingUpdate();
    const String& cssValue = document->domWindow()
                                 ->getComputedStyle(proxiedElement, String())
                                 ->getPropertyValueInternal(CSSPropertyOpacity);
    EXPECT_EQ("0.5", cssValue);
  }
}
TEST_F(ScrollingCoordinatorTest, setupScrollbarLayerShouldNotCrash)
{
    registerMockedHttpURLLoad("setup_scrollbar_layer_crash.html");
    navigateTo(m_baseURL + "setup_scrollbar_layer_crash.html");
    forceFullCompositingUpdate();
    // This test document setup an iframe with scrollbars, then switch to
    // an empty document by javascript.
}
TEST_F(ScrollingCoordinatorTest, scrollEventHandler)
{
    registerMockedHttpURLLoad("scroll-event-handler.html");
    navigateTo(m_baseURL + "scroll-event-handler.html");
    forceFullCompositingUpdate();

    ASSERT_TRUE(webLayerTreeView()->haveScrollEventHandlers());
}
TEST_F(ScrollingCoordinatorTest, wheelEventHandlerBoth)
{
    registerMockedHttpURLLoad("wheel-event-handler-both.html");
    navigateTo(m_baseURL + "wheel-event-handler-both.html");
    forceFullCompositingUpdate();

    ASSERT_EQ(WebEventListenerProperties::BlockingAndPassive, webLayerTreeView()->eventListenerProperties(WebEventListenerClass::MouseWheel));
}
TEST_F(ScrollingCoordinatorTest, touchEventHandlerPassive)
{
    registerMockedHttpURLLoad("touch-event-handler-passive.html");
    navigateTo(m_baseURL + "touch-event-handler-passive.html");
    forceFullCompositingUpdate();

    ASSERT_EQ(WebEventListenerProperties::Passive, webLayerTreeView()->eventListenerProperties(WebEventListenerClass::Touch));
}
TEST_F(ScrollingCoordinatorTest, clippedBodyTest)
{
    registerMockedHttpURLLoad("clipped-body.html");
    navigateTo(m_baseURL + "clipped-body.html");
    forceFullCompositingUpdate();

    WebLayer* rootScrollLayer = getRootScrollLayer();
    ASSERT_EQ(0u, rootScrollLayer->nonFastScrollableRegion().size());
}
TEST_F(ScrollingCoordinatorTest, wheelEventHandler)
{
    registerMockedHttpURLLoad("wheel-event-handler.html");
    navigateTo(m_baseURL + "wheel-event-handler.html");
    forceFullCompositingUpdate();

    WebLayer* rootScrollLayer = getRootScrollLayer();
    ASSERT_TRUE(rootScrollLayer->haveWheelEventHandlers());
}
TEST_F(ScrollingCoordinatorTest, updateEventHandlersDuringTeardown)
{
    registerMockedHttpURLLoad("scroll-event-handler-window.html");
    navigateTo(m_baseURL + "scroll-event-handler-window.html");
    forceFullCompositingUpdate();

    // Simulate detaching the document from its DOM window. This should not
    // cause a crash when the WebViewImpl is closed by the test runner.
    frame()->document()->detach();
}
TEST_F(ScrollingCoordinatorTest, iframeScrolling)
{
    registerMockedHttpURLLoad("iframe-scrolling.html");
    registerMockedHttpURLLoad("iframe-scrolling-inner.html");
    navigateTo(m_baseURL + "iframe-scrolling.html");
    forceFullCompositingUpdate();

    // Verify the properties of the accelerated scrolling element starting from the LayoutObject
    // all the way to the WebLayer.
    Element* scrollableFrame = frame()->document()->getElementById("scrollable");
    ASSERT_TRUE(scrollableFrame);

    LayoutObject* layoutObject = scrollableFrame->layoutObject();
    ASSERT_TRUE(layoutObject);
    ASSERT_TRUE(layoutObject->isLayoutPart());

    LayoutPart* layoutPart = toLayoutPart(layoutObject);
    ASSERT_TRUE(layoutPart);
    ASSERT_TRUE(layoutPart->widget());
    ASSERT_TRUE(layoutPart->widget()->isFrameView());

    FrameView* innerFrameView = toFrameView(layoutPart->widget());
    LayoutView* innerLayoutView = innerFrameView->layoutView();
    ASSERT_TRUE(innerLayoutView);

    PaintLayerCompositor* innerCompositor = innerLayoutView->compositor();
    ASSERT_TRUE(innerCompositor->inCompositingMode());
    ASSERT_TRUE(innerCompositor->scrollLayer());

    GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
    ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());

    WebLayer* webScrollLayer = scrollLayer->platformLayer();
    ASSERT_TRUE(webScrollLayer->scrollable());

#if OS(ANDROID)
    // Now verify we've attached impl-side scrollbars onto the scrollbar layers
    ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar());
    ASSERT_TRUE(innerCompositor->layerForHorizontalScrollbar()->hasContentsLayer());
    ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar());
    ASSERT_TRUE(innerCompositor->layerForVerticalScrollbar()->hasContentsLayer());
#endif
}
TEST_F(ScrollingCoordinatorTest, overflowHidden)
{
    registerMockedHttpURLLoad("overflow-hidden.html");
    navigateTo(m_baseURL + "overflow-hidden.html");
    forceFullCompositingUpdate();

    // Verify the properties of the accelerated scrolling element starting from the LayoutObject
    // all the way to the WebLayer.
    Element* overflowElement = frame()->document()->getElementById("unscrollable-y");
    ASSERT(overflowElement);

    LayoutObject* layoutObject = overflowElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    ASSERT_TRUE(layoutObject->hasLayer());

    LayoutBox* box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->usesCompositedScrolling());
    ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());

    CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
    ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    ASSERT(compositedLayerMapping->scrollingContentsLayer());

    GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());

    WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    ASSERT_TRUE(webScrollLayer->scrollable());
    ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
    ASSERT_FALSE(webScrollLayer->userScrollableVertical());

    overflowElement = frame()->document()->getElementById("unscrollable-x");
    ASSERT(overflowElement);

    layoutObject = overflowElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    ASSERT_TRUE(layoutObject->hasLayer());

    box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->scrollableArea()->usesCompositedScrolling());
    ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());

    compositedLayerMapping = box->layer()->compositedLayerMapping();
    ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    ASSERT(compositedLayerMapping->scrollingContentsLayer());

    graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());

    webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    ASSERT_TRUE(webScrollLayer->scrollable());
    ASSERT_FALSE(webScrollLayer->userScrollableHorizontal());
    ASSERT_TRUE(webScrollLayer->userScrollableVertical());
}
TEST_F(ScrollingCoordinatorTest, rtlIframe)
{
    registerMockedHttpURLLoad("rtl-iframe.html");
    registerMockedHttpURLLoad("rtl-iframe-inner.html");
    navigateTo(m_baseURL + "rtl-iframe.html");
    forceFullCompositingUpdate();

    // Verify the properties of the accelerated scrolling element starting from the LayoutObject
    // all the way to the WebLayer.
    Element* scrollableFrame = frame()->document()->getElementById("scrollable");
    ASSERT_TRUE(scrollableFrame);

    LayoutObject* layoutObject = scrollableFrame->layoutObject();
    ASSERT_TRUE(layoutObject);
    ASSERT_TRUE(layoutObject->isLayoutPart());

    LayoutPart* layoutPart = toLayoutPart(layoutObject);
    ASSERT_TRUE(layoutPart);
    ASSERT_TRUE(layoutPart->widget());
    ASSERT_TRUE(layoutPart->widget()->isFrameView());

    FrameView* innerFrameView = toFrameView(layoutPart->widget());
    LayoutView* innerLayoutView = innerFrameView->layoutView();
    ASSERT_TRUE(innerLayoutView);

    PaintLayerCompositor* innerCompositor = innerLayoutView->compositor();
    ASSERT_TRUE(innerCompositor->inCompositingMode());
    ASSERT_TRUE(innerCompositor->scrollLayer());

    GraphicsLayer* scrollLayer = innerCompositor->scrollLayer();
    ASSERT_EQ(innerFrameView, scrollLayer->scrollableArea());

    WebLayer* webScrollLayer = scrollLayer->platformLayer();
    ASSERT_TRUE(webScrollLayer->scrollable());

    int expectedScrollPosition = 958 + (innerFrameView->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
    ASSERT_EQ(expectedScrollPosition, webScrollLayer->scrollPositionDouble().x);
}
TEST_F(ScrollingCoordinatorTest, fractionalScrollingNonLayerFixedPosition)
{
    registerMockedHttpURLLoad("fractional-scroll-fixed-position.html");
    navigateTo(m_baseURL + "fractional-scroll-fixed-position.html");
    // Prevent fixed-position element from getting its own layer.
    webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false);
    forceFullCompositingUpdate();

    FrameView* frameView = frame()->view();
    frameView->scrollTo(DoublePoint(1.5, 1.5));
    WebLayer* rootScrollLayer = getRootScrollLayer();
    // Scroll on main if there is non-composited fixed position element.
    // And the containing scroll layer should not get fractional scroll offset.
    ASSERT_TRUE(rootScrollLayer->shouldScrollOnMainThread());
    ASSERT_EQ(1.0, rootScrollLayer->scrollPositionDouble().x);
    ASSERT_EQ(1.0, rootScrollLayer->scrollPositionDouble().y);
    ASSERT_EQ(0.0, rootScrollLayer->position().x);
    ASSERT_EQ(0.0, rootScrollLayer->position().y);
}
TEST_P(CompositorWorkerTest, plumbingElementIdAndMutableProperties) {
  registerMockedHttpURLLoad("compositor-proxy-basic.html");
  navigateTo(m_baseURL + "compositor-proxy-basic.html");

  forceFullCompositingUpdate();

  Document* document = frame()->document();

  Element* tallElement = document->getElementById("tall");
  WebLayer* tallLayer = webLayerFromElement(tallElement);
  EXPECT_TRUE(!tallLayer);

  Element* proxiedElement = document->getElementById("proxied-transform");
  WebLayer* proxiedLayer = webLayerFromElement(proxiedElement);
  EXPECT_TRUE(proxiedLayer->compositorMutableProperties() &
              CompositorMutableProperty::kTransform);
  EXPECT_FALSE(proxiedLayer->compositorMutableProperties() &
               (CompositorMutableProperty::kScrollLeft |
                CompositorMutableProperty::kScrollTop |
                CompositorMutableProperty::kOpacity));
  EXPECT_TRUE(proxiedLayer->elementId());

  Element* scrollElement = document->getElementById("proxied-scroller");
  WebLayer* scrollLayer = scrollingWebLayerFromElement(scrollElement);
  EXPECT_TRUE(scrollLayer->compositorMutableProperties() &
              (CompositorMutableProperty::kScrollLeft |
               CompositorMutableProperty::kScrollTop));
  EXPECT_FALSE(scrollLayer->compositorMutableProperties() &
               (CompositorMutableProperty::kTransform |
                CompositorMutableProperty::kOpacity));
  EXPECT_TRUE(scrollLayer->elementId());

  WebLayer* rootScrollLayer = getRootScrollLayer();
  EXPECT_TRUE(rootScrollLayer->compositorMutableProperties() &
              (CompositorMutableProperty::kScrollLeft |
               CompositorMutableProperty::kScrollTop));
  EXPECT_FALSE(rootScrollLayer->compositorMutableProperties() &
               (CompositorMutableProperty::kTransform |
                CompositorMutableProperty::kOpacity));

  EXPECT_TRUE(rootScrollLayer->elementId());
}
TEST_F(ScrollingCoordinatorTest, FixedPositionLosingBackingShouldTriggerMainThreadScroll)
{
    webViewImpl()->settings()->setPreferCompositingToLCDTextEnabled(false);
    registerMockedHttpURLLoad("fixed-position-losing-backing.html");
    navigateTo(m_baseURL + "fixed-position-losing-backing.html");
    forceFullCompositingUpdate();

    WebLayer* scrollLayer = frame()->page()->deprecatedLocalMainFrame()->view()->layerForScrolling()->platformLayer();
    Document* document = frame()->document();
    Element* fixedPos = document->getElementById("fixed");

    EXPECT_TRUE(static_cast<LayoutBoxModelObject*>(fixedPos->layoutObject())->layer()->hasCompositedLayerMapping());
    EXPECT_FALSE(scrollLayer->shouldScrollOnMainThread());

    fixedPos->setInlineStyleProperty(CSSPropertyTransform, CSSValueNone);
    forceFullCompositingUpdate();

    EXPECT_FALSE(static_cast<LayoutBoxModelObject*>(fixedPos->layoutObject())->layer()->hasCompositedLayerMapping());
    EXPECT_TRUE(scrollLayer->shouldScrollOnMainThread());
}
TEST_F(ScrollingCoordinatorTest, scrollbarsForceMainThreadOrHaveWebScrollbarLayer)
{
    registerMockedHttpURLLoad("trivial-scroller.html");
    navigateTo(m_baseURL + "trivial-scroller.html");
    forceFullCompositingUpdate();

    Document* document = frame()->document();
    Element* scrollableElement = document->getElementById("scroller");
    ASSERT(scrollableElement);

    LayoutObject* layoutObject = scrollableElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    LayoutBox* box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->usesCompositedScrolling());
    CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
    GraphicsLayer* scrollbarGraphicsLayer = compositedLayerMapping->layerForVerticalScrollbar();
    ASSERT_TRUE(scrollbarGraphicsLayer);

    bool hasWebScrollbarLayer = !scrollbarGraphicsLayer->drawsContent();
    ASSERT_TRUE(hasWebScrollbarLayer || scrollbarGraphicsLayer->platformLayer()->shouldScrollOnMainThread());
}
TEST_F(ScrollingCoordinatorTest, overflowScrolling)
{
    registerMockedHttpURLLoad("overflow-scrolling.html");
    navigateTo(m_baseURL + "overflow-scrolling.html");
    forceFullCompositingUpdate();

    // Verify the properties of the accelerated scrolling element starting from the LayoutObject
    // all the way to the WebLayer.
    Element* scrollableElement = frame()->document()->getElementById("scrollable");
    ASSERT(scrollableElement);

    LayoutObject* layoutObject = scrollableElement->layoutObject();
    ASSERT_TRUE(layoutObject->isBox());
    ASSERT_TRUE(layoutObject->hasLayer());

    LayoutBox* box = toLayoutBox(layoutObject);
    ASSERT_TRUE(box->usesCompositedScrolling());
    ASSERT_EQ(PaintsIntoOwnBacking, box->layer()->compositingState());

    CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping();
    ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer());
    ASSERT(compositedLayerMapping->scrollingContentsLayer());

    GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
    ASSERT_EQ(box->layer()->scrollableArea(), graphicsLayer->scrollableArea());

    WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer();
    ASSERT_TRUE(webScrollLayer->scrollable());
    ASSERT_TRUE(webScrollLayer->userScrollableHorizontal());
    ASSERT_TRUE(webScrollLayer->userScrollableVertical());

#if OS(ANDROID)
    // Now verify we've attached impl-side scrollbars onto the scrollbar layers
    ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar());
    ASSERT_TRUE(compositedLayerMapping->layerForHorizontalScrollbar()->hasContentsLayer());
    ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar());
    ASSERT_TRUE(compositedLayerMapping->layerForVerticalScrollbar()->hasContentsLayer());
#endif
}
TEST_F(ScrollingCoordinatorTest, setupScrollbarLayerShouldSetScrollLayerOpaque)
#endif
{
    registerMockedHttpURLLoad("wide_document.html");
    navigateTo(m_baseURL + "wide_document.html");
    forceFullCompositingUpdate();

    FrameView* frameView = frame()->view();
    ASSERT_TRUE(frameView);

    GraphicsLayer* scrollbarGraphicsLayer = frameView->layerForHorizontalScrollbar();
    ASSERT_TRUE(scrollbarGraphicsLayer);

    WebLayer* platformLayer = scrollbarGraphicsLayer->platformLayer();
    ASSERT_TRUE(platformLayer);

    WebLayer* contentsLayer = scrollbarGraphicsLayer->contentsLayer();
    ASSERT_TRUE(contentsLayer);

    // After scrollableAreaScrollbarLayerDidChange,
    // if the main frame's scrollbarLayer is opaque,
    // contentsLayer should be opaque too.
    ASSERT_EQ(platformLayer->opaque(), contentsLayer->opaque());
}
TEST_P(CompositorWorkerTest, applyingMutationsMultipleProperties) {
  registerMockedHttpURLLoad("compositor-proxy-basic.html");
  navigateTo(m_baseURL + "compositor-proxy-basic.html");

  Document* document = frame()->document();

  forceFullCompositingUpdate();

  Element* proxiedElement =
      document->getElementById("proxied-transform-and-opacity");
  WebLayer* proxiedLayer = webLayerFromElement(proxiedElement);
  EXPECT_TRUE(proxiedLayer->compositorMutableProperties() &
              CompositorMutableProperty::kTransform);
  EXPECT_TRUE(proxiedLayer->compositorMutableProperties() &
              CompositorMutableProperty::kOpacity);
  EXPECT_FALSE(proxiedLayer->compositorMutableProperties() &
               (CompositorMutableProperty::kScrollLeft |
                CompositorMutableProperty::kScrollTop));
  EXPECT_TRUE(proxiedLayer->elementId());

  TransformationMatrix transformMatrix(11, 12, 13, 14, 21, 22, 23, 24, 31, 32,
                                       33, 34, 41, 42, 43, 44);
  std::unique_ptr<CompositorMutation> mutation =
      wrapUnique(new CompositorMutation);
  mutation->setTransform(TransformationMatrix::toSkMatrix44(transformMatrix));
  mutation->setOpacity(0.5);

  proxiedElement->updateFromCompositorMutation(*mutation);
  {
    const String& transformValue =
        document->domWindow()
            ->getComputedStyle(proxiedElement, String())
            ->getPropertyValueInternal(CSSPropertyTransform);
    EXPECT_EQ(
        "matrix3d(11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, "
        "44)",
        transformValue);

    const String& opacityValue =
        document->domWindow()
            ->getComputedStyle(proxiedElement, String())
            ->getPropertyValueInternal(CSSPropertyOpacity);
    EXPECT_EQ("0.5", opacityValue);
  }

  // Verify that updating one property does not impact others
  mutation = wrapUnique(new CompositorMutation);
  mutation->setOpacity(0.8);

  proxiedElement->updateFromCompositorMutation(*mutation);
  {
    const String& transformValue =
        document->domWindow()
            ->getComputedStyle(proxiedElement, String())
            ->getPropertyValueInternal(CSSPropertyTransform);
    EXPECT_EQ(
        "matrix3d(11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, "
        "44)",
        transformValue);

    const String& opacityValue =
        document->domWindow()
            ->getComputedStyle(proxiedElement, String())
            ->getPropertyValueInternal(CSSPropertyOpacity);
    EXPECT_EQ("0.8", opacityValue);
  }
}
TEST_F(ScrollingCoordinatorTest, fastScrollingForFixedPosition)
{
    registerMockedHttpURLLoad("fixed-position.html");
    navigateTo(m_baseURL + "fixed-position.html");
    forceFullCompositingUpdate();

    // Fixed position should not fall back to main thread scrolling.
    WebLayer* rootScrollLayer = getRootScrollLayer();
    ASSERT_FALSE(rootScrollLayer->shouldScrollOnMainThread());

    Document* document = frame()->document();
    {
        Element* element = document->getElementById("div-tl");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    }
    {
        Element* element = document->getElementById("div-tr");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    }
    {
        Element* element = document->getElementById("div-bl");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    }
    {
        Element* element = document->getElementById("div-br");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    }
    {
        Element* element = document->getElementById("span-tl");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(!constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    }
    {
        Element* element = document->getElementById("span-tr");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(constraint.isFixedToRightEdge && !constraint.isFixedToBottomEdge);
    }
    {
        Element* element = document->getElementById("span-bl");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(!constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    }
    {
        Element* element = document->getElementById("span-br");
        ASSERT_TRUE(element);
        WebLayer* layer = webLayerFromElement(element);
        ASSERT_TRUE(layer);
        WebLayerPositionConstraint constraint = layer->positionConstraint();
        ASSERT_TRUE(constraint.isFixedPosition);
        ASSERT_TRUE(constraint.isFixedToRightEdge && constraint.isFixedToBottomEdge);
    }
}