diff --git a/content/base/public/Element.h b/content/base/public/Element.h index 7322d7058793..c93d55cbe861 100644 --- a/content/base/public/Element.h +++ b/content/base/public/Element.h @@ -1036,13 +1036,6 @@ protected: */ virtual Element* GetOffsetRect(nsRect& aRect); - /** - * Retrieve the size of the padding rect of this element. - * - * @param aSize the size of the padding rect - */ - nsIntSize GetPaddingRectSize(); - nsIFrame* GetStyledFrame(); virtual Element* GetNameSpaceElement() diff --git a/content/base/src/Element.cpp b/content/base/src/Element.cpp index 8d3c14e7aec6..a71d0a9cdb1c 100644 --- a/content/base/src/Element.cpp +++ b/content/base/src/Element.cpp @@ -514,20 +514,6 @@ Element::GetOffsetRect(nsRect& aRect) return nullptr; } -nsIntSize -Element::GetPaddingRectSize() -{ - nsIFrame* frame = GetStyledFrame(); - if (!frame) { - return nsIntSize(0, 0); - } - - NS_ASSERTION(frame->GetParent(), "Styled frame has no parent"); - nsRect rcFrame = nsLayoutUtils::GetAllInFlowPaddingRectsUnion(frame, frame->GetParent()); - return nsIntSize(nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width), - nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height)); -} - nsIScrollableFrame* Element::GetScrollFrame(nsIFrame **aStyledFrame) { @@ -597,6 +583,20 @@ Element::ScrollIntoView(bool aTop) nsIPresShell::SCROLL_OVERFLOW_HIDDEN); } +static nsSize GetScrollRectSizeForOverflowVisibleFrame(nsIFrame* aFrame) +{ + if (!aFrame) { + return nsSize(0,0); + } + + nsRect paddingRect = aFrame->GetPaddingRectRelativeToSelf(); + nsOverflowAreas overflowAreas(paddingRect, paddingRect); + nsLayoutUtils::UnionChildOverflow(aFrame, overflowAreas); + return nsLayoutUtils::GetScrolledRect(aFrame, + overflowAreas.ScrollableOverflow(), paddingRect.Size(), + aFrame->GetStyleVisibility()->mDirection).Size(); +} + int32_t Element::ScrollHeight() { @@ -604,11 +604,13 @@ Element::ScrollHeight() return 0; nsIScrollableFrame* sf = GetScrollFrame(); - if (!sf) { - return GetPaddingRectSize().height; + nscoord height; + if (sf) { + height = sf->GetScrollRange().height + sf->GetScrollPortRect().height; + } else { + height = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).height; } - nscoord height = sf->GetScrollRange().height + sf->GetScrollPortRect().height; return nsPresContext::AppUnitsToIntCSSPixels(height); } @@ -619,11 +621,13 @@ Element::ScrollWidth() return 0; nsIScrollableFrame* sf = GetScrollFrame(); - if (!sf) { - return GetPaddingRectSize().width; + nscoord width; + if (sf) { + width = sf->GetScrollRange().width + sf->GetScrollPortRect().width; + } else { + width = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).width; } - nscoord width = sf->GetScrollRange().width + sf->GetScrollPortRect().width; return nsPresContext::AppUnitsToIntCSSPixels(width); } diff --git a/dom/tests/mochitest/general/test_offsets.html b/dom/tests/mochitest/general/test_offsets.html index 87e9be7ff4a5..04be711991f3 100644 --- a/dom/tests/mochitest/general/test_offsets.html +++ b/dom/tests/mochitest/general/test_offsets.html @@ -60,6 +60,11 @@ value="This button is much longer than the others">

+
+
+
+
+

clientWidth || + element.scrollHeight > clientHeight) { + // The element overflows. Don't check scrollWidth/scrollHeight since the + // above calculation is not correct. + doScrollCheck = false; + } else { + scrollWidth = clientWidth; + scrollHeight = clientHeight; + } } - if (element instanceof SVGElement) - checkScrollState(element, 0, 0, 0, 0, element.id); - else - checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id); + if (doScrollCheck) { + if (element instanceof SVGElement) + checkScrollState(element, 0, 0, 0, 0, element.id); + else + checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id); + } if (element instanceof SVGElement) checkClientState(element, 0, 0, 0, 0, element.id); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index bcf429f0916c..c428d8d502db 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1153,6 +1153,40 @@ nsLayoutUtils::GetNearestScrollableFrame(nsIFrame* aFrame) return nullptr; } +// static +nsRect +nsLayoutUtils::GetScrolledRect(nsIFrame* aScrolledFrame, + const nsRect& aScrolledFrameOverflowArea, + const nsSize& aScrollPortSize, + uint8_t aDirection) +{ + nscoord x1 = aScrolledFrameOverflowArea.x, + x2 = aScrolledFrameOverflowArea.XMost(), + y1 = aScrolledFrameOverflowArea.y, + y2 = aScrolledFrameOverflowArea.YMost(); + if (y1 < 0) { + y1 = 0; + } + if (aDirection != NS_STYLE_DIRECTION_RTL) { + if (x1 < 0) { + x1 = 0; + } + } else { + if (x2 > aScrollPortSize.width) { + x2 = aScrollPortSize.width; + } + // When the scrolled frame chooses a size larger than its available width (because + // its padding alone is larger than the available width), we need to keep the + // start-edge of the scroll frame anchored to the start-edge of the scrollport. + // When the scrolled frame is RTL, this means moving it in our left-based + // coordinate system, so we need to compensate for its extra width here by + // effectively repositioning the frame. + nscoord extraWidth = std::max(0, aScrolledFrame->GetSize().width - aScrollPortSize.width); + x2 += extraWidth; + } + return nsRect(x1, y1, x2 - x1, y2 - y1); +} + //static bool nsLayoutUtils::HasPseudoStyle(nsIContent* aContent, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 458f593a0b40..a6c1f8332c52 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -374,6 +374,17 @@ public: */ static nsIScrollableFrame* GetNearestScrollableFrame(nsIFrame* aFrame); + /** + * GetScrolledRect returns the range of allowable scroll offsets + * for aScrolledFrame, assuming the scrollable overflow area is + * aScrolledFrameOverflowArea and the scrollport size is aScrollPortSize. + * aDirection is either NS_STYLE_DIRECTION_LTR or NS_STYLE_DIRECTION_RTL. + */ + static nsRect GetScrolledRect(nsIFrame* aScrolledFrame, + const nsRect& aScrolledFrameOverflowArea, + const nsSize& aScrollPortSize, + uint8_t aDirection); + /** * HasPseudoStyle returns true if aContent (whose primary style * context is aStyleContext) has the aPseudoElement pseudo-style diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 80d7b77dfe7f..1a441396ce50 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -3728,28 +3728,9 @@ nsRect nsGfxScrollFrameInner::GetScrolledRectInternal(const nsRect& aScrolledFrameOverflowArea, const nsSize& aScrollPortSize) const { - nscoord x1 = aScrolledFrameOverflowArea.x, - x2 = aScrolledFrameOverflowArea.XMost(), - y1 = aScrolledFrameOverflowArea.y, - y2 = aScrolledFrameOverflowArea.YMost(); - if (y1 < 0) - y1 = 0; - if (IsLTR()) { - if (x1 < 0) - x1 = 0; - } else { - if (x2 > aScrollPortSize.width) - x2 = aScrollPortSize.width; - // When the scrolled frame chooses a size larger than its available width (because - // its padding alone is larger than the available width), we need to keep the - // start-edge of the scroll frame anchored to the start-edge of the scrollport. - // When the scrolled frame is RTL, this means moving it in our left-based - // coordinate system, so we need to compensate for its extra width here by - // effectively repositioning the frame. - nscoord extraWidth = std::max(0, mScrolledFrame->GetSize().width - aScrollPortSize.width); - x2 += extraWidth; - } - return nsRect(x1, y1, x2 - x1, y2 - y1); + return nsLayoutUtils::GetScrolledRect(mScrolledFrame, + aScrolledFrameOverflowArea, aScrollPortSize, + IsLTR() ? NS_STYLE_DIRECTION_LTR : NS_STYLE_DIRECTION_RTL); } nsMargin