Bug 1436431 Part 1: Extend PresShell::GetRectVisibility to consider the target frame's scrollable ancestors.
MozReview-Commit-ID: JIP8ZRNu7fV
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -3762,23 +3762,47 @@ PresShell::GetRectVisibility(nsIFrame* a
if (sf) {
scrollPortRect = sf->GetScrollPortRect();
nsIFrame* f = do_QueryFrame(sf);
scrollPortRect += f->GetOffsetTo(rootFrame);
} else {
scrollPortRect = nsRect(nsPoint(0,0), rootFrame->GetSize());
}
+ // scrollPortRect has the viewport visible area relative to rootFrame.
+ nsRect visibleAreaRect(scrollPortRect);
+ // Find the intersection of this and the frame's ancestor scrollable
+ // frames. We walk the whole ancestor chain to find all the scrollable
+ // frames.
+ nsIScrollableFrame* scrollAncestorFrame =
+ nsLayoutUtils::GetNearestScrollableFrame(aFrame,
+ nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
+ while (scrollAncestorFrame) {
+ nsRect scrollAncestorRect = scrollAncestorFrame->GetScrollPortRect();
+ nsIFrame* f = do_QueryFrame(scrollAncestorFrame);
+ scrollAncestorRect += f->GetOffsetTo(rootFrame);
+
+ visibleAreaRect = visibleAreaRect.Intersect(scrollAncestorRect);
+
+ // Continue up the chain.
+ scrollAncestorFrame =
+ nsLayoutUtils::GetNearestScrollableFrame(f->GetParent(),
+ nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
+ }
+
+ // aRect is in the aFrame coordinate space, so bring it into rootFrame
+ // coordinate space.
nsRect r = aRect + aFrame->GetOffsetTo(rootFrame);
// If aRect is entirely visible then we don't need to ensure that
// at least aMinTwips of it is visible
- if (scrollPortRect.Contains(r))
+ if (visibleAreaRect.Contains(r)) {
return nsRectVisibility_kVisible;
-
- nsRect insetRect = scrollPortRect;
+ }
+
+ nsRect insetRect = visibleAreaRect;
insetRect.Deflate(aMinTwips, aMinTwips);
if (r.YMost() <= insetRect.y)
return nsRectVisibility_kAboveViewport;
if (r.y >= insetRect.YMost())
return nsRectVisibility_kBelowViewport;
if (r.XMost() <= insetRect.x)
return nsRectVisibility_kLeftOfViewport;
if (r.x >= insetRect.XMost())
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -825,27 +825,33 @@ public:
virtual bool ScrollFrameRectIntoView(nsIFrame* aFrame,
const nsRect& aRect,
ScrollAxis aVertical,
ScrollAxis aHorizontal,
uint32_t aFlags) = 0;
/**
* Determine if a rectangle specified in the frame's coordinate system
- * intersects the viewport "enough" to be considered visible.
+ * intersects "enough" with the viewport to be considered visible. This
+ * is not a strict test against the viewport -- it's a test against
+ * the intersection of the viewport and the frame's ancestor scrollable
+ * frames. If it doesn't intersect enough, return a value indicating
+ * which direction the frame's topmost ancestor scrollable frame would
+ * need to be scrolled to bring the frame into view.
* @param aFrame frame that aRect coordinates are specified relative to
* @param aRect rectangle in twips to test for visibility
- * @param aMinTwips is the minimum distance in from the edge of the viewport
- * that an object must be to be counted visible
+ * @param aMinTwips is the minimum distance in from the edge of the
+ * visible area that an object must be to be counted
+ * visible
* @return nsRectVisibility_kVisible if the rect is visible
* nsRectVisibility_kAboveViewport
* nsRectVisibility_kBelowViewport
* nsRectVisibility_kLeftOfViewport
- * nsRectVisibility_kRightOfViewport rectangle is outside the viewport
- * in the specified direction
+ * nsRectVisibility_kRightOfViewport rectangle is outside the
+ * topmost ancestor scrollable frame in the specified direction
*/
virtual nsRectVisibility GetRectVisibility(nsIFrame *aFrame,
const nsRect &aRect,
nscoord aMinTwips) const = 0;
/**
* Suppress notification of the frame manager that frames are
* being destroyed.