Bug 1120566 - Adjust points sent from APZ to Gecko for the 'scale-to-resolution' transform in APZCCallbackHelper::ApplyCallbackTransform. r=kats
authorBotond Ballo <botond@mozilla.com>
Fri, 16 Jan 2015 13:48:33 -0500
changeset 224405 3e38ec9ed49a0f4afae366bfc13d36ba892c0037
parent 224404 6396e2e43cdde77a135ab48123c7927e252bc9a3
child 224406 6ccc86f7429e38dec4343a43f7d994c4c553e91e
push id54213
push userkgupta@mozilla.com
push dateSat, 17 Jan 2015 15:31:45 +0000
treeherdermozilla-inbound@3e38ec9ed49a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1120566
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1120566 - Adjust points sent from APZ to Gecko for the 'scale-to-resolution' transform in APZCCallbackHelper::ApplyCallbackTransform. r=kats
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
gfx/layers/apz/util/APZCCallbackHelper.cpp
gfx/layers/apz/util/APZCCallbackHelper.h
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -490,17 +490,17 @@ already_AddRefed<nsIDOMWindowUtils>
 TabChildBase::GetDOMWindowUtils()
 {
   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
   nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
   return utils.forget();
 }
 
 already_AddRefed<nsIDocument>
-TabChildBase::GetDocument()
+TabChildBase::GetDocument() const
 {
   nsCOMPtr<nsIDOMDocument> domDoc;
   WebNavigation()->GetDocument(getter_AddRefs(domDoc));
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
   return doc.forget();
 }
 
 void
@@ -2109,17 +2109,18 @@ TabChild::RecvHandleDoubleTap(const CSSP
 {
     TABC_LOG("Handling double tap at %s with %p %p\n",
       Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
 
     if (!mGlobal || !mTabChildGlobal) {
         return true;
     }
 
-    CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
+    CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid,
+        GetPresShellResolution());
     nsString data;
     data.AppendLiteral("{ \"x\" : ");
     data.AppendFloat(point.x);
     data.AppendLiteral(", \"y\" : ");
     data.AppendFloat(point.y);
     data.AppendLiteral(" }");
 
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
@@ -2137,17 +2138,19 @@ TabChild::RecvHandleSingleTap(const CSSP
   if (!mGlobal || !mTabChildGlobal) {
     return true;
   }
 
   if (mTouchEndCancelled) {
     return true;
   }
 
-  LayoutDevicePoint currentPoint = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();;
+  LayoutDevicePoint currentPoint =
+      APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
+    * mWidget->GetDefaultScale();;
   if (!mActiveElementManager->ActiveElementUsesStyle()) {
     // If the active element isn't visually affected by the :active style, we
     // have no need to wait the extra sActiveDurationMs to make the activation
     // visually obvious to the user.
     FireSingleTapEvent(currentPoint);
     return true;
   }
 
@@ -2189,26 +2192,27 @@ TabChild::RecvHandleLongTap(const CSSPoi
   if (!mGlobal || !mTabChildGlobal) {
     return true;
   }
 
   SendPendingTouchPreventedResponse(false, aGuid);
 
   bool eventHandled =
       DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
-                         APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid),
+                         APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution()),
                          2, 1, 0, true,
                          nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
 
   TABC_LOG("Contextmenu event handled: %d\n", eventHandled);
 
   // If no one handle context menu, fire MOZLONGTAP event
   if (!eventHandled) {
     LayoutDevicePoint currentPoint =
-      APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();
+        APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
+      * mWidget->GetDefaultScale();
     int time = 0;
     nsEventStatus status =
       DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
     eventHandled = (status == nsEventStatus_eConsumeNoDefault);
     TABC_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
   }
 
   SendContentReceivedInputBlock(aGuid, aInputBlockId, eventHandled);
@@ -2657,25 +2661,38 @@ TabChild::SendSetTargetAPZCNotification(
   nsTArray<ScrollableLayerGuid> targets;
   for (size_t i = 0; i < aEvent.touches.Length(); i++) {
     waitForRefresh |= PrepareForSetTargetAPZCNotification(aGuid, aInputBlockId,
         rootFrame, aEvent.touches[i]->mRefPoint, &targets);
   }
   SendSetTargetAPZCNotification(shell, aInputBlockId, targets, waitForRefresh);
 }
 
+float
+TabChild::GetPresShellResolution() const
+{
+  nsCOMPtr<nsIDocument> document(GetDocument());
+  nsIPresShell* shell = document->GetShell();
+  if (!shell) {
+    return 1.0f;
+  }
+  return shell->GetXResolution();
+}
+
 bool
 TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
                              const ScrollableLayerGuid& aGuid,
                              const uint64_t& aInputBlockId)
 {
   TABC_LOG("Receiving touch event of type %d\n", aEvent.message);
 
   for (size_t i = 0; i < aEvent.touches.Length(); i++) {
-    aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale());
+    aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(
+        aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale(),
+        GetPresShellResolution());
   }
 
   if (aEvent.message == NS_TOUCH_START && IsAsyncPanZoomEnabled()) {
     SendSetTargetAPZCNotification(aEvent, aGuid, aInputBlockId);
   }
 
   WidgetTouchEvent localEvent(aEvent);
   localEvent.widget = mWidget;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -175,17 +175,17 @@ class TabChildBase : public nsISupports,
                      public ipc::MessageManagerCallback
 {
 public:
     TabChildBase();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TabChildBase)
 
-    virtual nsIWebNavigation* WebNavigation() = 0;
+    virtual nsIWebNavigation* WebNavigation() const = 0;
     virtual nsIWidget* WebWidget() = 0;
     nsIPrincipal* GetPrincipal() { return mPrincipal; }
     bool IsAsyncPanZoomEnabled();
     // Recalculates the display state, including the CSS
     // viewport. This should be called whenever we believe the
     // viewport data on a document may have changed. If it didn't
     // change, this function doesn't do anything.  However, it should
     // not be called all the time as it is fairly expensive.
@@ -201,17 +201,17 @@ public:
 
 protected:
     virtual ~TabChildBase();
     CSSSize GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport);
 
     // Get the DOMWindowUtils for the top-level window in this tab.
     already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils();
     // Get the Document for the top-level window in this tab.
-    already_AddRefed<nsIDocument> GetDocument();
+    already_AddRefed<nsIDocument> GetDocument() const;
 
     // Wrapper for nsIDOMWindowUtils.setCSSViewport(). This updates some state
     // variables local to this class before setting it.
     void SetCSSViewport(const CSSSize& aSize);
 
     // Wraps up a JSON object as a structured clone and sends it to the browser
     // chrome script.
     //
@@ -413,17 +413,17 @@ public:
     AllocPIndexedDBPermissionRequestChild(const Principal& aPrincipal)
                                           MOZ_OVERRIDE;
 
     virtual bool
     DeallocPIndexedDBPermissionRequestChild(
                                        PIndexedDBPermissionRequestChild* aActor)
                                        MOZ_OVERRIDE;
 
-    virtual nsIWebNavigation* WebNavigation() MOZ_OVERRIDE { return mWebNav; }
+    virtual nsIWebNavigation* WebNavigation() const MOZ_OVERRIDE { return mWebNav; }
     virtual nsIWidget* WebWidget() MOZ_OVERRIDE { return mWidget; }
 
     /** Return the DPI of the widget this TabChild draws to. */
     void GetDPI(float* aDPI);
     void GetDefaultScale(double *aScale);
 
     ScreenOrientation GetOrientation() { return mOrientation; }
 
@@ -606,16 +606,19 @@ private:
                                        const uint64_t& aInputBlockId,
                                        const nsTArray<ScrollableLayerGuid>& aTargets,
                                        bool aWaitForRefresh);
 
     void SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
                                        const mozilla::layers::ScrollableLayerGuid& aGuid,
                                        const uint64_t& aInputBlockId);
 
+    // Get the pres shell resolution of the document in this tab.
+    float GetPresShellResolution() const;
+
     void SetTabId(const TabId& aTabId)
     {
       MOZ_ASSERT(mUniqueId == 0);
 
       mUniqueId = aTabId;
       NestedTabChildMap()[mUniqueId] = this;
     }
 
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -307,18 +307,28 @@ APZCCallbackHelper::UpdateCallbackTransf
         return;
     }
     CSSPoint scrollDelta = aApzcMetrics.GetScrollOffset() - aActualMetrics.GetScrollOffset();
     content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(scrollDelta),
                          nsINode::DeleteProperty<CSSPoint>);
 }
 
 CSSPoint
-APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, const ScrollableLayerGuid& aGuid)
+APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
+                                           const ScrollableLayerGuid& aGuid,
+                                           float aPresShellResolution)
 {
+    // First, scale inversely by the pres shell resolution to cancel the
+    // scale-to-resolution transform that the compositor adds to the layer with
+    // the pres shell resolution. The points sent to Gecko by APZ don't have
+    // this transform unapplied (unlike other compositor-side transforms)
+    // because APZ doesn't know about it.
+    CSSPoint input = aInput / aPresShellResolution;
+
+    // Now apply the callback-transform.
     // XXX: technically we need to walk all the way up the layer tree from the layer
     // represented by |aGuid.mScrollId| up to the root of the layer tree and apply
     // the input transforms at each level in turn. However, it is quite difficult
     // to do this given that the structure of the layer tree may be different from
     // the structure of the content tree. Also it may be impossible to do correctly
     // at this point because there are other CSS transforms and such interleaved in
     // between so applying the inputTransforms all in a row at the end may leave
     // some things transformed improperly. In practice we should rarely hit scenarios
@@ -326,28 +336,29 @@ APZCCallbackHelper::ApplyCallbackTransfo
     // transform for the layer that the input hit.
 
     if (aGuid.mScrollId != FrameMetrics::NULL_SCROLL_ID) {
         nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
         if (content) {
             void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
             if (property) {
                 CSSPoint delta = (*static_cast<CSSPoint*>(property));
-                return aInput + delta;
+                return input + delta;
             }
         }
     }
-    return aInput;
+    return input;
 }
 
 nsIntPoint
 APZCCallbackHelper::ApplyCallbackTransform(const nsIntPoint& aPoint,
-                                        const ScrollableLayerGuid& aGuid,
-                                        const CSSToLayoutDeviceScale& aScale)
+                                           const ScrollableLayerGuid& aGuid,
+                                           const CSSToLayoutDeviceScale& aScale,
+                                           float aPresShellResolution)
 {
     LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
-    point = ApplyCallbackTransform(point / aScale, aGuid) * aScale;
+    point = ApplyCallbackTransform(point / aScale, aGuid, aPresShellResolution) * aScale;
     LayoutDeviceIntPoint ret = gfx::RoundedToInt(point);
     return nsIntPoint(ret.x, ret.y);
 }
 
 }
 }
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -84,24 +84,29 @@ public:
        |aActualMetrics| argument are the metrics representing the gecko state after we
        applied some or all of the APZ metrics. */
     static void UpdateCallbackTransform(const FrameMetrics& aApzcMetrics,
                                         const FrameMetrics& aActualMetrics);
 
     /* Apply an "input transform" to the given |aInput| and return the transformed value.
        The input transform applied is the one for the content element corresponding to
        |aGuid|; this is populated in a previous call to UpdateCallbackTransform. See that
-       method's documentations for details. */
+       method's documentations for details.
+       This method additionally adjusts |aInput| by inversely scaling by the provided
+       pres shell resolution, to cancel out a compositor-side transform (added in
+       bug 1076241) that APZ doesn't unapply. */
     static CSSPoint ApplyCallbackTransform(const CSSPoint& aInput,
-                                           const ScrollableLayerGuid& aGuid);
+                                           const ScrollableLayerGuid& aGuid,
+                                           float aPresShellResolution);
 
     /* Same as above, but operates on nsIntPoint that are assumed to be in LayoutDevice
        pixel space. Requires an additonal |aScale| parameter to convert between CSS and
        LayoutDevice space. */
     static nsIntPoint ApplyCallbackTransform(const nsIntPoint& aPoint,
                                              const ScrollableLayerGuid& aGuid,
-                                             const CSSToLayoutDeviceScale& aScale);
+                                             const CSSToLayoutDeviceScale& aScale,
+                                             float aPresShellResolution);
 };
 
 }
 }
 
 #endif /* mozilla_layers_APZCCallbackHelper_h */