From 4493ecd0bed0e4ed96d50b63938a8efe954abb31 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 21 Oct 2010 14:07:55 +0200 Subject: [PATCH] Bug 461843 - Show indication of where on the page you are when scrolling with Fennec. r=roc a=blocking-fennec --- layout/generic/nsGfxScrollFrame.cpp | 76 ++++++++++++++++-------- layout/generic/nsGfxScrollFrame.h | 10 ++++ widget/public/nsILookAndFeel.h | 1 + widget/src/xpwidgets/nsXPLookAndFeel.cpp | 2 + 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 48edb74aa43..21821c9955b 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -76,10 +76,10 @@ #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif -#include "nsDisplayList.h" #include "nsBidiUtils.h" #include "nsFrameManager.h" #include "nsIPrefService.h" +#include "nsILookAndFeel.h" #include "mozilla/dom/Element.h" using namespace mozilla::dom; @@ -1319,6 +1319,12 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter, mUpdateScrollbarAttributes(PR_FALSE), mScrollingActive(PR_FALSE) { + // lookup if we're allowed to overlap the content from the look&feel object + PRBool canOverlap; + nsPresContext* presContext = mOuter->PresContext(); + presContext->LookAndFeel()-> + GetMetric(nsILookAndFeel::eMetric_ScrollbarsCanOverlapContent, canOverlap); + mScrollbarsCanOverlapContent = canOverlap; } nsGfxScrollFrameInner::~nsGfxScrollFrameInner() @@ -1707,6 +1713,34 @@ AppendToTop(nsDisplayListBuilder* aBuilder, nsDisplayList* aDest, } } +nsresult +nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists, + const nsDisplayListCollection& aDest, + PRBool& aCreateLayer) +{ + nsresult rv = NS_OK; + PRBool hasResizer = HasResizer(); + for (nsIFrame* kid = mOuter->GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) { + if (kid != mScrolledFrame) { + if (kid == mScrollCornerBox && hasResizer) { + // skip the resizer as this will be drawn later on top of the scrolled content + continue; + } + rv = mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aDest, + nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT); + NS_ENSURE_SUCCESS(rv, rv); + // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into the + // PositionedDescendants list. + ::AppendToTop(aBuilder, aLists.BorderBackground(), + aDest.PositionedDescendants(), kid, + aCreateLayer); + } + } + return rv; +} + nsresult nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, @@ -1727,12 +1761,6 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, aDirtyRect, aLists); } - // Now display the scrollbars and scrollcorner. These parts are drawn - // in the border-background layer, on top of our own background and - // borders and underneath borders and backgrounds of later elements - // in the tree. - PRBool hasResizer = HasResizer(); - nsDisplayListCollection scrollParts; // We put scrollbars in their own layers when this is the root scroll // frame and we are a toplevel content document. In this situation, the // scrollbar(s) would normally be assigned their own layer anyway, since @@ -1743,23 +1771,16 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, // scrollbar works around the problem. PRBool createLayersForScrollbars = mIsRoot && mOuter->PresContext()->IsRootContentDocument(); - for (nsIFrame* kid = mOuter->GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) { - if (kid != mScrolledFrame) { - if (kid == mScrollCornerBox && hasResizer) { - // skip the resizer as this will be drawn later on top of the scrolled content - continue; - } - rv = mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, scrollParts, - nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT); - NS_ENSURE_SUCCESS(rv, rv); - // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into the - // PositionedDescendants list. - ::AppendToTop(aBuilder, aLists.BorderBackground(), - scrollParts.PositionedDescendants(), kid, - createLayersForScrollbars); - } - } + nsDisplayListCollection scrollParts; + if (!mScrollbarsCanOverlapContent) { + // Now display the scrollbars and scrollcorner. These parts are drawn + // in the border-background layer, on top of our own background and + // borders and underneath borders and backgrounds of later elements + // in the tree. + AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, + scrollParts, createLayersForScrollbars); + } // Overflow clipping can never clip frames outside our subtree, so there // is no need to worry about whether we are a moving frame that might clip @@ -1771,7 +1792,7 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our // dirty rect here. dirtyRect.IntersectRect(aDirtyRect, mScrollPort); - + nsDisplayListCollection set; rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set); NS_ENSURE_SUCCESS(rv, rv); @@ -1789,11 +1810,16 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, PR_TRUE, mIsRoot); NS_ENSURE_SUCCESS(rv, rv); + if (mScrollbarsCanOverlapContent) { + AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, + scrollParts, createLayersForScrollbars); + } + // Place the resizer in the display list in our Content() list above // scrolled content in the Content() list. // This ensures that the resizer appears above the content and the mouse can // still target the resizer even when scrollbars are hidden. - if (hasResizer && mScrollCornerBox) { + if (HasResizer() && mScrollCornerBox) { rv = mOuter->BuildDisplayListForChild(aBuilder, mScrollCornerBox, aDirtyRect, scrollParts, nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT); NS_ENSURE_SUCCESS(rv, rv); diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 4a5a1e918bf..2003bb4ce3c 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -43,6 +43,7 @@ #include "nsHTMLContainerFrame.h" #include "nsIAnonymousContentCreator.h" #include "nsBoxFrame.h" +#include "nsDisplayList.h" #include "nsIScrollableFrame.h" #include "nsIScrollPositionListener.h" #include "nsIStatefulFrame.h" @@ -91,6 +92,12 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists); + nsresult AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists, + const nsDisplayListCollection& aDest, + PRBool& aCreateLayer); + PRBool GetBorderRadii(nscoord aRadii[8]) const; // nsIReflowCallback @@ -295,6 +302,9 @@ public: // If true, we should be prepared to scroll using this scrollframe // by placing descendant content into its own layer(s) PRPackedBool mScrollingActive:1; + // If true, scrollbars are stacked on the top of the display list and can + // float above the content as a result + PRPackedBool mScrollbarsCanOverlapContent:1; }; /** diff --git a/widget/public/nsILookAndFeel.h b/widget/public/nsILookAndFeel.h index ed490b79e4a..44c542c43c6 100644 --- a/widget/public/nsILookAndFeel.h +++ b/widget/public/nsILookAndFeel.h @@ -184,6 +184,7 @@ public: eMetric_SelectTextfieldsOnKeyFocus, // select textfields when focused via tab/accesskey? eMetric_SubmenuDelay, // delay before submenus open eMetric_MenusCanOverlapOSBar, // can popups overlap menu/task bar? + eMetric_ScrollbarsCanOverlapContent, // can scrollbars float above content? eMetric_SkipNavigatingDisabledMenuItem, // skip navigating to disabled menu item? eMetric_DragThresholdX, // begin a drag if the mouse is moved further than the threshold while the button is down eMetric_DragThresholdY, diff --git a/widget/src/xpwidgets/nsXPLookAndFeel.cpp b/widget/src/xpwidgets/nsXPLookAndFeel.cpp index a227196d8f9..d91fab5b428 100644 --- a/widget/src/xpwidgets/nsXPLookAndFeel.cpp +++ b/widget/src/xpwidgets/nsXPLookAndFeel.cpp @@ -64,6 +64,8 @@ nsLookAndFeelIntPref nsXPLookAndFeel::sIntPrefs[] = { "ui.dragThresholdX", eMetric_DragThresholdX, PR_FALSE, nsLookAndFeelTypeInt, 0 }, { "ui.dragThresholdY", eMetric_DragThresholdY, PR_FALSE, nsLookAndFeelTypeInt, 0 }, { "ui.useAccessibilityTheme", eMetric_UseAccessibilityTheme, PR_FALSE, nsLookAndFeelTypeInt, 0 }, + { "ui.scrollbarsCanOverlapContent", eMetric_ScrollbarsCanOverlapContent, + PR_FALSE, nsLookAndFeelTypeInt, 0 }, { "ui.menusCanOverlapOSBar", eMetric_MenusCanOverlapOSBar, PR_FALSE, nsLookAndFeelTypeInt, 0 }, { "ui.skipNavigatingDisabledMenuItem", eMetric_SkipNavigatingDisabledMenuItem, PR_FALSE, nsLookAndFeelTypeInt, 0 },