diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index b18e1b11316e..166864141dce 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2556,15 +2556,62 @@ nsGfxScrollFrameInner::GetLineScrollAmount() const return nsSize(fontHeight, fontHeight); } +/** + * Compute the scrollport size excluding any fixed-pos headers and + * footers. A header or footer is an box that spans that entire width + * of the viewport and touches the top (or bottom, respectively) of the + * viewport. Headers and footers that cover more than a quarter of the + * the viewport are ignored since they probably aren't true headers and + * footers and we don't want to restrict scrolling too much in such cases. + * This is a bit conservative --- some pages use elements as headers or + * footers that don't span the entire width of the viewport --- but it + * should be a good start. + */ +static nsSize +GetScrollPortSizeExcludingHeadersAndFooters(nsIFrame* aViewportFrame, + const nsRect& aScrollPort) +{ + nsFrameList fixedFrames = aViewportFrame->GetChildList(nsIFrame::kFixedList); + nscoord headerBottom = 0; + nscoord footerTop = aScrollPort.height; + for (nsFrameList::Enumerator iterator(fixedFrames); !iterator.AtEnd(); + iterator.Next()) { + nsIFrame* f = iterator.get(); + nsRect r = f->GetRect().Intersect(aScrollPort); + if (r.x == 0 && r.width == aScrollPort.width && + r.height <= aScrollPort.height/3) { + if (r.y == 0) { + headerBottom = NS_MAX(headerBottom, r.height); + } + if (r.YMost() == aScrollPort.height) { + footerTop = NS_MIN(footerTop, r.y); + } + } + } + return nsSize(aScrollPort.width, footerTop - headerBottom); +} + nsSize nsGfxScrollFrameInner::GetPageScrollAmount() const { nsSize lineScrollAmount = GetLineScrollAmount(); + nsSize effectiveScrollPortSize; + if (mIsRoot) { + // Reduce effective scrollport height by the height of any fixed-pos + // headers or footers + nsIFrame* root = mOuter->PresContext()->PresShell()->GetRootFrame(); + effectiveScrollPortSize = + GetScrollPortSizeExcludingHeadersAndFooters(root, mScrollPort); + } else { + effectiveScrollPortSize = mScrollPort.Size(); + } // The page increment is the size of the page, minus the smaller of // 10% of the size or 2 lines. return nsSize( - mScrollPort.width - NS_MIN(mScrollPort.width/10, 2*lineScrollAmount.width), - mScrollPort.height - NS_MIN(mScrollPort.height/10, 2*lineScrollAmount.height)); + effectiveScrollPortSize.width - + NS_MIN(effectiveScrollPortSize.width/10, 2*lineScrollAmount.width), + effectiveScrollPortSize.height - + NS_MIN(effectiveScrollPortSize.height/10, 2*lineScrollAmount.height)); } /** diff --git a/layout/generic/test/Makefile.in b/layout/generic/test/Makefile.in index f17a52efb395..fb820609fbe4 100644 --- a/layout/generic/test/Makefile.in +++ b/layout/generic/test/Makefile.in @@ -65,6 +65,8 @@ MOCHITEST_FILES = \ test_invalidate_during_plugin_paint.html \ test_movement_by_characters.html \ test_movement_by_words.html \ + test_page_scroll_with_fixed_pos.html \ + page_scroll_with_fixed_pos_window.html \ test_plugin_clipping.xhtml \ test_plugin_clipping2.xhtml \ test_plugin_clipping_transformed.xhtml \ diff --git a/layout/generic/test/page_scroll_with_fixed_pos_window.html b/layout/generic/test/page_scroll_with_fixed_pos_window.html new file mode 100644 index 000000000000..93d84fa8b7d2 --- /dev/null +++ b/layout/generic/test/page_scroll_with_fixed_pos_window.html @@ -0,0 +1,81 @@ + + +
+Something to click on to get focus +
++ ++ + diff --git a/layout/generic/test/test_page_scroll_with_fixed_pos.html b/layout/generic/test/test_page_scroll_with_fixed_pos.html new file mode 100644 index 000000000000..309ae7f4e1e8 --- /dev/null +++ b/layout/generic/test/test_page_scroll_with_fixed_pos.html @@ -0,0 +1,16 @@ + + + +