зеркало из https://github.com/mozilla/gecko-dev.git
Bug 564991. Part 16: Improve performance by putting each scrollbar in its own layer. Also note that Mac scrollbars are opaque. r=mats,sr=dbaron
This commit is contained in:
Родитель
f63eab3242
Коммит
b496b17fb3
|
@ -73,6 +73,7 @@ enum Type {
|
|||
TYPE_OPACITY,
|
||||
TYPE_OPTION_EVENT_GRABBER,
|
||||
TYPE_OUTLINE,
|
||||
TYPE_OWN_LAYER,
|
||||
TYPE_PAGE_CONTENT,
|
||||
TYPE_PAGE_SEQUENCE,
|
||||
TYPE_PLUGIN,
|
||||
|
|
|
@ -1143,6 +1143,26 @@ PRBool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem*
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsDisplayOwnLayer::nsDisplayOwnLayer(nsIFrame* aFrame, nsDisplayList* aList)
|
||||
: nsDisplayWrapList(aFrame, aList) {
|
||||
MOZ_COUNT_CTOR(nsDisplayOwnLayer);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplayOwnLayer::~nsDisplayOwnLayer() {
|
||||
MOZ_COUNT_DTOR(nsDisplayOwnLayer);
|
||||
}
|
||||
#endif
|
||||
|
||||
// nsDisplayOpacity uses layers for rendering
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager) {
|
||||
nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
nsDisplayClip::nsDisplayClip(nsIFrame* aFrame, nsIFrame* aClippingFrame,
|
||||
nsDisplayItem* aItem, const nsRect& aRect)
|
||||
: nsDisplayWrapList(aFrame, aItem),
|
||||
|
|
|
@ -1480,6 +1480,27 @@ public:
|
|||
NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item that has no purpose but to ensure its contents get
|
||||
* their own layer.
|
||||
*/
|
||||
class nsDisplayOwnLayer : public nsDisplayWrapList {
|
||||
public:
|
||||
nsDisplayOwnLayer(nsIFrame* aFrame, nsDisplayList* aList);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayOwnLayer();
|
||||
#endif
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager);
|
||||
virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
|
||||
{
|
||||
// Don't allow merging, each sublist must have its own layer
|
||||
return PR_FALSE;
|
||||
}
|
||||
NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
|
||||
};
|
||||
|
||||
/**
|
||||
* nsDisplayClip can clip a list of items, but we take a single item
|
||||
* initially and then later merge other items into it when we merge
|
||||
|
|
|
@ -1680,6 +1680,17 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AppendToTop(nsDisplayListBuilder* aBuilder, nsDisplayList* aDest,
|
||||
nsDisplayList* aSource, nsIFrame* aSourceFrame, PRBool aOwnLayer)
|
||||
{
|
||||
if (aOwnLayer) {
|
||||
aDest->AppendNewToTop(new (aBuilder) nsDisplayOwnLayer(aSourceFrame, aSource));
|
||||
} else {
|
||||
aDest->AppendToTop(aSource);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
|
@ -1706,6 +1717,16 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
// 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
|
||||
// they're not scrolled with the rest of the document. But when both
|
||||
// scrollbars are visible, the layer's visible rectangle would be the size
|
||||
// of the viewport, so most layer implementations would create a layer buffer
|
||||
// that's much larger than necessary. Creating independent layers for each
|
||||
// scrollbar works around the problem.
|
||||
PRBool createLayersForScrollbars = mIsRoot &&
|
||||
!nsContentUtils::IsChildOfSameType(mOuter->GetContent()->GetCurrentDoc());
|
||||
for (nsIFrame* kid = mOuter->GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) {
|
||||
if (kid != mScrolledFrame) {
|
||||
if (kid == mScrollCornerBox && hasResizer) {
|
||||
|
@ -1715,11 +1736,14 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
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);
|
||||
}
|
||||
}
|
||||
// DISPLAY_CHILD_FORCE_STACKING_CONTEXT puts everything into the
|
||||
// PositionedDescendants list.
|
||||
aLists.BorderBackground()->AppendToTop(scrollParts.PositionedDescendants());
|
||||
|
||||
|
||||
// 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
|
||||
|
@ -1754,7 +1778,9 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// DISPLAY_CHILD_FORCE_STACKING_CONTEXT puts everything into the
|
||||
// PositionedDescendants list.
|
||||
aLists.Content()->AppendToTop(scrollParts.PositionedDescendants());
|
||||
::AppendToTop(aBuilder, aLists.Content(),
|
||||
scrollParts.PositionedDescendants(), mScrollCornerBox,
|
||||
createLayersForScrollbars);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2897,7 +2923,8 @@ nsGfxScrollFrameInner::ReflowCallbackCanceled()
|
|||
}
|
||||
|
||||
static void LayoutAndInvalidate(nsBoxLayoutState& aState,
|
||||
nsIFrame* aBox, const nsRect& aRect)
|
||||
nsIFrame* aBox, const nsRect& aRect,
|
||||
PRBool aScrollbarIsBeingHidden)
|
||||
{
|
||||
// When a child box changes shape of position, the parent
|
||||
// is responsible for invalidation; the overflow rect must be invalidated
|
||||
|
@ -2907,13 +2934,23 @@ static void LayoutAndInvalidate(nsBoxLayoutState& aState,
|
|||
// mHasVScrollbar/mHasHScrollbar is false, and this is called after those
|
||||
// flags have been set ... if a scrollbar is being hidden, we still need
|
||||
// to invalidate the scrollbar area here.
|
||||
// But we also need to invalidate the scrollbar itself in case it has
|
||||
// its own layer; we need to ensure that layer is updated.
|
||||
PRBool rectChanged = aBox->GetRect() != aRect;
|
||||
if (rectChanged) {
|
||||
aBox->GetParent()->Invalidate(aBox->GetOverflowRect() + aBox->GetPosition());
|
||||
if (aScrollbarIsBeingHidden) {
|
||||
aBox->GetParent()->Invalidate(aBox->GetOverflowRect() + aBox->GetPosition());
|
||||
} else {
|
||||
aBox->InvalidateOverflowRect();
|
||||
}
|
||||
}
|
||||
nsBoxFrame::LayoutChildAt(aState, aBox, aRect);
|
||||
if (rectChanged) {
|
||||
aBox->GetParent()->Invalidate(aBox->GetOverflowRect() + aBox->GetPosition());
|
||||
if (aScrollbarIsBeingHidden) {
|
||||
aBox->GetParent()->Invalidate(aBox->GetOverflowRect() + aBox->GetPosition());
|
||||
} else {
|
||||
aBox->InvalidateOverflowRect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3005,7 +3042,7 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState,
|
|||
r.y = aContentArea.YMost() - r.height;
|
||||
NS_ASSERTION(r.height >= 0, "Scroll area should be inside client rect");
|
||||
}
|
||||
LayoutAndInvalidate(aState, mScrollCornerBox, r);
|
||||
LayoutAndInvalidate(aState, mScrollCornerBox, r, PR_FALSE);
|
||||
}
|
||||
|
||||
nsPresContext* presContext = mScrolledFrame->PresContext();
|
||||
|
@ -3018,7 +3055,7 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState,
|
|||
mVScrollbarBox->GetMargin(margin);
|
||||
vRect.Deflate(margin);
|
||||
AdjustScrollbarRectForResizer(mOuter, presContext, vRect, hasResizer, PR_TRUE);
|
||||
LayoutAndInvalidate(aState, mVScrollbarBox, vRect);
|
||||
LayoutAndInvalidate(aState, mVScrollbarBox, vRect, !mHasVerticalScrollbar);
|
||||
}
|
||||
|
||||
if (mHScrollbarBox) {
|
||||
|
@ -3030,7 +3067,7 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState,
|
|||
mHScrollbarBox->GetMargin(margin);
|
||||
hRect.Deflate(margin);
|
||||
AdjustScrollbarRectForResizer(mOuter, presContext, hRect, hasResizer, PR_FALSE);
|
||||
LayoutAndInvalidate(aState, mHScrollbarBox, hRect);
|
||||
LayoutAndInvalidate(aState, mHScrollbarBox, hRect, !mHasHorizontalScrollbar);
|
||||
}
|
||||
|
||||
// may need to update fixed position children of the viewport,
|
||||
|
|
|
@ -2500,9 +2500,17 @@ nsNativeThemeCocoa::ThemeNeedsComboboxDropmarker()
|
|||
nsITheme::Transparency
|
||||
nsNativeThemeCocoa::GetWidgetTransparency(nsIFrame* aFrame, PRUint8 aWidgetType)
|
||||
{
|
||||
if (aWidgetType == NS_THEME_MENUPOPUP ||
|
||||
aWidgetType == NS_THEME_TOOLTIP)
|
||||
switch (aWidgetType) {
|
||||
case NS_THEME_MENUPOPUP:
|
||||
case NS_THEME_TOOLTIP:
|
||||
return eTransparent;
|
||||
|
||||
return eUnknownTransparency;
|
||||
case NS_THEME_SCROLLBAR_SMALL:
|
||||
case NS_THEME_SCROLLBAR:
|
||||
// Scrollbars are drawn opaque. Knowing this improves performance.
|
||||
return eOpaque;
|
||||
|
||||
default:
|
||||
return eUnknownTransparency;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче