diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index f67a98eea6ea..ebbf4d9db361 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -1749,6 +1749,7 @@ GK_ATOM(DeleteTxnName, "Deleting") // IPC stuff GK_ATOM(Remote, "remote") GK_ATOM(RemoteId, "_remote_id") +GK_ATOM(DisplayPort, "_displayport") // Names for system metrics GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward") diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index c5afed5d702b..f531269c6ed1 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -48,6 +48,7 @@ #include "nsFocusManager.h" #include "nsIEventStateManager.h" #include "nsEventStateManager.h" +#include "nsFrameManager.h" #include "nsIScrollableFrame.h" @@ -258,9 +259,25 @@ nsDOMWindowUtils::SetCSSViewport(float aWidthPx, float aHeightPx) return NS_OK; } +static void DestroyNsRect(void* aObject, nsIAtom* aPropertyName, + void* aPropertyValue, void* aData) +{ + nsRect* rect = static_cast(aPropertyValue); + delete rect; +} + NS_IMETHODIMP nsDOMWindowUtils::SetDisplayPort(float aXPx, float aYPx, float aWidthPx, float aHeightPx) +{ + NS_ABORT_IF_FALSE(false, "This interface is deprecated."); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx, + float aWidthPx, float aHeightPx, + nsIDOMElement* aElement) { if (!IsUniversalXPConnectCapable()) { return NS_ERROR_DOM_SECURITY_ERR; @@ -275,9 +292,59 @@ nsDOMWindowUtils::SetDisplayPort(float aXPx, float aYPx, nsPresContext::CSSPixelsToAppUnits(aYPx), nsPresContext::CSSPixelsToAppUnits(aWidthPx), nsPresContext::CSSPixelsToAppUnits(aHeightPx)); - presShell->SetDisplayPort(displayport); - presShell->SetIgnoreViewportScrolling(PR_TRUE); + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsCOMPtr content = do_QueryInterface(aElement); + + if (!content) { + return NS_ERROR_INVALID_ARG; + } + + nsRect lastDisplayPort; + if (nsLayoutUtils::GetDisplayPort(content, &lastDisplayPort) && + displayport == lastDisplayPort) { + return NS_OK; + } + + content->SetProperty(nsGkAtoms::DisplayPort, new nsRect(displayport), + DestroyNsRect); + + nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); + if (rootScrollFrame) { + if (content == rootScrollFrame->GetContent()) { + // We are setting the root displayport. The pres context needs a special + // flag to be set. + presShell->SetIgnoreViewportScrolling(PR_TRUE); + } + } + + // FIXME (Bug 593243 should fix this.) + // + // Invalidated content does not pay any attention to the displayport, so + // invalidating the subdocument's root frame could end up not repainting + // visible content. + // + // For instance, imagine the iframe is located at y=1000. Even though the + // displayport may intersect the iframe's viewport, the visual overflow + // rect of the root content could be (0, 0, 800, 500). Since the dirty region + // does not intersect the visible overflow rect, the display list for the + // iframe will not even be generated. + // + // Here, we find the very top presShell and use its root frame for + // invalidation instead. + // + nsPresContext* rootPresContext = GetPresContext()->GetRootPresContext(); + if (rootPresContext) { + nsIPresShell* rootPresShell = rootPresContext->GetPresShell(); + nsIFrame* rootFrame = rootPresShell->FrameManager()->GetRootFrame(); + if (rootFrame) { + rootFrame->InvalidateWithFlags(rootFrame->GetVisualOverflowRectRelativeToSelf(), + nsIFrame::INVALIDATE_NO_THEBES_LAYERS); + } + } return NS_OK; } diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 4b5975223505..182a52f27116 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -129,30 +129,7 @@ interface nsIDOMWindowUtils : nsISupports { void setCSSViewport(in float aWidthPx, in float aHeightPx); /** - * Set the "displayport" to be in - * units of CSS pixels, regardless of the size of the enclosing - * widget/view. This will *not* trigger reflow. - * - * is relative to the top-left of the CSS viewport. This - * means that the pixels rendered to the displayport take scrolling - * into account, for example. - * - * The displayport will be used as the window's visible region for - * the purposes of invalidation and painting. The displayport can - * approximately be thought of as a "persistent" drawWindow() - * (albeit with coordinates relative to the CSS viewport): the - * bounds are remembered by the platform, and layer pixels are - * retained and updated inside the viewport bounds. - * - * It's legal to set a displayport that extends beyond the CSS - * viewport in any direction (left/right/top/bottom). - * - * It's also legal to set a displayport that extends beyond the - * document's bounds. The value of the pixels rendered outside the - * document bounds is not yet defined. - * - * The caller of this method must have UniversalXPConnect - * privileges. + * @DEPRECATED See nsIDOMWindowUtils_MOZILLA_2_0_BRANCH. */ void setDisplayPort(in float aXPx, in float aYPx, in float aWidthPx, in float aHeightPx); @@ -824,7 +801,7 @@ interface nsIDOMWindowUtils : nsISupports { typedef unsigned long long nsViewID; -[scriptable, uuid(be2e28c8-64f8-4100-906d-8a451ddd6835)] +[scriptable, uuid(7ad49829-e631-4cdd-a237-95847d9bcbe6)] interface nsIDOMWindowUtils_MOZILLA_2_0_BRANCH : nsISupports { /** * Get the type of the currently focused html input, if any. @@ -838,6 +815,36 @@ interface nsIDOMWindowUtils_MOZILLA_2_0_BRANCH : nsISupports { */ nsIDOMElement findElementWithViewId(in nsViewID aId); + /** + * For any scrollable element, this allows you to override the + * visible region and draw more than what is visible, which is + * useful for asynchronous drawing. The "displayport" will be + * in units of CSS pixels, + * regardless of the size of the enclosing container. This + * will *not* trigger reflow. + * + * For the root scroll area, pass in the root document element. + * For scrollable elements, pass in the container element (for + * instance, the element with overflow: scroll). + * + * is relative to the top-left of what would normally be + * the visible area of the element. This means that the pixels + * rendered to the displayport take scrolling into account, + * for example. + * + * It's legal to set a displayport that extends beyond the overflow + * area in any direction (left/right/top/bottom). + * + * It's also legal to set a displayport that extends beyond the + * area's bounds. No pixels are rendered outside the area bounds. + * + * The caller of this method must have UniversalXPConnect + * privileges. + */ + void setDisplayPortForElement(in float aXPx, in float aYPx, + in float aWidthPx, in float aHeightPx, + in nsIDOMElement aElement); + /** * Same as enterModalState, but returns the window associated with the * current JS context. diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index f46588d93638..7306602b923e 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -1295,7 +1295,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, item->GetLayerState(mBuilder, mManager); // Assign the item to a layer - if (layerState == LAYER_ACTIVE && (aClip.mRoundedClipRects.IsEmpty() || + if (layerState == LAYER_ACTIVE_FORCE || + layerState == LAYER_ACTIVE && (aClip.mRoundedClipRects.IsEmpty() || // We can use the visible rect here only because the item has its own // layer, like the comment below. !aClip.IsRectClippedByRoundedCorner(item->GetVisibleRect()))) { diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index b4c7135f8f29..8a4137fb624f 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -56,7 +56,10 @@ namespace mozilla { enum LayerState { LAYER_NONE, LAYER_INACTIVE, - LAYER_ACTIVE + LAYER_ACTIVE, + // Force an active layer even if it causes incorrect rendering, e.g. + // when the layer has rounded rect clips. + LAYER_ACTIVE_FORCE }; /** diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index fd665e269b9b..41f9cc199929 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -149,12 +149,13 @@ static void UnmarkFrameForDisplay(nsIFrame* aFrame) { } static void RecordFrameMetrics(nsIFrame* aForFrame, + nsIFrame* aViewportFrame, ContainerLayer* aRoot, nsRect aVisibleRect, nsRect aViewport, + nsRect aDisplayPort, ViewID aScrollId) { nsPresContext* presContext = aForFrame->PresContext(); - nsIPresShell* presShell = presContext->GetPresShell(); nsIntRect visible = aVisibleRect.ToNearestPixels(presContext->AppUnitsPerDevPixel()); aRoot->SetVisibleRegion(nsIntRegion(visible)); @@ -163,23 +164,23 @@ static void RecordFrameMetrics(nsIFrame* aForFrame, PRInt32 auPerDevPixel = presContext->AppUnitsPerDevPixel(); metrics.mViewport = aViewport.ToNearestPixels(auPerDevPixel); - if (presShell->UsingDisplayPort()) { - metrics.mDisplayPort = - presShell->GetDisplayPort().ToNearestPixels(auPerDevPixel); + if (aViewport != aDisplayPort) { + metrics.mDisplayPort = aDisplayPort.ToNearestPixels(auPerDevPixel); } - nsIScrollableFrame* rootScrollableFrame = - presShell->GetRootScrollFrameAsScrollable(); - if (rootScrollableFrame) { - nsSize contentSize = - rootScrollableFrame->GetScrollRange().Size() + - rootScrollableFrame->GetScrollPortRect().Size(); + nsIScrollableFrame* scrollableFrame = NULL; + if (aViewportFrame) + scrollableFrame = aViewportFrame->GetScrollTargetFrame(); + + if (scrollableFrame) { + nsSize contentSize = + scrollableFrame->GetScrollRange().Size() + + scrollableFrame->GetScrollPortRect().Size(); metrics.mContentSize = nsIntSize(NSAppUnitsToIntPixels(contentSize.width, auPerDevPixel), NSAppUnitsToIntPixels(contentSize.height, auPerDevPixel)); metrics.mViewportScrollOffset = - rootScrollableFrame->GetScrollPosition().ToNearestPixels(auPerDevPixel); - + scrollableFrame->GetScrollPosition().ToNearestPixels(auPerDevPixel); } else { nsSize contentSize = aForFrame->GetSize(); @@ -523,7 +524,18 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, ViewID id = presContext->IsRootContentDocument() ? FrameMetrics::ROOT_SCROLL_ID : FrameMetrics::NULL_SCROLL_ID; - RecordFrameMetrics(aForFrame, root, mVisibleRect, mVisibleRect, id); + nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); + nsRect visibleRect = mVisibleRect; + if (rootScrollFrame) { + nsIContent* content = rootScrollFrame->GetContent(); + if (content) { + // If there is a displayport defined for the root content element, + // it will be stored in visibleRect. + nsLayoutUtils::GetDisplayPort(content, &visibleRect); + } + } + RecordFrameMetrics(aForFrame, presShell->GetRootScrollFrame(), + root, mVisibleRect, mVisibleRect, visibleRect, id); // If the layer manager supports resolution scaling, set that up if (LayerManager::LAYERS_BASIC == layerManager->GetBackendType()) { @@ -1694,9 +1706,11 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder, nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, nsDisplayList* aList, nsIFrame* aForFrame, - nsIFrame* aViewportFrame) + nsIFrame* aViewportFrame, + const nsRect& aDisplayPort) : nsDisplayOwnLayer(aBuilder, aForFrame, aList) , mViewportFrame(aViewportFrame) + , mDisplayPort(aDisplayPort) { #ifdef NS_BUILD_REFCNT_LOGGING MOZ_COUNT_CTOR(nsDisplayScrollLayer); @@ -1721,7 +1735,8 @@ nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder, mViewportFrame->GetPosition() + aBuilder->ToReferenceFrame(mViewportFrame); - RecordFrameMetrics(mFrame, layer, mVisibleRect, viewport, scrollId); + RecordFrameMetrics(mFrame, mViewportFrame, layer, mVisibleRect, viewport, + mDisplayPort, scrollId); return layer.forget(); } @@ -1733,14 +1748,17 @@ nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder, PRBool& aContainsRootContentDocBG) { nsPresContext* presContext = mFrame->PresContext(); - nsIPresShell* presShell = presContext->GetPresShell(); - if (presShell->UsingDisplayPort()) { + nsRect viewport = mViewportFrame->GetRect() - + mViewportFrame->GetPosition() + + aBuilder->ToReferenceFrame(mViewportFrame); + + if (mDisplayPort != viewport) { // The visible region for the children may be much bigger than the hole we // are viewing the children from, so that the compositor process has enough // content to asynchronously pan while content is being refreshed. - nsRegion childVisibleRegion = presShell->GetDisplayPort() + aBuilder->ToReferenceFrame(mViewportFrame); + nsRegion childVisibleRegion = mDisplayPort + aBuilder->ToReferenceFrame(mViewportFrame); nsRect boundedRect; boundedRect.IntersectRect(childVisibleRegion.GetBounds(), mList.GetBounds(aBuilder)); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index f43c0db5cb2a..0fe4596d55f4 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1790,9 +1790,12 @@ class nsDisplayScrollLayer : public nsDisplayOwnLayer * @param aForFrame This will determine what the displayport is. It should be * the root content frame of the scrolled area. * @param aViewportFrame The viewport frame you see this content through. + * @param aDisplayPort Overrides the visibility of the child items if it + * is not equal to the visible area. */ nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, nsDisplayList* aList, - nsIFrame* aForFrame, nsIFrame* aViewportFrame); + nsIFrame* aForFrame, nsIFrame* aViewportFrame, + const nsRect& aDisplayPort); NS_DISPLAY_DECL_NAME("ScrollLayer", TYPE_SCROLL_LAYER) #ifdef NS_BUILD_REFCNT_LOGGING @@ -1807,8 +1810,16 @@ class nsDisplayScrollLayer : public nsDisplayOwnLayer const nsRect& aAllowVisibleRegionExpansion, PRBool& aContainsRootContentDocBG); + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager) + { + // Force this as a layer so we can scroll asynchronously. + // This causes incorrect rendering for rounded clips! + return mozilla::LAYER_ACTIVE_FORCE; + } private: nsIFrame* mViewportFrame; + nsRect mDisplayPort; }; #endif diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index de2343f10c46..c709200c5f6a 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -1154,19 +1154,21 @@ class nsIPresShell : public nsIPresShell_base * Set up a "displayport", which overrides what everything else thinks * is the visible region of this document with the specified * displayport rect. + * @DEPRECATED Use nsLayoutUtils displayport methods */ virtual void SetDisplayPort(const nsRect& aDisplayPort) = 0; PRBool UsingDisplayPort() const - { return mRenderFlags & STATE_USING_DISPLAYPORT; } + { NS_ABORT_IF_FALSE(false, "UsingDisplayPort is deprecated"); return false; } /** * Return the displayport being used. |UsingDisplayPort()| must be * true. + * @DEPRECATED Use nsLayoutUtils displayport methods */ nsRect GetDisplayPort() { - NS_ABORT_IF_FALSE(UsingDisplayPort(), "no displayport defined!"); - return mDisplayPort; + NS_ABORT_IF_FALSE(false, "GetDisplayPort is deprecated"); + return nsRect(); } /** diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index af437cdff059..07a7b58a7f7f 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -143,6 +143,10 @@ static void DestroyViewID(void* aObject, nsIAtom* aPropertyName, delete id; } +/** + * A namespace class for static layout utilities. + */ + ViewID nsLayoutUtils::FindIDFor(nsIContent* aContent) { @@ -177,9 +181,19 @@ nsLayoutUtils::FindContentFor(ViewID aId) } } -/** - * A namespace class for static layout utilities. - */ +bool +nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult) +{ + void* property = aContent->GetProperty(nsGkAtoms::DisplayPort); + if (!property) { + return false; + } + + if (aResult) { + *aResult = *static_cast(property); + } + return true; +} nsIFrame* nsLayoutUtils::GetLastContinuationWithChild(nsIFrame* aFrame) @@ -1368,6 +1382,16 @@ nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFra nsPresContext* presContext = aFrame->PresContext(); nsIPresShell* presShell = presContext->PresShell(); + nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); + bool usingDisplayPort = false; + nsRect displayport; + if (rootScrollFrame) { + nsIContent* content = rootScrollFrame->GetContent(); + if (content) { + usingDisplayPort = nsLayoutUtils::GetDisplayPort(content, &displayport); + } + } + PRBool ignoreViewportScrolling = presShell->IgnoringViewportScrolling(); nsRegion visibleRegion; if (aFlags & PAINT_WIDGET_LAYERS) { @@ -1377,10 +1401,10 @@ nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFra // |ignoreViewportScrolling| and |usingDisplayPort| are persistent // document-rendering state. We rely on PresShell to flush // retained layers as needed when that persistent state changes. - if (!presShell->UsingDisplayPort()) { + if (!usingDisplayPort) { visibleRegion = aFrame->GetVisualOverflowRectRelativeToSelf(); } else { - visibleRegion = presShell->GetDisplayPort(); + visibleRegion = displayport; } } else { visibleRegion = aDirtyRegion; diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 1c43364a74e4..1eeca3b075d6 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -94,6 +94,11 @@ class nsLayoutUtils */ static nsIContent* FindContentFor(ViewID aId); + /** + * Get display port for the given element. + */ + static bool GetDisplayPort(nsIContent* aContent, nsRect *aResult); + /** * Use heuristics to figure out the name of the child list that * aChildFrame is currently in. diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 388f87e938d9..b0c02ea48494 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1037,12 +1037,10 @@ class PresShell : public nsIPresShell, public nsIViewObserver, struct RenderingState { RenderingState(PresShell* aPresShell) : mRenderFlags(aPresShell->mRenderFlags) - , mDisplayPort(aPresShell->mDisplayPort) , mXResolution(aPresShell->mXResolution) , mYResolution(aPresShell->mYResolution) { } PRUint32 mRenderFlags; - nsRect mDisplayPort; float mXResolution; float mYResolution; }; @@ -1056,7 +1054,6 @@ class PresShell : public nsIPresShell, public nsIViewObserver, ~AutoSaveRestoreRenderingState() { mPresShell->mRenderFlags = mOldState.mRenderFlags; - mPresShell->mDisplayPort = mOldState.mDisplayPort; mPresShell->mXResolution = mOldState.mXResolution; mPresShell->mYResolution = mOldState.mYResolution; } @@ -6017,14 +6014,7 @@ void PresShell::SetIgnoreViewportScrolling(PRBool aIgnore) void PresShell::SetDisplayPort(const nsRect& aDisplayPort) { - if (UsingDisplayPort() && mDisplayPort == aDisplayPort) { - return; - } - RenderingState state(this); - state.mRenderFlags = ChangeFlag(mRenderFlags, PR_TRUE, - STATE_USING_DISPLAYPORT); - state.mDisplayPort = aDisplayPort; - SetRenderingState(state); + NS_ABORT_IF_FALSE(false, "SetDisplayPort is deprecated"); } nsresult PresShell::SetResolution(float aXResolution, float aYResolution) @@ -6054,11 +6044,6 @@ void PresShell::SetRenderingState(const RenderingState& aState) } mRenderFlags = aState.mRenderFlags; - if (UsingDisplayPort()) { - mDisplayPort = aState.mDisplayPort; - } else { - mDisplayPort = nsRect(); - } mXResolution = aState.mXResolution; mYResolution = aState.mYResolution; @@ -6066,16 +6051,6 @@ void PresShell::SetRenderingState(const RenderingState& aState) if (NS_SUCCEEDED(mViewManager->GetRootView(rootView)) && rootView) { rootView->SetInvalidationDimensions(&mDisplayPort); } - - nsPresContext* rootPresContext = mPresContext->GetRootPresContext(); - if (rootPresContext) { - nsIPresShell* rootPresShell = rootPresContext->GetPresShell(); - nsIFrame* rootFrame = rootPresShell->FrameManager()->GetRootFrame(); - if (rootFrame) { - rootFrame->InvalidateWithFlags(rootFrame->GetVisualOverflowRectRelativeToSelf(), - nsIFrame::INVALIDATE_NO_THEBES_LAYERS); - } - } } void PresShell::SynthesizeMouseMove(PRBool aFromScroll) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index edd2efe8d477..9815e533c10e 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1879,9 +1879,12 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, scrollParts, createLayersForScrollbars); } - nsIPresShell* presShell = mOuter->PresContext()->GetPresShell(); - nsRect scrollPort = (mIsRoot && presShell->UsingDisplayPort()) ? - (presShell->GetDisplayPort()) : mScrollPort; + nsRect displayport; + PRBool usingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), + &displayport); + if (!usingDisplayPort) { + displayport = mScrollPort; + } // 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 @@ -1892,18 +1895,69 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder, // had dirty rects saved for them by their parent frames calling // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our // dirty rect here. - dirtyRect.IntersectRect(aDirtyRect, scrollPort); + dirtyRect.IntersectRect(aDirtyRect, mScrollPort); + + if (usingDisplayPort) { + dirtyRect = displayport; + } nsDisplayListCollection set; - rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set); + + nsPresContext* presContext = mOuter->PresContext(); + PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); + +#ifdef MOZ_IPC + // Since making new layers is expensive, only use nsDisplayScrollLayer + // if the area is scrollable. + // + // Scroll frames can be generated with a scroll range that is 0, 0. + // Furthermore, it is not worth the memory tradeoff to allow asynchronous + // scrolling of small scroll frames. We use an arbitrary minimum scroll + // range of 20 pixels to eliminate many gfx scroll frames from becoming a + // layer. + // + nsRect scrollRange = GetScrollRange(); + PRBool buildingLayer = + (XRE_GetProcessType() == GeckoProcessType_Content && + (scrollRange.width >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel) || + scrollRange.height >= NSIntPixelsToAppUnits(20, appUnitsPerDevPixel))) && + (!mIsRoot || !mOuter->PresContext()->IsRootContentDocument()); + +#else + PRBool buildingLayer = false; +#endif + + if (buildingLayer) { + // Note that using StackingContext breaks z order, so the resulting + // rendering can be incorrect for weird edge cases! + + rv = mScrolledFrame->BuildDisplayListForStackingContext( + aBuilder, + dirtyRect + mOuter->GetOffsetTo(mScrolledFrame), + set.Content() + ); + + nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer( + aBuilder, + set.Content(), + mScrolledFrame, + mOuter, + displayport + ); + set.Content()->AppendNewToTop(layerItem); + } else { + rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set); + } + NS_ENSURE_SUCCESS(rv, rv); nsRect clip; - clip = scrollPort + aBuilder->ToReferenceFrame(mOuter); + clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter); nscoord radii[8]; // Our override of GetBorderRadii ensures we never have a radius at // the corners where we have a scrollbar. mOuter->GetPaddingBoxBorderRadii(radii); + // mScrolledFrame may have given us a background, e.g., the scrolled canvas // frame below the viewport. If so, we want it to be clipped. We also want // to end up on our BorderBackground list. diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 3426f50ec941..4fd1470140e2 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -340,32 +340,12 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, PRInt32 parentAPD = PresContext()->AppUnitsPerDevPixel(); PRInt32 subdocAPD = presContext->AppUnitsPerDevPixel(); - nsIFrame* subdocRootScrollFrame = presShell->GetRootScrollFrame(); - nsRect dirty; if (subdocRootFrame) { - if (presShell->UsingDisplayPort() && subdocRootScrollFrame) { - dirty = presShell->GetDisplayPort(); - - // The visual overflow rect of our viewport frame unfortunately may not - // intersect with the displayport of that frame. For example, the scroll - // offset of the frame may be (0, 0) so that the visual overflow rect - // is (0, 0, 800px, 500px) while the display port may have its top-left - // corner below y=500px. - // - // We have to force the frame to have a little faith and build a display - // list anyway. (see nsIFrame::BuildDisplayListForChild for the short- - // circuit code we are evading here). - // - subdocRootScrollFrame->AddStateBits( - NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO); - - } else { - // get the dirty rect relative to the root frame of the subdoc - dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); - // and convert into the appunits of the subdoc - dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); - } + // get the dirty rect relative to the root frame of the subdoc + dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame); + // and convert into the appunits of the subdoc + dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD); aBuilder->EnterPresShell(subdocRootFrame, dirty); } @@ -425,32 +405,6 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, bool addedLayer = false; -#ifdef MOZ_IPC - // Make a scrollable layer in the child process so it can be manipulated - // with transforms in the parent process. - if (XRE_GetProcessType() == GeckoProcessType_Content) { - nsIScrollableFrame* scrollFrame = presShell->GetRootScrollFrameAsScrollable(); - - if (scrollFrame) { - NS_ASSERTION(subdocRootFrame, "Root scroll frame should be non-null"); - nsRect scrollRange = scrollFrame->GetScrollRange(); - - // Since making new layers is expensive, only use nsDisplayScrollLayer - // if the area is scrollable. - if (scrollRange.width != 0 || scrollRange.height != 0) { - addedLayer = true; - nsDisplayScrollLayer* layerItem = new (aBuilder) nsDisplayScrollLayer( - aBuilder, - &childItems, - subdocRootScrollFrame, - subdocRootFrame - ); - childItems.AppendToTop(layerItem); - } - } - } -#endif - if (subdocRootFrame && parentAPD != subdocAPD) { NS_WARN_IF_FALSE(!addedLayer, "Two container layers have been added. " diff --git a/layout/ipc/test-ipcbrowser-content.js b/layout/ipc/test-ipcbrowser-content.js index a31e9ef63da1..8fe6e3721758 100644 --- a/layout/ipc/test-ipcbrowser-content.js +++ b/layout/ipc/test-ipcbrowser-content.js @@ -3,6 +3,11 @@ function windowUtils() { .getInterface(Components.interfaces.nsIDOMWindowUtils); } +function windowUtils20() { + return windowUtils() + .QueryInterface(Components.interfaces.nsIDOMWindowUtils_MOZILLA_2_0_BRANCH); +} + function recvSetViewport(w, h) { dump("setting viewport to "+ w +"x"+ h +"\n"); @@ -14,7 +19,7 @@ function recvSetDisplayPort(x, y, w, h) { dump("setting displayPort to <"+ x +", "+ y +", "+ w +", "+ h +">\n"); - windowUtils().setDisplayPort(x, y, w, h); + windowUtils20().setDisplayPortForElement(x, y, w, h, content.document.documentElement); } function recvSetResolution(xres, yres) { diff --git a/layout/tools/reftest/reftest-content.js b/layout/tools/reftest/reftest-content.js index f648af311294..4b2abd2f69ea 100644 --- a/layout/tools/reftest/reftest-content.js +++ b/layout/tools/reftest/reftest-content.js @@ -120,6 +120,11 @@ function windowUtils() { .getInterface(CI.nsIDOMWindowUtils); } +function windowUtils20() { + return windowUtils() + .QueryInterface(Components.interfaces.nsIDOMWindowUtils_MOZILLA_2_0_BRANCH); +} + function IDForEventTarget(event) { try { @@ -253,7 +258,7 @@ function setupDisplayport(contentRootElement) { var dph = attrOrDefault("reftest-displayport-h", 0); if (dpw !== 0 || dph !== 0) { LogInfo("Setting displayport to "); - windowUtils().setDisplayPort(0, 0, dpw, dph); + windowUtils20().setDisplayPortForElement(0, 0, dpw, dph, content.document.documentElement); } // XXX support resolution when needed