diff --git a/content/base/public/nsIFrameLoader.idl b/content/base/public/nsIFrameLoader.idl index 1c19499dd8ef..ec54aad9d23a 100644 --- a/content/base/public/nsIFrameLoader.idl +++ b/content/base/public/nsIFrameLoader.idl @@ -45,6 +45,90 @@ interface nsIFrame; interface nsIChromeFrameMessageManager; interface nsIVariant; +typedef unsigned long long nsContentViewId; + +/** + * These interfaces do *not* scroll or scale the content document; + * instead they set a "goal" scroll/scale wrt the current content + * view. When the content document is painted, the scroll* + * attributes are used to set a compensating transform. If the + * metrics of the content document's current pixels don't match the + * view config, the transform matrix may need to translate + * content pixels and/or perform a "fuzzy-scale" that doesn't + * re-rasterize fonts or intelligently resample images. + * + * The attrs are allowed to transform content pixels in + * such a way that the 's visible rect encloses pixels that + * the content document does not (yet) define. + * + * The view scroll values are in units of chrome-document CSS + * pixels. + * + * These APIs are designed to be used with nsIDOMWindowUtils + * setDisplayPort() and setResolution(). + */ +[scriptable, uuid(fbd25468-d2cf-487b-bc58-a0e105398b47)] +interface nsIContentView : nsISupports +{ + /** + * Scroll view to or by the given chrome-document CSS pixels. + * Fails if the view is no longer valid. + */ + void scrollTo(in float xPx, in float yPx); + void scrollBy(in float dxPx, in float dyPx); + + void setScale(in float xScale, in float yScale); + + /** + * Scroll offset in chrome-document CSS pixels. + * + * When this view is active (i.e. it is being painted because it's in the + * visible region of the screen), this value is at first lined up with the + * content's scroll offset. + * + * Note that when this view becomes inactive, the new content view will have + * scroll values that are reset to the default! + */ + readonly attribute float scrollX; + readonly attribute float scrollY; + + /** + * ID that can be used in conjunction with nsIDOMWindowUtils to change + * the actual document, instead of just how it is transformed. + */ + readonly attribute nsContentViewId id; +}; + +[scriptable, uuid(ba5af90d-ece5-40b2-9a1d-a0154128db1c)] +interface nsIContentViewManager : nsISupports +{ + /** + * Retrieve view scrolling/scaling interfaces in a given area, + * used to support asynchronous re-paints of content pixels. + * These interfaces are only meaningful for . + * + * Pixels are in chrome device pixels and are relative to the browser + * element. + * + * @param aX x coordinate that will be in target rectangle + * @param aY y coordinate that will be in target rectangle + * @param aTopSize How much to expand up the rectangle + * @param aRightSize How much to expand right the rectangle + * @param aBottomSize How much to expand down the rectangle + * @param aLeftSize How much to expand left the rectangle + */ + void getContentViewsIn(in float aXPx, in float aYPx, + in float aTopSize, in float aRightSize, + in float aBottomSize, in float aLeftSize, + [optional] out unsigned long aLength, + [retval, array, size_is(aLength)] out nsIContentView aResult); + + /** + * The root content view. + */ + readonly attribute nsIContentView rootContentView; +}; + [scriptable, uuid(50a67436-bb44-11df-8d9a-001e37d2764a)] interface nsIFrameLoader : nsISupports { @@ -121,34 +205,14 @@ interface nsIFrameLoader : nsISupports attribute boolean delayRemoteDialogs; + /** - * Implement viewport scrolling/scaling, used to support - * asynchronous re-paints of content pixels. These interfaces are - * only meaningful for . - * - * These interfaces do *not* scroll or scale the content document; - * instead they set a "goal" scroll/scale wrt the current content - * viewport. When the content document is painted, the viewport* - * attributes are used to set a compensating transform. If the - * metrics of the content document's current pixels don't match the - * viewport* config, the transform matrix may need to translate - * content pixels and/or perform a "fuzzy-scale" that doesn't - * re-rasterize fonts or intelligently resample images. - * - * The viewport* attrs are allowed to transform content pixels in - * such a way that the 's visible rect encloses pixels that - * the content document does not (yet) define. - * - * The viewport scroll values are in units of chrome-document CSS - * pixels. - * - * These APIs are designed to be used with nsIDOMWindowUtils - * setDisplayPort() and setResolution(). + * DEPRECATED. Please QI to nsIContentViewManager. + * FIXME 615368 */ void scrollViewportTo(in float xPx, in float yPx); void scrollViewportBy(in float dxPx, in float dyPx); void setViewportScale(in float xScale, in float yScale); - readonly attribute float viewportScrollX; readonly attribute float viewportScrollY; }; diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index a65e11397660..2c4a2dd768f5 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -110,6 +110,8 @@ #include "mozilla/AutoRestore.h" #include "mozilla/unused.h" +#include "Layers.h" + #ifdef MOZ_IPC #include "ContentParent.h" #include "TabParent.h" @@ -118,6 +120,8 @@ using namespace mozilla; using namespace mozilla::dom; #endif +using namespace mozilla::layers; + #include "jsapi.h" class nsAsyncDocShellDestroyer : public nsRunnable @@ -139,6 +143,106 @@ public: nsRefPtr mDocShell; }; +static void InvalidateFrame(nsIFrame* aFrame) +{ + nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size()); + // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view + // semantics the same for both in-process and out-of-process + // . This is just a transform of the layer subtree in + // both. + aFrame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS); +} + +NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView) + +bool +nsContentView::IsRoot() const +{ + return mScrollId == FrameMetrics::ROOT_SCROLL_ID; +} + +nsresult +nsContentView::Update(const ViewConfig& aConfig) +{ + if (aConfig == mConfig) { + return NS_OK; + } + mConfig = aConfig; + + // View changed. Try to locate our subdoc frame and invalidate + // it if found. + if (!mOwnerContent) { + if (IsRoot()) { + // Oops, don't have a frame right now. That's OK; the view + // config persists and will apply to the next frame we get, if we + // ever get one. + return NS_OK; + } else { + // This view is no longer valid. + return NS_ERROR_NOT_AVAILABLE; + } + } + + nsIFrame* frame = mOwnerContent->GetPrimaryFrame(); + + // XXX could be clever here and compute a smaller invalidation + // rect + InvalidateFrame(frame); + return NS_OK; +} + +NS_IMETHODIMP +nsContentView::ScrollTo(float aXpx, float aYpx) +{ + ViewConfig config(mConfig); + config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx), + nsPresContext::CSSPixelsToAppUnits(aYpx)); + return Update(config); +} + +NS_IMETHODIMP +nsContentView::ScrollBy(float aDXpx, float aDYpx) +{ + ViewConfig config(mConfig); + config.mScrollOffset.MoveBy(nsPresContext::CSSPixelsToAppUnits(aDXpx), + nsPresContext::CSSPixelsToAppUnits(aDYpx)); + return Update(config); +} + +NS_IMETHODIMP +nsContentView::SetScale(float aXScale, float aYScale) +{ + ViewConfig config(mConfig); + config.mXScale = aXScale; + config.mYScale = aYScale; + return Update(config); +} + +NS_IMETHODIMP +nsContentView::GetScrollX(float* aViewScrollX) +{ + *aViewScrollX = nsPresContext::AppUnitsToFloatCSSPixels( + mConfig.mScrollOffset.x); + return NS_OK; +} + +NS_IMETHODIMP +nsContentView::GetScrollY(float* aViewScrollY) +{ + *aViewScrollY = nsPresContext::AppUnitsToFloatCSSPixels( + mConfig.mScrollOffset.y); + return NS_OK; +} + +NS_IMETHODIMP +nsContentView::GetId(nsContentViewId* aId) +{ + NS_ASSERTION(sizeof(nsContentViewId) == sizeof(ViewID), + "ID size for XPCOM ID and internal ID type are not the same!"); + *aId = mScrollId; + return NS_OK; +} + // Bug 136580: Limit to the number of nested content frames that can have the // same URL. This is to stop content that is recursively loading // itself. Note that "#foo" on the end of URL doesn't affect @@ -177,9 +281,31 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsFrameLoader, nsIFrameLoader) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader) NS_INTERFACE_MAP_ENTRY(nsIFrameLoader) NS_INTERFACE_MAP_ENTRY(nsIFrameLoader_MOZILLA_2_0_BRANCH) + NS_INTERFACE_MAP_ENTRY(nsIContentViewManager) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader) NS_INTERFACE_MAP_END +nsFrameLoader::nsFrameLoader(nsIContent *aOwner, PRBool aNetworkCreated) + : mOwnerContent(aOwner) + , mDepthTooGreat(PR_FALSE) + , mIsTopLevelContent(PR_FALSE) + , mDestroyCalled(PR_FALSE) + , mNeedsAsyncDestroy(PR_FALSE) + , mInSwap(PR_FALSE) + , mInShow(PR_FALSE) + , mHideCalled(PR_FALSE) + , mNetworkCreated(aNetworkCreated) +#ifdef MOZ_IPC + , mDelayRemoteDialogs(PR_FALSE) + , mRemoteBrowserShown(PR_FALSE) + , mRemoteFrame(false) + , mCurrentRemoteFrame(nsnull) + , mRemoteBrowser(nsnull) +#endif + , mContentView(new nsContentView(aOwner, FrameMetrics::ROOT_SCROLL_ID)) +{ +} + nsFrameLoader* nsFrameLoader::Create(nsIContent* aOwner, PRBool aNetworkCreated) { @@ -997,8 +1123,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther, ourWindow->SetFrameElementInternal(otherFrameElement); otherWindow->SetFrameElementInternal(ourFrameElement); - mOwnerContent = otherContent; - aOther->mOwnerContent = ourContent; + SetOwnerContent(otherContent); + aOther->SetOwnerContent(ourContent); nsRefPtr ourMessageManager = mMessageManager; nsRefPtr otherMessageManager = aOther->mMessageManager; @@ -1099,7 +1225,7 @@ nsFrameLoader::Destroy() doc->SetSubDocumentFor(mOwnerContent, nsnull); } - mOwnerContent = nsnull; + SetOwnerContent(nsnull); } DestroyChild(); @@ -1154,6 +1280,12 @@ nsFrameLoader::GetDepthTooGreat(PRBool* aDepthTooGreat) return NS_OK; } +void +nsFrameLoader::SetOwnerContent(nsIContent* aContent) +{ + mOwnerContent = aContent; +} + #ifdef MOZ_IPC bool nsFrameLoader::ShouldUseRemoteProcess() @@ -1505,95 +1637,49 @@ nsFrameLoader::UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame) NS_IMETHODIMP nsFrameLoader::ScrollViewportTo(float aXpx, float aYpx) { - ViewportConfig config(mViewportConfig); - config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx), - nsPresContext::CSSPixelsToAppUnits(aYpx)); - return UpdateViewportConfig(config); + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsFrameLoader::ScrollViewportBy(float aDXpx, float aDYpx) { - ViewportConfig config(mViewportConfig); - config.mScrollOffset.MoveBy(nsPresContext::CSSPixelsToAppUnits(aDXpx), - nsPresContext::CSSPixelsToAppUnits(aDYpx)); - return UpdateViewportConfig(config); + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsFrameLoader::SetViewportScale(float aXScale, float aYScale) { - ViewportConfig config(mViewportConfig); - config.mXScale = aXScale; - config.mYScale = aYScale; - return UpdateViewportConfig(config); + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsFrameLoader::GetViewportScrollX(float* aViewportScrollX) { - *aViewportScrollX = - nsPresContext::AppUnitsToFloatCSSPixels(mViewportConfig.mScrollOffset.x); - return NS_OK; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsFrameLoader::GetViewportScrollY(float* aViewportScrollY) { - *aViewportScrollY = - nsPresContext::AppUnitsToFloatCSSPixels(mViewportConfig.mScrollOffset.y); - return NS_OK; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsFrameLoader::GetRenderMode(PRUint32* aRenderMode) { - *aRenderMode = mViewportConfig.mRenderMode; + *aRenderMode = mRenderMode; return NS_OK; } NS_IMETHODIMP nsFrameLoader::SetRenderMode(PRUint32 aRenderMode) { - ViewportConfig config(mViewportConfig); - config.mRenderMode = aRenderMode; - return UpdateViewportConfig(config); -} - -nsresult -nsFrameLoader::UpdateViewportConfig(const ViewportConfig& aNewConfig) -{ - if (aNewConfig == mViewportConfig) { - return NS_OK; - } else if (!mViewportConfig.AsyncScrollEnabled() && - !aNewConfig.AsyncScrollEnabled()) { - // The target viewport can't be set in synchronous mode - return NS_ERROR_NOT_AVAILABLE; - } - // XXX if we go from disabled->enabled, should we clear out the old - // config? Or what? - - mViewportConfig = aNewConfig; - - // Viewport changed. Try to locate our subdoc frame and invalidate - // it if found. - nsIFrame* frame = GetPrimaryFrameOfOwningContent(); - if (!frame) { - // Oops, don't have a frame right now. That's OK; the viewport - // config persists and will apply to the next frame we get, if we - // ever get one. + if (aRenderMode == mRenderMode) { return NS_OK; } - // XXX could be clever here and compute a smaller invalidation - // rect - nsRect rect = nsRect(nsPoint(0, 0), frame->GetRect().Size()); - // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep viewport - // semantics the same for both in-process and out-of-process - // . This is just a transform of the layer subtree in - // both. - frame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS); - + mRenderMode = aRenderMode; + InvalidateFrame(GetPrimaryFrameOfOwningContent()); return NS_OK; } @@ -1882,6 +1968,25 @@ nsFrameLoader::GetMessageManager(nsIChromeFrameMessageManager** aManager) return NS_OK; } +NS_IMETHODIMP +nsFrameLoader::GetContentViewsIn(float aXPx, float aYPx, + float aTopSize, float aRightSize, + float aBottomSize, float aLeftSize, + PRUint32* aLength, + nsIContentView*** aResult) +{ + *aResult = nsnull; + *aLength = 0; + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::GetRootContentView(nsIContentView** aContentView) +{ + nsRefPtr(GetContentView()).forget(aContentView); + return NS_OK; +} + nsresult nsFrameLoader::EnsureMessageManager() { diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h index ec3d8818a09b..9f1e6be29292 100644 --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -52,6 +52,7 @@ #include "nsIURI.h" #include "nsAutoPtr.h" #include "nsFrameMessageManager.h" +#include "Layers.h" class nsIContent; class nsIURI; @@ -80,73 +81,38 @@ class QX11EmbedContainer; #endif #endif -class nsFrameLoader : public nsIFrameLoader, - public nsIFrameLoader_MOZILLA_2_0_BRANCH +/** + * Defines a target configuration for this 's content + * document's view. If the content document's actual view + * doesn't match this nsIContentView, then on paints its pixels + * are transformed to compensate for the difference. + * + * Used to support asynchronous re-paints of content pixels; see + * nsIContentView. + */ +class nsContentView : public nsIContentView { - friend class AutoResetInShow; -#ifdef MOZ_IPC - typedef mozilla::dom::PBrowserParent PBrowserParent; - typedef mozilla::dom::TabParent TabParent; - typedef mozilla::layout::RenderFrameParent RenderFrameParent; -#endif - -protected: - nsFrameLoader(nsIContent *aOwner, PRBool aNetworkCreated) : - mOwnerContent(aOwner), - mDepthTooGreat(PR_FALSE), - mIsTopLevelContent(PR_FALSE), - mDestroyCalled(PR_FALSE), - mNeedsAsyncDestroy(PR_FALSE), - mInSwap(PR_FALSE), - mInShow(PR_FALSE), - mHideCalled(PR_FALSE), - mNetworkCreated(aNetworkCreated) -#ifdef MOZ_IPC - , mDelayRemoteDialogs(PR_FALSE) - , mRemoteBrowserShown(PR_FALSE) - , mRemoteFrame(false) - , mCurrentRemoteFrame(nsnull) - , mRemoteBrowser(nsnull) -#endif - {} - public: - /** - * Defines a target configuration for this 's content - * document's viewport. If the content document's actual viewport - * doesn't match a desired ViewportConfig, then on paints its pixels - * are transformed to compensate for the difference. - * - * Used to support asynchronous re-paints of content pixels; see - * nsIFrameLoader.scrollViewport* and viewportScale. - */ - struct ViewportConfig { - ViewportConfig() - : mRenderMode(nsIFrameLoader_MOZILLA_2_0_BRANCH::RENDER_MODE_DEFAULT) - , mScrollOffset(0, 0) + typedef mozilla::layers::FrameMetrics::ViewID ViewID; + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTVIEW + + struct ViewConfig { + ViewConfig() + : mScrollOffset(0, 0) , mXScale(1.0) , mYScale(1.0) {} // Default copy ctor and operator= are fine - PRBool operator==(const ViewportConfig& aOther) const + PRBool operator==(const ViewConfig& aOther) const { - return (mRenderMode == aOther.mRenderMode && - mScrollOffset == aOther.mScrollOffset && + return (mScrollOffset == aOther.mScrollOffset && mXScale == aOther.mXScale && mYScale == aOther.mYScale); } - PRBool AsyncScrollEnabled() const - { - return !!(mRenderMode & RENDER_MODE_ASYNC_SCROLL); - } - - // See nsIFrameLoader.idl. Short story, if !(mRenderMode & - // RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in - // favor of what content tells. - PRUint32 mRenderMode; // This is the scroll offset the user wishes or expects // its enclosed content document to have. "Scroll offset" here // means the document pixel at pixel (0,0) within the CSS @@ -163,6 +129,50 @@ public: float mYScale; }; + nsContentView(nsIContent* aOwnerContent, ViewID aScrollId, + ViewConfig aConfig = ViewConfig()) + : mOwnerContent(aOwnerContent) + , mScrollId(aScrollId) + , mConfig(aConfig) + {} + + bool IsRoot() const; + + ViewID GetId() const + { + return mScrollId; + } + + ViewConfig GetViewConfig() const + { + return mConfig; + } + + nsIContent *mOwnerContent; // WEAK + +private: + nsresult Update(const ViewConfig& aConfig); + + ViewID mScrollId; + ViewConfig mConfig; +}; + + +class nsFrameLoader : public nsIFrameLoader, + public nsIFrameLoader_MOZILLA_2_0_BRANCH, + public nsIContentViewManager +{ + friend class AutoResetInShow; +#ifdef MOZ_IPC + typedef mozilla::dom::PBrowserParent PBrowserParent; + typedef mozilla::dom::TabParent TabParent; + typedef mozilla::layout::RenderFrameParent RenderFrameParent; +#endif + +protected: + nsFrameLoader(nsIContent *aOwner, PRBool aNetworkCreated); + +public: ~nsFrameLoader() { mNeedsAsyncDestroy = PR_TRUE; if (mMessageManager) { @@ -177,6 +187,7 @@ public: NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameLoader, nsIFrameLoader) NS_DECL_NSIFRAMELOADER NS_DECL_NSIFRAMELOADER_MOZILLA_2_0_BRANCH + NS_DECL_NSICONTENTVIEWMANAGER NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI); nsresult ReallyStartLoading(); void Finalize(); @@ -261,7 +272,9 @@ public: #endif nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; } - const ViewportConfig& GetViewportConfig() { return mViewportConfig; } + nsContentView* GetContentView() { return mContentView; } + + void SetOwnerContent(nsIContent* aContent); private: @@ -295,8 +308,6 @@ private: bool ShowRemoteFrame(const nsIntSize& size); #endif - nsresult UpdateViewportConfig(const ViewportConfig& aNewConfig); - nsCOMPtr mDocShell; nsCOMPtr mURIToLoad; nsIContent *mOwnerContent; // WEAK @@ -327,7 +338,12 @@ private: TabParent* mRemoteBrowser; #endif - ViewportConfig mViewportConfig; + nsRefPtr mContentView; + + // See nsIFrameLoader.idl. Short story, if !(mRenderMode & + // RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in + // favor of what content tells. + PRUint32 mRenderMode; }; #endif diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index 6862d05f18ec..4bbc7fa1fb87 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -49,7 +49,7 @@ #include "nsViewportFrame.h" #include "nsSubDocumentFrame.h" -typedef nsFrameLoader::ViewportConfig ViewportConfig; +typedef nsContentView::ViewConfig ViewConfig; using namespace mozilla::layers; namespace mozilla { @@ -85,7 +85,7 @@ AssertValidContainerOfShadowTree(ContainerLayer* aContainer, static void ComputeShadowTreeTransform(nsIFrame* aContainerFrame, const FrameMetrics& aMetrics, - const ViewportConfig& aConfig, + const ViewConfig& aConfig, nsDisplayListBuilder* aBuilder, nsIntPoint* aShadowTranslation, float* aShadowXScale, @@ -286,7 +286,7 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, float shadowXScale, shadowYScale; ComputeShadowTreeTransform(aFrame, shadowRoot->GetFrameMetrics(), - mFrameLoader->GetViewportConfig(), + mFrameLoader->GetContentView()->GetViewConfig(), aBuilder, &shadowTranslation, &shadowXScale, &shadowYScale);