Bug 1120566 - Adjust points sent from APZ to Gecko for the 'scale-to-resolution' transform in APZCCallbackHelper::ApplyCallbackTransform. r=kats, a=bajaj
authorBotond Ballo <botond@mozilla.com>
Fri, 16 Jan 2015 13:48:33 -0500
changeset 232312 7762046d329655298b2155f449aa0612e403101a
parent 232311 b20871154f131a6b9bfca3c0e79f59f35eced4ac
child 232313 4a338e68a6eba6f836b81ed680b60e881d903371
push id30
push userryanvm@gmail.com
push dateWed, 21 Jan 2015 01:09:36 +0000
treeherdermozilla-b2g37_v2_2@7762046d3296 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, bajaj
bugs1120566
milestone37.0a2
Bug 1120566 - Adjust points sent from APZ to Gecko for the 'scale-to-resolution' transform in APZCCallbackHelper::ApplyCallbackTransform. r=kats, a=bajaj
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
@@ -2093,17 +2093,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);
@@ -2121,17 +2122,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;
   }
 
@@ -2173,26 +2176,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);
@@ -2641,25 +2645,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; }
 
@@ -601,16 +601,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 */