Bug 618249: Default remote-browser to synchronous scrolling, and let users change that. r=tn sr=roc a=a
authorChris Jones <jones.chris.g@gmail.com>
Tue, 11 Jan 2011 15:34:31 -0600
changeset 60322 bddac4e2bf745c8389c383f0ea3b2a54d887f4bd
parent 60321 7cad0cd7b62e3dd9088be1f9e7855718040dd7a9
child 60323 e2e5b5e57ca4a13c913c4aba789567ebf16fb6ec
push idunknown
push userunknown
push dateunknown
reviewerstn, roc, a
bugs618249
milestone2.0b10pre
Bug 618249: Default remote-browser to synchronous scrolling, and let users change that. r=tn sr=roc a=a
content/base/public/nsIFrameLoader.idl
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsObjectLoadingContent.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/html/content/src/nsGenericHTMLElement.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/test-ipcbrowser-chrome.js
--- a/content/base/public/nsIFrameLoader.idl
+++ b/content/base/public/nsIFrameLoader.idl
@@ -171,8 +171,30 @@ interface nsIFrameLoaderOwner : nsISuppo
    *
    * @throws NS_ERROR_NOT_IMPLEMENTED if the swapping logic is not
    *   implemented for the two given frame loader owners.
    * @throws NS_ERROR_DOM_SECURITY_ERR if the swap is not allowed on
    *   security grounds.
    */
   void swapFrameLoaders(in nsIFrameLoaderOwner aOtherOwner);
 };
+
+/** Please merge me into something else after 2.0 branches. */
+[scriptable, uuid(e3e2d3f8-1397-4984-abb3-435c29a1ca55)]
+interface nsIFrameLoader_MOZILLA_2_0_BRANCH : nsISupports
+{
+  /** 
+   * The default rendering mode is synchronous scrolling.  In this
+   * mode, it's an error to try to set a target viewport.
+   */
+  const unsigned long RENDER_MODE_DEFAULT        = 0x00000000;
+  /**
+   * When asynchronous scrolling is enabled, a target viewport can be
+   * set to transform content pixels wrt its CSS viewport.
+   *
+   * NB: when async scrolling is enabled, it's the *user's*
+   * responsibility to update the target scroll offset.  In effect,
+   * the platform hands over control of scroll offset to the user.
+   */
+  const unsigned long RENDER_MODE_ASYNC_SCROLL   = 0x00000001;
+
+  attribute unsigned long renderMode;
+};
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -166,22 +166,23 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameLoader)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocShell)
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsFrameLoader::mMessageManager");
   cb.NoteXPCOMChild(static_cast<nsIContentFrameMessageManager*>(tmp->mMessageManager.get()));
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChildMessageManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
+NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsFrameLoader, nsIFrameLoader)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsFrameLoader, nsIFrameLoader)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIFrameLoader_MOZILLA_2_0_BRANCH)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
 NS_INTERFACE_MAP_END
 
 nsFrameLoader*
 nsFrameLoader::Create(nsIContent* aOwner, PRBool aNetworkCreated)
 {
   NS_ENSURE_TRUE(aOwner, nsnull);
   nsIDocument* doc = aOwner->GetOwnerDoc();
   NS_ENSURE_TRUE(doc && !doc->GetDisplayDocument() &&
@@ -1539,22 +1540,44 @@ nsFrameLoader::GetViewportScrollX(float*
 NS_IMETHODIMP
 nsFrameLoader::GetViewportScrollY(float* aViewportScrollY)
 {
   *aViewportScrollY =
     nsPresContext::AppUnitsToFloatCSSPixels(mViewportConfig.mScrollOffset.y);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::GetRenderMode(PRUint32* aRenderMode)
+{
+  *aRenderMode = mViewportConfig.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
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -75,17 +75,18 @@ class RenderFrameParent;
 #ifdef MOZ_WIDGET_GTK2
 typedef struct _GtkWidget GtkWidget;
 #endif
 #ifdef MOZ_WIDGET_QT
 class QX11EmbedContainer;
 #endif
 #endif
 
-class nsFrameLoader : public nsIFrameLoader
+class nsFrameLoader : public nsIFrameLoader,
+                      public nsIFrameLoader_MOZILLA_2_0_BRANCH
 {
   friend class AutoResetInShow;
 #ifdef MOZ_IPC
   typedef mozilla::dom::PBrowserParent PBrowserParent;
   typedef mozilla::dom::TabParent TabParent;
   typedef mozilla::layout::RenderFrameParent RenderFrameParent;
 #endif
 
@@ -116,30 +117,41 @@ public:
    * 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()
-      : mScrollOffset(0, 0)
+      : mRenderMode(nsIFrameLoader_MOZILLA_2_0_BRANCH::RENDER_MODE_DEFAULT)
+      , mScrollOffset(0, 0)
       , mXScale(1.0)
       , mYScale(1.0)
     {}
 
     // Default copy ctor and operator= are fine
 
     PRBool operator==(const ViewportConfig& aOther) const
     {
-      return (mScrollOffset == aOther.mScrollOffset &&
+      return (mRenderMode == aOther.mRenderMode &&
+              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 <browser> user wishes or expects
     // its enclosed content document to have.  "Scroll offset" here
     // means the document pixel at pixel (0,0) within the CSS
     // viewport.  If the content document's actual scroll offset
     // doesn't match |mScrollOffset|, the difference is used to define
     // a translation transform when painting the content document.
     nsPoint mScrollOffset;
     // The scale at which the <browser> user wishes to paint its
@@ -157,18 +169,19 @@ public:
       mMessageManager->Disconnect();
     }
     nsFrameLoader::Destroy();
   }
 
   static nsFrameLoader* Create(nsIContent* aOwner, PRBool aNetworkCreated);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(nsFrameLoader)
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameLoader, nsIFrameLoader)
   NS_DECL_NSIFRAMELOADER
+  NS_DECL_NSIFRAMELOADER_MOZILLA_2_0_BRANCH
   NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI);
   nsresult ReallyStartLoading();
   void Finalize();
   nsIDocShell* GetExistingDocShell() { return mDocShell; }
   nsPIDOMEventTarget* GetTabChildGlobalAsEventTarget();
   nsresult CreateStaticClone(nsIFrameLoader* aDest);
 
   /**
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -1519,17 +1519,17 @@ nsObjectLoadingContent::RemovedFromDocum
     // have already loaded the content.
     mURI = nsnull;
   }
 }
 
 void
 nsObjectLoadingContent::Traverse(nsCycleCollectionTraversalCallback &cb)
 {
-  cb.NoteXPCOMChild(mFrameLoader);
+  cb.NoteXPCOMChild(static_cast<nsIFrameLoader*>(mFrameLoader));
 }
 
 // <private>
 /* static */ PRBool
 nsObjectLoadingContent::IsSuccessfulRequest(nsIRequest* aRequest)
 {
   nsresult status;
   nsresult rv = aRequest->GetStatus(&status);
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -3687,17 +3687,17 @@ nsCanvasRenderingContext2D::AsyncDrawXUL
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_DOM_SECURITY_ERR;
     }
 
     nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aElem);
     if (!loaderOwner)
         return NS_ERROR_FAILURE;
 
-    nsCOMPtr<nsFrameLoader> frameloader = loaderOwner->GetFrameLoader();
+    nsRefPtr<nsFrameLoader> frameloader = loaderOwner->GetFrameLoader();
     if (!frameloader)
         return NS_ERROR_FAILURE;
 
 #ifdef MOZ_IPC
     PBrowserParent *child = frameloader->GetRemoteBrowser();
     if (!child) {
         nsCOMPtr<nsIDOMWindow> window =
             do_GetInterface(frameloader->GetExistingDocShell());
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3047,17 +3047,17 @@ nsGenericHTMLFrameElement::~nsGenericHTM
   if (mFrameLoader) {
     mFrameLoader->Destroy();
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
                                                   nsGenericHTMLElement)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFrameLoader)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFrameLoader, nsIFrameLoader)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_TABLE_HEAD(nsGenericHTMLFrameElement)
   NS_INTERFACE_TABLE_INHERITED2(nsGenericHTMLFrameElement,
                                 nsIDOMNSHTMLFrameElement,
                                 nsIFrameLoaderOwner)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLFrameElement)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -92,30 +92,36 @@ ComputeShadowTreeTransform(nsIFrame* aCo
 {
   nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
   // Offset to the content rect in case we have borders or padding
   nsPoint frameOffset =
     (aBuilder->ToReferenceFrame(aContainerFrame->GetParent()) +
      aContainerFrame->GetContentRect().TopLeft());
   *aShadowTranslation = frameOffset.ToNearestPixels(auPerDevPixel);
 
-  // |aMetrics.mViewportScrollOffset| was the content document's
-  // scroll offset when it was painted (the document pixel at CSS
-  // viewport (0,0)).  |aConfig.mScrollOffset| is what our user
-  // expects, or wants, the content-document scroll offset to be.  So
-  // we set a compensating translation that moves the content document
-  // pixels to where the user wants them to be.
-  nsIntPoint scrollCompensation =
-    (aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel));
-  scrollCompensation.x -= aMetrics.mViewportScrollOffset.x * aConfig.mXScale;
-  scrollCompensation.y -= aMetrics.mViewportScrollOffset.y * aConfig.mYScale;
-  *aShadowTranslation -= scrollCompensation;
+  if (aConfig.AsyncScrollEnabled()) {
+    // |aMetrics.mViewportScrollOffset| was the content document's
+    // scroll offset when it was painted (the document pixel at CSS
+    // viewport (0,0)).  |aConfig.mScrollOffset| is what our user
+    // expects, or wants, the content-document scroll offset to be.  So
+    // we set a compensating translation that moves the content document
+    // pixels to where the user wants them to be.
+    nsIntPoint scrollCompensation =
+      (aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel));
+    scrollCompensation.x -= aMetrics.mViewportScrollOffset.x * aConfig.mXScale;
+    scrollCompensation.y -= aMetrics.mViewportScrollOffset.y * aConfig.mYScale;
+    *aShadowTranslation -= scrollCompensation;
 
-  *aShadowXScale = aConfig.mXScale;
-  *aShadowYScale = aConfig.mYScale;
+    *aShadowXScale = aConfig.mXScale;
+    *aShadowYScale = aConfig.mYScale;
+  } else {
+    *aShadowXScale = 1;
+    *aShadowYScale = 1;
+  }
+           
 }
 
 static void
 UpdateShadowSubtree(Layer* aSubtreeRoot)
 {
   ShadowLayer* shadow = aSubtreeRoot->AsShadowLayer();
 
   shadow->SetShadowClipRect(aSubtreeRoot->GetClipRect());
--- a/layout/ipc/test-ipcbrowser-chrome.js
+++ b/layout/ipc/test-ipcbrowser-chrome.js
@@ -1,23 +1,30 @@
 function init() {
+    enableAsyncScrolling();
     messageManager.loadFrameScript(
         "chrome://global/content/test-ipcbrowser-content.js", true
     );
 }
 
 function browser() {
     return document.getElementById("content");
 }
 
 function frameLoader() {
     return browser().QueryInterface(Components.interfaces.nsIFrameLoaderOwner)
                     .frameLoader;
 }
 
+function enableAsyncScrolling() {
+    var i = Components.interfaces.nsIFrameLoader_MOZILLA_2_0_BRANCH;
+    var enabler = frameLoader().QueryInterface(i);
+    enabler.renderMode = i.RENDER_MODE_ASYNC_SCROLL;
+}
+
 // Functions affecting the content window.
 
 function loadURL(url) {
     browser().setAttribute('src', url);
 }
 
 function scrollContentBy(dx, dy) {
     messageManager.sendAsyncMessage("scrollBy",