#include "RuntimeEnabledFeatures.h"
#include "core/dom/Document.h"
+#include "core/dom/FullscreenElementStack.h"
#include "core/dom/Node.h"
#include "core/dom/WheelController.h"
-#include "core/html/HTMLElement.h"
-#include "core/frame/Frame.h"
+#include "core/frame/EventHandlerRegistry.h"
#include "core/frame/FrameView.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
+#include "core/html/HTMLElement.h"
#include "core/page/Page.h"
-#include "core/page/Settings.h"
-#include "core/platform/ScrollAnimator.h"
-#include "core/platform/ScrollbarTheme.h"
-#include "core/platform/chromium/support/WebScrollbarImpl.h"
-#include "core/platform/chromium/support/WebScrollbarThemeGeometryNative.h"
-#include "core/platform/graphics/GraphicsLayer.h"
+#include "core/plugins/PluginView.h"
+#include "core/rendering/RenderGeometryMap.h"
+#include "core/rendering/RenderView.h"
+#include "core/rendering/compositing/CompositedLayerMapping.h"
+#include "core/rendering/compositing/RenderLayerCompositor.h"
#include "platform/TraceEvent.h"
+#include "platform/exported/WebScrollbarImpl.h"
+#include "platform/exported/WebScrollbarThemeGeometryNative.h"
#include "platform/geometry/Region.h"
#include "platform/geometry/TransformState.h"
+#include "platform/graphics/GraphicsLayer.h"
#if OS(MACOSX)
-#include "core/platform/mac/ScrollAnimatorMac.h"
+#include "platform/mac/ScrollAnimatorMac.h"
#endif
-#include "core/plugins/PluginView.h"
-#include "core/rendering/CompositedLayerMapping.h"
-#include "core/rendering/RenderGeometryMap.h"
-#include "core/rendering/RenderLayerCompositor.h"
-#include "core/rendering/RenderView.h"
-#include "platform/geometry/IntRect.h"
+#include "platform/scroll/ScrollAnimator.h"
+#include "platform/scroll/ScrollbarTheme.h"
#include "public/platform/Platform.h"
#include "public/platform/WebCompositorSupport.h"
#include "public/platform/WebLayerPositionConstraint.h"
#include "public/platform/WebScrollbarThemePainter.h"
#include "wtf/text/StringBuilder.h"
-using WebKit::WebLayer;
-using WebKit::WebLayerPositionConstraint;
-using WebKit::WebRect;
-using WebKit::WebScrollbarLayer;
-using WebKit::WebVector;
+using blink::WebLayer;
+using blink::WebLayerPositionConstraint;
+using blink::WebRect;
+using blink::WebScrollbarLayer;
+using blink::WebVector;
+namespace {
-namespace WebCore {
-
-static WebLayer* scrollingWebLayerForGraphicsLayer(GraphicsLayer* layer)
+WebLayer* toWebLayer(WebCore::GraphicsLayer* layer)
{
- return layer->platformLayer();
+ return layer ? layer->platformLayer() : 0;
}
-WebLayer* ScrollingCoordinator::scrollingWebLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
- GraphicsLayer* graphicsLayer = scrollLayerForScrollableArea(scrollableArea);
- return graphicsLayer ? scrollingWebLayerForGraphicsLayer(graphicsLayer) : 0;
-}
+} // namespace
-PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
+namespace WebCore {
+
+PassOwnPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
{
- return adoptRef(new ScrollingCoordinator(page));
+ return adoptPtr(new ScrollingCoordinator(page));
}
ScrollingCoordinator::ScrollingCoordinator(Page* page)
: m_page(page)
, m_scrollGestureRegionIsDirty(false)
, m_touchEventTargetRectsAreDirty(false)
+ , m_shouldScrollOnMainThreadDirty(false)
+ , m_wasFrameScrollable(false)
+ , m_lastMainThreadScrollingReasons(0)
{
}
ScrollingCoordinator::~ScrollingCoordinator()
{
- ASSERT(!m_page);
- for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
- GraphicsLayer::unregisterContentsLayer(it->value->layer());
- for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
- GraphicsLayer::unregisterContentsLayer(it->value->layer());
-
}
bool ScrollingCoordinator::touchHitTestingEnabled() const
void ScrollingCoordinator::setShouldHandleScrollGestureOnMainThreadRegion(const Region& region)
{
- if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view())) {
+ if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
Vector<IntRect> rects = region.rects();
WebVector<WebRect> webRects(rects.size());
for (size_t i = 0; i < rects.size(); ++i)
void ScrollingCoordinator::notifyLayoutUpdated()
{
- // These computations need to happen after compositing is updated.
m_scrollGestureRegionIsDirty = true;
m_touchEventTargetRectsAreDirty = true;
+ m_shouldScrollOnMainThreadDirty = true;
}
void ScrollingCoordinator::updateAfterCompositingChange()
m_touchEventTargetRectsAreDirty = false;
}
+ FrameView* frameView = m_page->mainFrame()->view();
+ bool frameIsScrollable = frameView && frameView->isScrollable();
+ if (m_shouldScrollOnMainThreadDirty || m_wasFrameScrollable != frameIsScrollable) {
+ setShouldUpdateScrollLayerPositionOnMainThread(mainThreadScrollingReasons());
+ m_shouldScrollOnMainThreadDirty = false;
+ }
+ m_wasFrameScrollable = frameIsScrollable;
+
+ // The mainFrame view doesn't get included in the FrameTree below, so we
+ // update its size separately.
+ if (WebLayer* scrollingWebLayer = frameView ? toWebLayer(frameView->layerForScrolling()) : 0) {
+ scrollingWebLayer->setBounds(frameView->contentsSize());
+ // If there is a fullscreen element, set the scroll clip layer to 0 so main frame won't scroll.
+ Element* fullscreenElement = FullscreenElementStack::fullscreenElementFrom(*(m_page->mainFrame()->document()));
+ if (fullscreenElement)
+ scrollingWebLayer->setScrollClipLayer(0);
+ else
+ scrollingWebLayer->setScrollClipLayer(toWebLayer(frameView->layerForContainer()));
+ }
+
const FrameTree& tree = m_page->mainFrame()->tree();
- for (const Frame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
- if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(child->view()))
+ for (const LocalFrame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
+ if (WebLayer* scrollLayer = toWebLayer(child->view()->layerForScrolling()))
scrollLayer->setBounds(child->view()->contentsSize());
}
}
void ScrollingCoordinator::setLayerIsContainerForFixedPositionLayers(GraphicsLayer* layer, bool enable)
{
- if (WebLayer* scrollableLayer = scrollingWebLayerForGraphicsLayer(layer))
+ if (WebLayer* scrollableLayer = toWebLayer(layer))
scrollableLayer->setIsContainerForFixedPositionLayers(enable);
}
static void clearPositionConstraintExceptForLayer(GraphicsLayer* layer, GraphicsLayer* except)
{
- if (layer && layer != except && scrollingWebLayerForGraphicsLayer(layer))
- scrollingWebLayerForGraphicsLayer(layer)->setPositionConstraint(WebLayerPositionConstraint());
+ if (layer && layer != except && toWebLayer(layer))
+ toWebLayer(layer)->setPositionConstraint(WebLayerPositionConstraint());
}
static WebLayerPositionConstraint computePositionConstraint(const RenderLayer* layer)
{
- ASSERT(layer->compositedLayerMapping());
+ ASSERT(layer->hasCompositedLayerMapping());
do {
if (layer->renderer()->style()->position() == FixedPosition) {
const RenderObject* fixedPositionObject = layer->renderer();
// Composited layers that inherit a fixed position state will be positioned with respect to the nearest compositedLayerMapping's GraphicsLayer.
// So, once we find a layer that has its own compositedLayerMapping, we can stop searching for a fixed position RenderObject.
- } while (layer && layer->compositedLayerMapping());
+ } while (layer && !layer->hasCompositedLayerMapping());
return WebLayerPositionConstraint();
}
void ScrollingCoordinator::updateLayerPositionConstraint(RenderLayer* layer)
{
- ASSERT(layer->compositedLayerMapping());
- CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping();
- GraphicsLayer* mainLayer = compositedLayerMapping->childForSuperlayers();
+ ASSERT(layer->hasCompositedLayerMapping());
+ CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping();
+ GraphicsLayer* mainLayer = compositedLayerMapping->localRootForOwningLayer();
// Avoid unnecessary commits
clearPositionConstraintExceptForLayer(compositedLayerMapping->ancestorClippingLayer(), mainLayer);
clearPositionConstraintExceptForLayer(compositedLayerMapping->mainGraphicsLayer(), mainLayer);
- if (WebLayer* scrollableLayer = scrollingWebLayerForGraphicsLayer(mainLayer))
+ if (WebLayer* scrollableLayer = toWebLayer(mainLayer))
scrollableLayer->setPositionConstraint(computePositionConstraint(layer));
}
static PassOwnPtr<WebScrollbarLayer> createScrollbarLayer(Scrollbar* scrollbar)
{
ScrollbarTheme* theme = scrollbar->theme();
- WebKit::WebScrollbarThemePainter painter(theme, scrollbar);
- OwnPtr<WebKit::WebScrollbarThemeGeometry> geometry(WebKit::WebScrollbarThemeGeometryNative::create(theme));
+ blink::WebScrollbarThemePainter painter(theme, scrollbar);
+ OwnPtr<blink::WebScrollbarThemeGeometry> geometry(blink::WebScrollbarThemeGeometryNative::create(theme));
- OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createScrollbarLayer(new WebKit::WebScrollbarImpl(scrollbar), painter, geometry.leakPtr()));
+ OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(blink::Platform::current()->compositorSupport()->createScrollbarLayer(new blink::WebScrollbarImpl(scrollbar), painter, geometry.leakPtr()));
GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
return scrollbarLayer.release();
}
-PassOwnPtr<WebScrollbarLayer> ScrollingCoordinator::createSolidColorScrollbarLayer(ScrollbarOrientation orientation, int thumbThickness, bool isLeftSideVerticalScrollbar)
+PassOwnPtr<WebScrollbarLayer> ScrollingCoordinator::createSolidColorScrollbarLayer(ScrollbarOrientation orientation, int thumbThickness, int trackStart, bool isLeftSideVerticalScrollbar)
{
- WebKit::WebScrollbar::Orientation webOrientation = (orientation == HorizontalScrollbar) ? WebKit::WebScrollbar::Horizontal : WebKit::WebScrollbar::Vertical;
- OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createSolidColorScrollbarLayer(webOrientation, thumbThickness, isLeftSideVerticalScrollbar));
+ blink::WebScrollbar::Orientation webOrientation = (orientation == HorizontalScrollbar) ? blink::WebScrollbar::Horizontal : blink::WebScrollbar::Vertical;
+ OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(blink::Platform::current()->compositorSupport()->createSolidColorScrollbarLayer(webOrientation, thumbThickness, trackStart, isLeftSideVerticalScrollbar));
GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
return scrollbarLayer.release();
}
scrollbarGraphicsLayer->setDrawsContent(true);
}
-static void setupScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer, WebScrollbarLayer* scrollbarLayer, WebLayer* scrollLayer)
+static void setupScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer, WebScrollbarLayer* scrollbarLayer, WebLayer* scrollLayer, WebLayer* containerLayer)
{
ASSERT(scrollbarGraphicsLayer);
ASSERT(scrollbarLayer);
return;
}
scrollbarLayer->setScrollLayer(scrollLayer);
+ scrollbarLayer->setClipLayer(containerLayer);
scrollbarGraphicsLayer->setContentsToPlatformLayer(scrollbarLayer->layer());
scrollbarGraphicsLayer->setDrawsContent(false);
}
-WebScrollbarLayer* ScrollingCoordinator::addWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, PassOwnPtr<WebKit::WebScrollbarLayer> scrollbarLayer)
+WebScrollbarLayer* ScrollingCoordinator::addWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, PassOwnPtr<blink::WebScrollbarLayer> scrollbarLayer)
{
ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
- return scrollbars.add(scrollableArea, scrollbarLayer).iterator->value.get();
+ return scrollbars.add(scrollableArea, scrollbarLayer).storedValue->value.get();
}
WebScrollbarLayer* ScrollingCoordinator::getWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
if (!isMainFrame && platformSupportsMainFrameOnly)
return;
- GraphicsLayer* scrollbarGraphicsLayer = orientation == HorizontalScrollbar ? horizontalScrollbarLayerForScrollableArea(scrollableArea) : verticalScrollbarLayerForScrollableArea(scrollableArea);
+ GraphicsLayer* scrollbarGraphicsLayer = orientation == HorizontalScrollbar
+ ? scrollableArea->layerForHorizontalScrollbar()
+ : scrollableArea->layerForVerticalScrollbar();
+
if (scrollbarGraphicsLayer) {
Scrollbar* scrollbar = orientation == HorizontalScrollbar ? scrollableArea->horizontalScrollbar() : scrollableArea->verticalScrollbar();
if (scrollbar->isCustomScrollbar()) {
OwnPtr<WebScrollbarLayer> webScrollbarLayer;
if (settings->useSolidColorScrollbars()) {
ASSERT(RuntimeEnabledFeatures::overlayScrollbarsEnabled());
- webScrollbarLayer = createSolidColorScrollbarLayer(orientation, scrollbar->theme()->thumbThickness(scrollbar), scrollableArea->shouldPlaceVerticalScrollbarOnLeft());
+ webScrollbarLayer = createSolidColorScrollbarLayer(orientation, scrollbar->theme()->thumbThickness(scrollbar), scrollbar->theme()->trackPosition(scrollbar), scrollableArea->shouldPlaceVerticalScrollbarOnLeft());
} else {
webScrollbarLayer = createScrollbarLayer(scrollbar);
}
scrollbarGraphicsLayer->setContentsOpaque(isMainFrame && isOpaqueScrollbar);
scrollbarLayer->layer()->setOpaque(scrollbarGraphicsLayer->contentsOpaque());
- setupScrollbarLayer(scrollbarGraphicsLayer, scrollbarLayer, scrollingWebLayerForScrollableArea(scrollableArea));
+ WebLayer* scrollLayer = toWebLayer(scrollableArea->layerForScrolling());
+ WebLayer* containerLayer = toWebLayer(scrollableArea->layerForContainer());
+ setupScrollbarLayer(scrollbarGraphicsLayer, scrollbarLayer, scrollLayer, containerLayer);
} else
removeWebScrollbarLayer(scrollableArea, orientation);
}
bool ScrollingCoordinator::scrollableAreaScrollLayerDidChange(ScrollableArea* scrollableArea)
{
- GraphicsLayer* scrollLayer = scrollLayerForScrollableArea(scrollableArea);
+ GraphicsLayer* scrollLayer = scrollableArea->layerForScrolling();
+
if (scrollLayer) {
- bool isMainFrame = isForMainFrame(scrollableArea);
- scrollLayer->setScrollableArea(scrollableArea, isMainFrame);
+ ASSERT(m_page);
+ // With pinch virtual viewport we no longer need to special case the main frame.
+ bool pinchVirtualViewportEnabled = m_page->settings().pinchVirtualViewportEnabled();
+ bool layerScrollShouldFireGraphicsLayerDidScroll = isForMainFrame(scrollableArea) && !pinchVirtualViewportEnabled;
+ scrollLayer->setScrollableArea(scrollableArea, layerScrollShouldFireGraphicsLayerDidScroll);
}
- WebLayer* webLayer = scrollingWebLayerForScrollableArea(scrollableArea);
+ WebLayer* webLayer = toWebLayer(scrollableArea->layerForScrolling());
+ WebLayer* containerLayer = toWebLayer(scrollableArea->layerForContainer());
if (webLayer) {
- webLayer->setScrollable(true);
+ webLayer->setScrollClipLayer(containerLayer);
webLayer->setScrollPosition(IntPoint(scrollableArea->scrollPosition() - scrollableArea->minimumScrollPosition()));
- webLayer->setMaxScrollPosition(IntSize(scrollableArea->scrollSize(HorizontalScrollbar), scrollableArea->scrollSize(VerticalScrollbar)));
+ webLayer->setBounds(scrollableArea->contentsSize());
bool canScrollX = scrollableArea->userInputScrollable(HorizontalScrollbar);
bool canScrollY = scrollableArea->userInputScrollable(VerticalScrollbar);
webLayer->setUserScrollable(canScrollX, canScrollY);
}
if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, HorizontalScrollbar)) {
- GraphicsLayer* horizontalScrollbarLayer = horizontalScrollbarLayerForScrollableArea(scrollableArea);
+ GraphicsLayer* horizontalScrollbarLayer = scrollableArea->layerForHorizontalScrollbar();
if (horizontalScrollbarLayer)
- setupScrollbarLayer(horizontalScrollbarLayer, scrollbarLayer, webLayer);
+ setupScrollbarLayer(horizontalScrollbarLayer, scrollbarLayer, webLayer, containerLayer);
}
if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, VerticalScrollbar)) {
- GraphicsLayer* verticalScrollbarLayer = verticalScrollbarLayerForScrollableArea(scrollableArea);
+ GraphicsLayer* verticalScrollbarLayer = scrollableArea->layerForVerticalScrollbar();
if (verticalScrollbarLayer)
- setupScrollbarLayer(verticalScrollbarLayer, scrollbarLayer, webLayer);
+ setupScrollbarLayer(verticalScrollbarLayer, scrollbarLayer, webLayer, containerLayer);
}
return !!webLayer;
}
+typedef WTF::HashMap<const GraphicsLayer*, Vector<LayoutRect> > GraphicsLayerHitTestRects;
+
// In order to do a DFS cross-frame walk of the RenderLayer tree, we need to know which
// RenderLayers have child frames inside of them. This computes a mapping for the
// current frame which we can consult while walking the layers of that frame.
// Whenever we descend into a new frame, a new map will be created.
-typedef HashMap<const RenderLayer*, Vector<const Frame*> > LayerFrameMap;
-static void makeLayerChildFrameMap(const Frame* currentFrame, LayerFrameMap* map)
+typedef HashMap<const RenderLayer*, Vector<const LocalFrame*> > LayerFrameMap;
+static void makeLayerChildFrameMap(const LocalFrame* currentFrame, LayerFrameMap* map)
{
map->clear();
const FrameTree& tree = currentFrame->tree();
- for (const Frame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
- const RenderLayer* containingLayer = child->ownerRenderer()->enclosingLayer();
+ for (const LocalFrame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
+ const RenderObject* ownerRenderer = child->ownerRenderer();
+ if (!ownerRenderer)
+ continue;
+ const RenderLayer* containingLayer = ownerRenderer->enclosingLayer();
LayerFrameMap::iterator iter = map->find(containingLayer);
if (iter == map->end())
- iter = map->add(containingLayer, Vector<const Frame*>()).iterator;
- iter->value.append(child);
+ map->add(containingLayer, Vector<const LocalFrame*>()).storedValue->value.append(child);
+ else
+ iter->value.append(child);
}
}
-static void convertLayerRectsToEnclosingCompositedLayerRecursive(
+// Return the enclosingCompositedLayerForRepaint for the given RenderLayer
+// including crossing frame boundaries.
+static const RenderLayer* enclosingCompositedLayer(const RenderLayer* layer)
+{
+ RenderLayer* compositedLayer = 0;
+ while (!compositedLayer) {
+ compositedLayer = layer->enclosingCompositingLayerForRepaint();
+ if (!compositedLayer) {
+ RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
+ if (!owner)
+ break;
+ layer = owner->enclosingLayer();
+ }
+ }
+ // Since this machinery is used only when accelerated compositing is enabled, we expect
+ // that every layer should have an enclosing composited layer.
+ ASSERT(compositedLayer);
+ return compositedLayer;
+}
+
+static void projectRectsToGraphicsLayerSpaceRecursive(
const RenderLayer* curLayer,
const LayerHitTestRects& layerRects,
- LayerHitTestRects& compositorRects,
+ GraphicsLayerHitTestRects& graphicsRects,
RenderGeometryMap& geometryMap,
HashSet<const RenderLayer*>& layersWithRects,
LayerFrameMap& layerChildFrameMap)
LayerHitTestRects::const_iterator layerIter = layerRects.find(curLayer);
if (layerIter != layerRects.end()) {
// Find the enclosing composited layer when it's in another document (for non-composited iframes).
- RenderLayer* compositedLayer = 0;
- for (const RenderLayer* layer = layerIter->key; !compositedLayer;) {
- compositedLayer = layer->enclosingCompositingLayerForRepaint();
- if (!compositedLayer) {
- RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
- if (!owner)
- break;
- layer = owner->enclosingLayer();
- }
- }
- if (!compositedLayer) {
- // Since this machinery is used only when accelerated compositing is enabled, we expect
- // that every layer should have an enclosing composited layer.
- ASSERT_NOT_REACHED();
+ const RenderLayer* compositedLayer = enclosingCompositedLayer(layerIter->key);
+ if (!compositedLayer)
return;
+
+ // Find the appropriate GraphicsLayer for the composited RenderLayer.
+ GraphicsLayer* graphicsLayer;
+ LayoutSize extraOffset;
+ if (compositedLayer->compositingState() == PaintsIntoGroupedBacking) {
+ graphicsLayer = compositedLayer->groupedMapping()->squashingLayer();
+ extraOffset = -compositedLayer->offsetFromSquashingLayerOrigin();
+ } else {
+ ASSERT(compositedLayer->hasCompositedLayerMapping());
+ CompositedLayerMappingPtr compositedLayerMapping = compositedLayer->compositedLayerMapping();
+ // The origin for the graphics layer does not have to be the same
+ // as the composited layer (e.g. when a child layer has negative
+ // offset and paints into this layer), so when projecting rects to
+ // graphics layer space they have to be offset by the origin for
+ // the composited layer.
+ extraOffset = compositedLayerMapping->contentOffsetInCompositingLayer();
+ // If the layer is using composited scrolling, then it's the contents that these
+ // rects apply to.
+ graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
+ if (!graphicsLayer)
+ graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
}
- LayerHitTestRects::iterator compIter = compositorRects.find(compositedLayer);
- if (compIter == compositorRects.end())
- compIter = compositorRects.add(compositedLayer, Vector<LayoutRect>()).iterator;
- // Transform each rect to the co-ordinate space of it's enclosing composited layer.
+ GraphicsLayerHitTestRects::iterator glIter = graphicsRects.find(graphicsLayer);
+ Vector<LayoutRect>* glRects;
+ if (glIter == graphicsRects.end())
+ glRects = &graphicsRects.add(graphicsLayer, Vector<LayoutRect>()).storedValue->value;
+ else
+ glRects = &glIter->value;
+ // Transform each rect to the co-ordinate space of the graphicsLayer.
for (size_t i = 0; i < layerIter->value.size(); ++i) {
LayoutRect rect = layerIter->value[i];
if (compositedLayer != curLayer) {
if (compositedLayer->renderer()->hasOverflowClip())
rect.move(compositedLayer->renderBox()->scrolledContentOffset());
}
- compIter->value.append(rect);
+ rect.move(extraOffset);
+ glRects->append(rect);
}
}
for (const RenderLayer* childLayer = curLayer->firstChild(); childLayer; childLayer = childLayer->nextSibling()) {
if (layersWithRects.contains(childLayer)) {
geometryMap.pushMappingsToAncestor(childLayer, curLayer);
- convertLayerRectsToEnclosingCompositedLayerRecursive(childLayer, layerRects, compositorRects, geometryMap, layersWithRects, layerChildFrameMap);
+ projectRectsToGraphicsLayerSpaceRecursive(childLayer, layerRects, graphicsRects, geometryMap, layersWithRects, layerChildFrameMap);
geometryMap.popMappingsToAncestor(curLayer);
}
}
LayerFrameMap::iterator mapIter = layerChildFrameMap.find(curLayer);
if (mapIter != layerChildFrameMap.end()) {
for (size_t i = 0; i < mapIter->value.size(); i++) {
- const Frame* childFrame = mapIter->value[i];
+ const LocalFrame* childFrame = mapIter->value[i];
const RenderLayer* childLayer = childFrame->view()->renderView()->layer();
if (layersWithRects.contains(childLayer)) {
LayerFrameMap newLayerChildFrameMap;
makeLayerChildFrameMap(childFrame, &newLayerChildFrameMap);
geometryMap.pushMappingsToAncestor(childLayer, curLayer);
- convertLayerRectsToEnclosingCompositedLayerRecursive(childLayer, layerRects, compositorRects, geometryMap, layersWithRects, newLayerChildFrameMap);
+ projectRectsToGraphicsLayerSpaceRecursive(childLayer, layerRects, graphicsRects, geometryMap, layersWithRects, newLayerChildFrameMap);
geometryMap.popMappingsToAncestor(curLayer);
}
}
}
}
-static void convertLayerRectsToEnclosingCompositedLayer(Frame* mainFrame, const LayerHitTestRects& layerRects, LayerHitTestRects& compositorRects)
+static void projectRectsToGraphicsLayerSpace(LocalFrame* mainFrame, const LayerHitTestRects& layerRects, GraphicsLayerHitTestRects& graphicsRects)
{
- TRACE_EVENT0("input", "ScrollingCoordinator::convertLayerRectsToEnclosingCompositedLayer");
+ TRACE_EVENT0("input", "ScrollingCoordinator::projectRectsToGraphicsLayerSpace");
bool touchHandlerInChildFrame = false;
// We have a set of rects per RenderLayer, we need to map them to their bounding boxes in their
MapCoordinatesFlags flags = UseTransforms;
if (touchHandlerInChildFrame)
flags |= TraverseDocumentBoundaries;
+ RenderLayer* rootLayer = mainFrame->contentRenderer()->layer();
RenderGeometryMap geometryMap(flags);
+ geometryMap.pushMappingsToAncestor(rootLayer, 0);
LayerFrameMap layerChildFrameMap;
makeLayerChildFrameMap(mainFrame, &layerChildFrameMap);
- convertLayerRectsToEnclosingCompositedLayerRecursive(mainFrame->contentRenderer()->layer(), layerRects, compositorRects, geometryMap, layersWithRects, layerChildFrameMap);
+ projectRectsToGraphicsLayerSpaceRecursive(rootLayer, layerRects, graphicsRects, geometryMap, layersWithRects, layerChildFrameMap);
}
void ScrollingCoordinator::updateTouchEventTargetRectsIfNeeded()
setTouchEventTargetRects(touchEventTargetRects);
}
+void ScrollingCoordinator::reset()
+{
+ for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
+ GraphicsLayer::unregisterContentsLayer(it->value->layer());
+ for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
+ GraphicsLayer::unregisterContentsLayer(it->value->layer());
+
+ m_horizontalScrollbars.clear();
+ m_verticalScrollbars.clear();
+ m_layersWithTouchRects.clear();
+ m_wasFrameScrollable = false;
+
+ // This is retained for testing.
+ m_lastMainThreadScrollingReasons = 0;
+ setShouldUpdateScrollLayerPositionOnMainThread(m_lastMainThreadScrollingReasons);
+}
+
// Note that in principle this could be called more often than computeTouchEventTargetRects, for
// example during a non-composited scroll (although that's not yet implemented - crbug.com/261307).
-void ScrollingCoordinator::setTouchEventTargetRects(const LayerHitTestRects& layerRects)
+void ScrollingCoordinator::setTouchEventTargetRects(LayerHitTestRects& layerRects)
{
TRACE_EVENT0("input", "ScrollingCoordinator::setTouchEventTargetRects");
- LayerHitTestRects compositorRects;
- convertLayerRectsToEnclosingCompositedLayer(m_page->mainFrame(), layerRects, compositorRects);
-
+ // Update the list of layers with touch hit rects.
HashSet<const RenderLayer*> oldLayersWithTouchRects;
m_layersWithTouchRects.swap(oldLayersWithTouchRects);
+ for (LayerHitTestRects::iterator it = layerRects.begin(); it != layerRects.end(); ++it) {
+ if (!it->value.isEmpty()) {
+ const RenderLayer* compositedLayer = enclosingCompositedLayer(it->key);
+ if (compositedLayer)
+ m_layersWithTouchRects.add(compositedLayer);
+ }
+ }
- for (LayerHitTestRects::const_iterator iter = compositorRects.begin(); iter != compositorRects.end(); ++iter) {
- const RenderLayer* layer = iter->key;
+ // Ensure we have an entry for each composited layer that previously had rects (so that old
+ // ones will get cleared out). Note that ideally we'd track this on GraphicsLayer instead of
+ // RenderLayer, but we have no good hook into the lifetime of a GraphicsLayer.
+ for (HashSet<const RenderLayer*>::iterator it = oldLayersWithTouchRects.begin(); it != oldLayersWithTouchRects.end(); ++it) {
+ if (!layerRects.contains(*it))
+ layerRects.add(*it, Vector<LayoutRect>());
+ }
+
+ GraphicsLayerHitTestRects graphicsLayerRects;
+ projectRectsToGraphicsLayerSpace(m_page->mainFrame(), layerRects, graphicsLayerRects);
+
+ for (GraphicsLayerHitTestRects::const_iterator iter = graphicsLayerRects.begin(); iter != graphicsLayerRects.end(); ++iter) {
+ const GraphicsLayer* graphicsLayer = iter->key;
WebVector<WebRect> webRects(iter->value.size());
for (size_t i = 0; i < iter->value.size(); ++i)
webRects[i] = enclosingIntRect(iter->value[i]);
- CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping();
- // If the layer is using composited scrolling, then it's the contents that these
- // rects apply to.
- GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
- if (!graphicsLayer)
- graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
graphicsLayer->platformLayer()->setTouchEventHandlerRegion(webRects);
- oldLayersWithTouchRects.remove(layer);
- m_layersWithTouchRects.add(layer);
- }
-
- // If there are any layers left that we haven't updated, clear them out.
- for (HashSet<const RenderLayer*>::iterator it = oldLayersWithTouchRects.begin(); it != oldLayersWithTouchRects.end(); ++it) {
- if (CompositedLayerMapping* compositedLayerMapping = (*it)->compositedLayerMapping()) {
- GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
- if (!graphicsLayer)
- graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
- graphicsLayer->platformLayer()->setTouchEventHandlerRegion(WebVector<WebRect>());
- }
}
}
-void ScrollingCoordinator::touchEventTargetRectsDidChange(const Document*)
+void ScrollingCoordinator::touchEventTargetRectsDidChange()
{
if (!touchHitTestingEnabled())
return;
// FIXME: scheduleAnimation() is just a method of forcing the compositor to realize that it
// needs to commit here. We should expose a cleaner API for this.
RenderView* renderView = m_page->mainFrame()->contentRenderer();
- if (renderView && renderView->compositor() && renderView->compositor()->inCompositingMode())
+ if (renderView && renderView->compositor() && renderView->compositor()->staleInCompositingMode())
m_page->mainFrame()->view()->scheduleAnimation();
m_touchEventTargetRectsAreDirty = true;
void ScrollingCoordinator::updateScrollParentForGraphicsLayer(GraphicsLayer* child, RenderLayer* parent)
{
WebLayer* scrollParentWebLayer = 0;
- if (parent && parent->compositedLayerMapping())
- scrollParentWebLayer = scrollingWebLayerForGraphicsLayer(parent->compositedLayerMapping()->parentForSublayers());
+ if (parent && parent->hasCompositedLayerMapping())
+ scrollParentWebLayer = toWebLayer(parent->compositedLayerMapping()->parentForSublayers());
child->setScrollParent(scrollParentWebLayer);
}
void ScrollingCoordinator::updateClipParentForGraphicsLayer(GraphicsLayer* child, RenderLayer* parent)
{
WebLayer* clipParentWebLayer = 0;
- if (parent && parent->compositedLayerMapping())
- clipParentWebLayer = scrollingWebLayerForGraphicsLayer(parent->compositedLayerMapping()->parentForSublayers());
+ if (parent && parent->hasCompositedLayerMapping())
+ clipParentWebLayer = toWebLayer(parent->compositedLayerMapping()->parentForSublayers());
child->setClipParent(clipParentWebLayer);
}
m_layersWithTouchRects.remove(layer);
}
-void ScrollingCoordinator::setWheelEventHandlerCount(unsigned count)
+void ScrollingCoordinator::updateHaveWheelEventHandlers()
{
- if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view()))
- scrollLayer->setHaveWheelEventHandlers(count > 0);
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
+ unsigned wheelEventHandlerCount = 0;
+
+ for (LocalFrame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
+ wheelEventHandlerCount += WheelController::from(*frame->document())->wheelEventHandlerCount();
+ }
+
+ scrollLayer->setHaveWheelEventHandlers(wheelEventHandlerCount);
+ }
}
-void ScrollingCoordinator::recomputeWheelEventHandlerCountForFrameView(FrameView* frameView)
+void ScrollingCoordinator::updateHaveScrollEventHandlers()
{
- UNUSED_PARAM(frameView);
- setWheelEventHandlerCount(computeCurrentWheelEventHandlerCount());
+ ASSERT(isMainThread());
+ ASSERT(m_page);
+
+ // Currently the compositor only cares whether there are scroll handlers anywhere on the page
+ // instead on a per-layer basis. We therefore only update this information for the root
+ // scrolling layer.
+ if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
+ bool haveHandlers = m_page->frameHost().eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::ScrollEvent);
+ scrollLayer->setHaveScrollEventHandlers(haveHandlers);
+ }
}
void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons reasons)
{
- if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view()))
+ if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
+ m_lastMainThreadScrollingReasons = reasons;
scrollLayer->setShouldScrollOnMainThread(reasons);
+ }
}
-void ScrollingCoordinator::pageDestroyed()
+void ScrollingCoordinator::willBeDestroyed()
{
ASSERT(m_page);
m_page = 0;
+ for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
+ GraphicsLayer::unregisterContentsLayer(it->value->layer());
+ for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
+ GraphicsLayer::unregisterContentsLayer(it->value->layer());
}
bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView) const
return renderView->usesCompositing();
}
-Region ScrollingCoordinator::computeShouldHandleScrollGestureOnMainThreadRegion(const Frame* frame, const IntPoint& frameLocation) const
+Region ScrollingCoordinator::computeShouldHandleScrollGestureOnMainThreadRegion(const LocalFrame* frame, const IntPoint& frameLocation) const
{
Region shouldHandleScrollGestureOnMainThreadRegion;
FrameView* frameView = frame->view();
}
const FrameTree& tree = frame->tree();
- for (Frame* subFrame = tree.firstChild(); subFrame; subFrame = subFrame->tree().nextSibling())
+ for (LocalFrame* subFrame = tree.firstChild(); subFrame; subFrame = subFrame->tree().nextSibling())
shouldHandleScrollGestureOnMainThreadRegion.unite(computeShouldHandleScrollGestureOnMainThreadRegion(subFrame, offset));
return shouldHandleScrollGestureOnMainThreadRegion;
if (targets->contains(ancestor))
hasTouchEventTargetAncestor = true;
}
- if (!hasTouchEventTargetAncestor)
+ if (!hasTouchEventTargetAncestor) {
+ // Walk up the tree to the outermost non-composited scrollable layer.
+ RenderLayer* enclosingNonCompositedScrollLayer = 0;
+ for (RenderLayer* parent = renderer->enclosingLayer(); parent && parent->compositingState() == NotComposited; parent = parent->parent()) {
+ if (parent->scrollsOverflow())
+ enclosingNonCompositedScrollLayer = parent;
+ }
+
+ // Report the whole non-composited scroll layer as a touch hit rect because any
+ // rects inside of it may move around relative to their enclosing composited layer
+ // without causing the rects to be recomputed. Non-composited scrolling occurs on
+ // the main thread, so we're not getting much benefit from compositor touch hit
+ // testing in this case anyway.
+ if (enclosingNonCompositedScrollLayer)
+ enclosingNonCompositedScrollLayer->computeSelfHitTestRects(rects);
+
renderer->computeLayerHitTestRects(rects);
+ }
}
}
accumulateDocumentTouchEventTargetRects(rects, document);
}
-unsigned ScrollingCoordinator::computeCurrentWheelEventHandlerCount()
-{
- unsigned wheelEventHandlerCount = 0;
-
- for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
- if (frame->document())
- wheelEventHandlerCount += WheelController::from(frame->document())->wheelEventHandlerCount();
- }
-
- return wheelEventHandlerCount;
-}
-
-void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView* frameView)
-{
- ASSERT(isMainThread());
- ASSERT(m_page);
-
- recomputeWheelEventHandlerCountForFrameView(frameView);
-}
-
void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* frameView)
{
ASSERT(isMainThread());
if (!coordinatesScrollingForFrameView(frameView))
return;
- updateShouldUpdateScrollLayerPositionOnMainThread();
+ m_shouldScrollOnMainThreadDirty = true;
}
void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView)
if (!coordinatesScrollingForFrameView(frameView))
return;
- updateShouldUpdateScrollLayerPositionOnMainThread();
-}
-
-GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
- return scrollableArea->layerForScrolling();
-}
-
-GraphicsLayer* ScrollingCoordinator::horizontalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
- return scrollableArea->layerForHorizontalScrollbar();
-}
-
-GraphicsLayer* ScrollingCoordinator::verticalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
- return scrollableArea->layerForVerticalScrollbar();
+ m_shouldScrollOnMainThreadDirty = true;
}
bool ScrollingCoordinator::isForMainFrame(ScrollableArea* scrollableArea) const
return scrollableArea == m_page->mainFrame()->view();
}
-GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameView)
-{
- RenderView* renderView = frameView->frame().contentRenderer();
- if (!renderView)
- return 0;
- return renderView->compositor()->scrollLayer();
-}
-
-GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView*)
-{
- return 0;
-}
-
void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
{
ASSERT(isMainThread());
return;
notifyLayoutUpdated();
- recomputeWheelEventHandlerCountForFrameView(frameView);
- updateShouldUpdateScrollLayerPositionOnMainThread();
+ updateHaveWheelEventHandlers();
+ updateHaveScrollEventHandlers();
}
#if OS(MACOSX)
MainThreadScrollingReasons ScrollingCoordinator::mainThreadScrollingReasons() const
{
+ // The main thread scrolling reasons are applicable to scrolls of the main
+ // frame. If it does not exist or if it is not scrollable, there is no
+ // reason to force main thread scrolling.
FrameView* frameView = m_page->mainFrame()->view();
if (!frameView)
return static_cast<MainThreadScrollingReasons>(0);
return mainThreadScrollingReasons;
}
-void ScrollingCoordinator::updateShouldUpdateScrollLayerPositionOnMainThread()
-{
- setShouldUpdateScrollLayerPositionOnMainThread(mainThreadScrollingReasons());
-}
-
String ScrollingCoordinator::mainThreadScrollingReasonsAsText(MainThreadScrollingReasons reasons)
{
StringBuilder stringBuilder;
String ScrollingCoordinator::mainThreadScrollingReasonsAsText() const
{
- return mainThreadScrollingReasonsAsText(mainThreadScrollingReasons());
+ ASSERT(m_page->mainFrame()->document()->lifecycle().state() >= DocumentLifecycle::CompositingClean);
+ return mainThreadScrollingReasonsAsText(m_lastMainThreadScrollingReasons);
+}
+
+bool ScrollingCoordinator::frameViewIsDirty() const
+{
+ FrameView* frameView = m_page->mainFrame()->view();
+ bool frameIsScrollable = frameView && frameView->isScrollable();
+ if (frameIsScrollable != m_wasFrameScrollable)
+ return true;
+
+ if (WebLayer* scrollLayer = frameView ? toWebLayer(frameView->layerForScrolling()) : 0)
+ return blink::WebSize(frameView->contentsSize()) != scrollLayer->bounds();
+ return false;
}
} // namespace WebCore