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:
Robert O'Callahan 2010-07-16 09:08:03 +12:00
Родитель f63eab3242
Коммит b496b17fb3
5 изменённых файлов: 100 добавлений и 13 удалений

Просмотреть файл

@ -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;
}
}