https://bugs.webkit.org/show_bug.cgi?id=144420
Reviewed by Tim Horton.
Source/WebCore:
Compute the non-fast-scrollable region in document coordinates, to make it easier
to reason about. Previously, it was document coordinates offset by top content inset.
* page/DebugPageOverlays.cpp:
(WebCore::MouseWheelRegionOverlay::updateRegion): Traverse all frames to compute the wheel
event handler region, mapping each to root view coords, and then mapping back into document
coords at the end.
(WebCore::NonFastScrollableRegionOverlay::updateRegion): No offset needed here; the
overlay and region are both document coordinates.
* page/FrameView.h: Make some mapping function overrides public, and expose widgetsInRenderTree().
* page/Page.cpp:
(WebCore::Page::nonFastScrollableRects): Remove frame argument.
* page/Page.h:
* page/PageOverlay.cpp:
(WebCore::PageOverlay::bounds):
(WebCore::PageOverlay::viewToOverlayOffset): Convenience function to map between
view and overlay coordinates.
* page/PageOverlay.h:
* page/scrolling/AsyncScrollingCoordinator.cpp: New computeNonFastScrollableRegion() signature.
(WebCore::AsyncScrollingCoordinator::updateNonFastScrollableRegion):
(WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated):
(WebCore::AsyncScrollingCoordinator::scrollingStateTreeAsText):
* page/scrolling/ScrollingCoordinator.cpp:
(WebCore::ScrollingCoordinator::absoluteNonFastScrollableRegionForFrame): This function
recurses on frames, computing an absolute (document-relative) region per frame. This
removes the confusing offsetting through top content inset.
Change how we get to plugins that want wheel events; we can't get from PluginViewBase
to renderers, so use FrameView's list of Widgets, and their RenderWidgets. This fixes
regions for transformed plugin-ins.
For subframes, we get a region in the subframe's document coords. Map to that sub-frame,
then to our frame, then to our document.
(WebCore::ScrollingCoordinator::absoluteNonFastScrollableRegion): Wrapper that hides
the recursive function.
(WebCore::ScrollingCoordinator::computeNonFastScrollableRegion): Deleted.
* page/scrolling/ScrollingCoordinator.h:
* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::shouldHandleWheelEventSynchronously): Map the event point
from view coordinates to document coordinates for testing against the non-fast region.
We previously assert that the root note is a FrameScrolling node.
* page/scrolling/ScrollingTreeFrameScrollingNode.cpp:
(WebCore::ScrollingTreeFrameScrollingNode::viewToContentsOffset): Similar to ScrollView::viewToContents()
for the scrolling tree.
* page/scrolling/ScrollingTreeFrameScrollingNode.h:
* testing/Internals.cpp:
(WebCore::Internals::nonFastScrollableRects): No need for frame arg.
LayoutTests:
We now report the non-fast region in document coordinates, so these two results change.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/top-content-inset-expected.txt:
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/top-content-inset-header-expected.txt:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183597
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2015-04-29 Simon Fraser <simon.fraser@apple.com>
+
+ Compute the non-fast-scrollable region in main-document coordinates
+ https://bugs.webkit.org/show_bug.cgi?id=144420
+
+ Reviewed by Tim Horton.
+
+ We now report the non-fast region in document coordinates, so these two results change.
+
+ * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/top-content-inset-expected.txt:
+ * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/top-content-inset-header-expected.txt:
+
2015-04-29 Joseph Pecoraro <pecoraro@apple.com>
NodeList has issues with Symbol and empty string
Wheel event rect:
-28, 110 - 128, 210
+28, 50 - 128, 150
Wheel event rect:
-28, 110 - 128, 210
+28, 50 - 128, 150
+2015-04-29 Simon Fraser <simon.fraser@apple.com>
+
+ Compute the non-fast-scrollable region in main-document coordinates
+ https://bugs.webkit.org/show_bug.cgi?id=144420
+
+ Reviewed by Tim Horton.
+
+ Compute the non-fast-scrollable region in document coordinates, to make it easier
+ to reason about. Previously, it was document coordinates offset by top content inset.
+
+ * page/DebugPageOverlays.cpp:
+ (WebCore::MouseWheelRegionOverlay::updateRegion): Traverse all frames to compute the wheel
+ event handler region, mapping each to root view coords, and then mapping back into document
+ coords at the end.
+ (WebCore::NonFastScrollableRegionOverlay::updateRegion): No offset needed here; the
+ overlay and region are both document coordinates.
+ * page/FrameView.h: Make some mapping function overrides public, and expose widgetsInRenderTree().
+ * page/Page.cpp:
+ (WebCore::Page::nonFastScrollableRects): Remove frame argument.
+ * page/Page.h:
+ * page/PageOverlay.cpp:
+ (WebCore::PageOverlay::bounds):
+ (WebCore::PageOverlay::viewToOverlayOffset): Convenience function to map between
+ view and overlay coordinates.
+ * page/PageOverlay.h:
+ * page/scrolling/AsyncScrollingCoordinator.cpp: New computeNonFastScrollableRegion() signature.
+ (WebCore::AsyncScrollingCoordinator::updateNonFastScrollableRegion):
+ (WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated):
+ (WebCore::AsyncScrollingCoordinator::scrollingStateTreeAsText):
+ * page/scrolling/ScrollingCoordinator.cpp:
+ (WebCore::ScrollingCoordinator::absoluteNonFastScrollableRegionForFrame): This function
+ recurses on frames, computing an absolute (document-relative) region per frame. This
+ removes the confusing offsetting through top content inset.
+ Change how we get to plugins that want wheel events; we can't get from PluginViewBase
+ to renderers, so use FrameView's list of Widgets, and their RenderWidgets. This fixes
+ regions for transformed plugin-ins.
+ For subframes, we get a region in the subframe's document coords. Map to that sub-frame,
+ then to our frame, then to our document.
+ (WebCore::ScrollingCoordinator::absoluteNonFastScrollableRegion): Wrapper that hides
+ the recursive function.
+ (WebCore::ScrollingCoordinator::computeNonFastScrollableRegion): Deleted.
+ * page/scrolling/ScrollingCoordinator.h:
+ * page/scrolling/ScrollingTree.cpp:
+ (WebCore::ScrollingTree::shouldHandleWheelEventSynchronously): Map the event point
+ from view coordinates to document coordinates for testing against the non-fast region.
+ We previously assert that the root note is a FrameScrolling node.
+ * page/scrolling/ScrollingTreeFrameScrollingNode.cpp:
+ (WebCore::ScrollingTreeFrameScrollingNode::viewToContentsOffset): Similar to ScrollView::viewToContents()
+ for the scrolling tree.
+ * page/scrolling/ScrollingTreeFrameScrollingNode.h:
+ * testing/Internals.cpp:
+ (WebCore::Internals::nonFastScrollableRects): No need for frame arg.
+
2015-04-29 Brent Fulgham <bfulgham@apple.com>
Expand test infrastructure to support scrolling tests
bool MouseWheelRegionOverlay::updateRegion()
{
- std::unique_ptr<Region> region = std::make_unique<Region>(m_frame.document()->absoluteRegionForEventTargets(m_frame.document()->wheelEventTargets()).first);
+ std::unique_ptr<Region> region = std::make_unique<Region>();
+
+ for (const Frame* frame = &m_frame; frame; frame = frame->tree().traverseNext()) {
+ if (!frame->view() || !frame->document())
+ continue;
+
+ Document::RegionFixedPair frameRegion = frame->document()->absoluteRegionForEventTargets(frame->document()->wheelEventTargets());
+
+ IntPoint frameOffset = frame->view()->contentsToRootView(IntPoint());
+ frameRegion.first.translate(toIntSize(frameOffset));
+
+ region->unite(frameRegion.first);
+ }
+
+ region->translate(m_overlay->viewToOverlayOffset());
bool regionChanged = !m_region || !(*m_region == *region);
m_region = WTF::move(region);
if (Page* page = m_frame.page()) {
if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
- *region = scrollingCoordinator->computeNonFastScrollableRegion(m_frame, IntPoint());
+ *region = scrollingCoordinator->absoluteNonFastScrollableRegion();
}
- // computeNonFastScrollableRegion() applies topContentInset.
- region->translate(IntSize(0, -m_frame.view()->topContentInset()));
-
bool regionChanged = !m_region || !(*m_region == *region);
m_region = WTF::move(region);
return regionChanged;
WEBCORE_EXPORT IntPoint convertFromRendererToContainingView(const RenderElement*, const IntPoint&) const;
WEBCORE_EXPORT IntPoint convertFromContainingViewToRenderer(const RenderElement*, const IntPoint&) const;
+ // Override ScrollView methods to do point conversion via renderers, in order to take transforms into account.
+ virtual IntRect convertToContainingView(const IntRect&) const override;
+ virtual IntRect convertFromContainingView(const IntRect&) const override;
+ virtual IntPoint convertToContainingView(const IntPoint&) const override;
+ virtual IntPoint convertFromContainingView(const IntPoint&) const override;
+
bool isFrameViewScrollCorner(RenderScrollbarPart* scrollCorner) const { return m_scrollCorner == scrollCorner; }
// isScrollable() takes an optional Scrollability parameter that allows the caller to define what they mean by 'scrollable.'
void didAddWidgetToRenderTree(Widget&);
void willRemoveWidgetFromRenderTree(Widget&);
+ const HashSet<Widget*>& widgetsInRenderTree() const { return m_widgetsInRenderTree; }
+
void addTrackedRepaintRect(const FloatRect&);
// exposedRect represents WebKit's understanding of what part
virtual void delegatesScrollingDidChange() override;
- // Override ScrollView methods to do point conversion via renderers, in order to
- // take transforms into account.
- virtual IntRect convertToContainingView(const IntRect&) const override;
- virtual IntRect convertFromContainingView(const IntRect&) const override;
- virtual IntPoint convertToContainingView(const IntPoint&) const override;
- virtual IntPoint convertFromContainingView(const IntPoint&) const override;
-
// ScrollableArea interface
virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) override;
virtual void scrollTo(const IntSize&) override;
return String();
}
-Ref<ClientRectList> Page::nonFastScrollableRects(const Frame& frame)
+Ref<ClientRectList> Page::nonFastScrollableRects()
{
if (Document* document = m_mainFrame->document())
document->updateLayout();
Vector<IntRect> rects;
if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
- rects = scrollingCoordinator->computeNonFastScrollableRegion(frame, IntPoint()).rects();
+ rects = scrollingCoordinator->absoluteNonFastScrollableRegion().rects();
Vector<FloatQuad> quads(rects.size());
for (size_t i = 0; i < rects.size(); ++i)
quads[i] = FloatRect(rects[i]);
+
return ClientRectList::create(quads);
}
WEBCORE_EXPORT String scrollingStateTreeAsText();
WEBCORE_EXPORT String synchronousScrollingReasonsAsText();
- WEBCORE_EXPORT Ref<ClientRectList> nonFastScrollableRects(const Frame&);
+ WEBCORE_EXPORT Ref<ClientRectList> nonFastScrollableRects();
Settings& settings() const { return *m_settings; }
ProgressTracker& progress() const { return *m_progress; }
}
case OverlayType::Document:
return IntRect(IntPoint(), frameView->contentsSize());
- };
+ }
ASSERT_NOT_REACHED();
return IntRect(IntPoint(), frameView->contentsSize());
pageOverlayController->didChangeOverlayFrame(*this);
}
+IntSize PageOverlay::viewToOverlayOffset() const
+{
+ switch (m_overlayType) {
+ case OverlayType::View:
+ return IntSize();
+
+ case OverlayType::Document: {
+ FrameView* frameView = m_page->mainFrame().view();
+ return frameView ? toIntSize(frameView->viewToContents(IntPoint())) : IntSize();
+ }
+ }
+ return IntSize();
+}
+
void PageOverlay::setBackgroundColor(RGBA32 backgroundColor)
{
if (m_backgroundColor == backgroundColor)
WEBCORE_EXPORT IntRect frame() const;
WEBCORE_EXPORT void setFrame(IntRect);
+ WEBCORE_EXPORT IntSize viewToOverlayOffset() const;
+
RGBA32 backgroundColor() const { return m_backgroundColor; }
void setBackgroundColor(RGBA32);
if (!m_scrollingStateTree->rootStateNode())
return;
- m_scrollingStateTree->rootStateNode()->setNonFastScrollableRegion(computeNonFastScrollableRegion(m_page->mainFrame(), IntPoint()));
+ m_scrollingStateTree->rootStateNode()->setNonFastScrollableRegion(absoluteNonFastScrollableRegion());
m_nonFastScrollableRegionDirty = false;
}
// frame view whose layout was updated is not the main frame.
// In the future, we may want to have the ability to set non-fast scrolling regions for more than
// just the root node. But right now, this concept only applies to the root.
- m_scrollingStateTree->rootStateNode()->setNonFastScrollableRegion(computeNonFastScrollableRegion(m_page->mainFrame(), IntPoint()));
+ m_scrollingStateTree->rootStateNode()->setNonFastScrollableRegion(absoluteNonFastScrollableRegion());
m_nonFastScrollableRegionDirty = false;
if (!coordinatesScrollingForFrameView(frameView))
{
if (m_scrollingStateTree->rootStateNode()) {
if (m_nonFastScrollableRegionDirty)
- m_scrollingStateTree->rootStateNode()->setNonFastScrollableRegion(computeNonFastScrollableRegion(m_page->mainFrame(), IntPoint()));
+ m_scrollingStateTree->rootStateNode()->setNonFastScrollableRegion(absoluteNonFastScrollableRegion());
return m_scrollingStateTree->rootStateNode()->scrollingStateTreeAsText();
}
return renderView->usesCompositing();
}
-Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame& frame, const IntPoint& frameLocation) const
+Region ScrollingCoordinator::absoluteNonFastScrollableRegionForFrame(const Frame& frame) const
{
RenderView* renderView = frame.contentRenderer();
if (!renderView || renderView->documentBeingDestroyed())
// FIXME: should ASSERT(!frameView->needsLayout()) here, but need to fix DebugPageOverlays
// to not ask for regions at bad times.
- IntPoint offset = frameLocation;
- offset.moveBy(frameView->frameRect().location());
- offset.move(0, frameView->topContentInset());
-
if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) {
for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
ScrollableArea* scrollableArea = *it;
// Composited scrollable areas can be scrolled off the main thread.
if (scrollableArea->usesAsyncScrolling())
continue;
+
IntRect box = scrollableArea->scrollableAreaBoundingBox();
- box.moveBy(offset);
nonFastScrollableRegion.unite(box);
}
}
- for (const auto& child : frameView->children()) {
- if (!is<PluginViewBase>(*child))
+ for (auto& widget : frameView->widgetsInRenderTree()) {
+ RenderWidget* renderWidget = RenderWidget::find(widget);
+ if (!renderWidget || !is<PluginViewBase>(*widget))
continue;
- PluginViewBase& pluginViewBase = downcast<PluginViewBase>(*child);
- if (pluginViewBase.wantsWheelEvents())
- nonFastScrollableRegion.unite(pluginViewBase.frameRect());
+
+ if (downcast<PluginViewBase>(*widget).wantsWheelEvents())
+ nonFastScrollableRegion.unite(renderWidget->absoluteBoundingBoxRect());
}
+
+ // FIXME: if we've already accounted for this subframe as a scrollable area, we can avoid recursing into it here.
+ for (Frame* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling()) {
+ FrameView* subframeView = subframe->view();
+ if (!subframeView)
+ continue;
- for (Frame* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling())
- nonFastScrollableRegion.unite(computeNonFastScrollableRegion(*subframe, offset));
+ Region subframeRegion = absoluteNonFastScrollableRegionForFrame(*subframe);
+ // Map from the frame document to our document.
+ IntPoint offset = subframeView->contentsToView(IntPoint());
+ offset = subframeView->convertToContainingView(offset);
+ offset = frameView->viewToContents(offset);
+
+ // FIXME: this translation ignores non-trival transforms on the frame.
+ subframeRegion.translate(toIntSize(offset));
+ nonFastScrollableRegion.unite(subframeRegion);
+ }
- // Include wheel event handler region for the main frame.
Document::RegionFixedPair wheelHandlerRegion = frame.document()->absoluteRegionForEventTargets(frame.document()->wheelEventTargets());
bool wheelHandlerInFixedContent = wheelHandlerRegion.second;
if (wheelHandlerInFixedContent) {
bool inFixed;
wheelHandlerRegion.first.unite(enclosingIntRect(frame.document()->absoluteEventHandlerBounds(inFixed)));
}
- wheelHandlerRegion.first.translate(toIntSize(offset));
+
nonFastScrollableRegion.unite(wheelHandlerRegion.first);
+ // FIXME: If this is not the main frame, we could clip the region to the frame's bounds.
return nonFastScrollableRegion;
#endif
}
+Region ScrollingCoordinator::absoluteNonFastScrollableRegion() const
+{
+ return absoluteNonFastScrollableRegionForFrame(m_page->mainFrame());
+}
+
void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView& frameView)
{
ASSERT(isMainThread());
static String synchronousScrollingReasonsAsText(SynchronousScrollingReasons);
String synchronousScrollingReasonsAsText() const;
- Region computeNonFastScrollableRegion(const Frame&, const IntPoint& frameLocation) const;
+ Region absoluteNonFastScrollableRegion() const;
protected:
explicit ScrollingCoordinator(Page*);
virtual bool hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView&) const;
void updateSynchronousScrollingReasons(FrameView&);
+
+ Region absoluteNonFastScrollableRegionForFrame(const Frame&) const;
bool m_forceSynchronousScrollLayerPositionUpdates { false };
};
#include "PlatformWheelEvent.h"
#include "ScrollingStateTree.h"
+#include "ScrollingTreeFrameScrollingNode.h"
#include "ScrollingTreeNode.h"
#include "ScrollingTreeOverflowScrollingNode.h"
#include "ScrollingTreeScrollingNode.h"
if (shouldSetLatch)
m_latchedNode = 0;
- if (!m_nonFastScrollableRegion.isEmpty()) {
+ if (!m_nonFastScrollableRegion.isEmpty() && m_rootNode) {
+ ScrollingTreeFrameScrollingNode& frameScrollingNode = downcast<ScrollingTreeFrameScrollingNode>(*m_rootNode);
// FIXME: This is not correct for non-default scroll origins.
FloatPoint position = wheelEvent.position();
- position.moveBy(m_mainFrameScrollPosition);
+ position.move(frameScrollingNode.viewToContentsOffset(m_mainFrameScrollPosition));
if (m_nonFastScrollableRegion.contains(roundedIntPoint(position)))
return true;
}
setScrollPositionWithoutContentEdgeConstraints(newScrollPosition);
}
+FloatSize ScrollingTreeFrameScrollingNode::viewToContentsOffset(const FloatPoint& scrollOffset) const
+{
+ return toFloatSize(scrollOffset) - FloatSize(0, headerHeight() + topContentInset());
+}
+
} // namespace WebCore
#endif // ENABLE(ASYNC_SCROLLING)
SynchronousScrollingReasons synchronousScrollingReasons() const { return m_synchronousScrollingReasons; }
bool shouldUpdateScrollLayerPositionSynchronously() const { return m_synchronousScrollingReasons; }
+ FloatSize viewToContentsOffset(const FloatPoint& scrollOffset) const;
+
protected:
ScrollingTreeFrameScrollingNode(ScrollingTree&, ScrollingNodeID);
if (!page)
return nullptr;
- return page->nonFastScrollableRects(*document->frame());
+ return page->nonFastScrollableRects();
}
void Internals::garbageCollectDocumentResources(ExceptionCode& ec) const