Bug 1055557 - Ensure the right presShell resolution is used in ApplyCallbackTransform for fennec-apz scenarios. r=botond
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2103,45 +2103,44 @@ TabChild::RecvHandleDoubleTap(const CSSP
Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
if (!mGlobal || !mTabChildGlobal) {
return true;
}
// Note: there is nothing to do with the modifiers here, as we are not
// synthesizing any sort of mouse event.
- CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid,
- GetPresShellResolution());
+ CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
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);
return true;
}
bool
TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mGlobal && mTabChildGlobal) {
- mAPZEventState->ProcessSingleTap(aPoint, aModifiers, aGuid, GetPresShellResolution());
+ mAPZEventState->ProcessSingleTap(aPoint, aModifiers, aGuid);
}
return true;
}
bool
TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
{
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessLongTap(GetPresShell(), aPoint, aModifiers, aGuid,
- aInputBlockId, GetPresShellResolution());
+ aInputBlockId);
}
return true;
}
bool
TabChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
const APZStateChange& aChange,
const int& aArg)
@@ -2376,40 +2375,29 @@ TabChild::CancelTapTracking()
{
mActivePointerId = -1;
if (mTapHoldTimer) {
mTapHoldTimer->Cancel();
}
mTapHoldTimer = nullptr;
}
-float
-TabChild::GetPresShellResolution() const
-{
- nsCOMPtr<nsIDocument> document(GetDocument());
- nsIPresShell* shell = document->GetShell();
- if (!shell) {
- return 1.0f;
- }
- return shell->GetResolution();
-}
-
bool
TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId,
const nsEventStatus& aApzResponse)
{
TABC_LOG("Receiving touch event of type %d\n", aEvent.message);
WidgetTouchEvent localEvent(aEvent);
localEvent.widget = mPuppetWidget;
APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
- mPuppetWidget->GetDefaultScale(), GetPresShellResolution());
+ mPuppetWidget->GetDefaultScale());
if (localEvent.message == NS_TOUCH_START && AsyncPanZoomEnabled()) {
if (gfxPrefs::TouchActionEnabled()) {
APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(mPuppetWidget,
localEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback);
}
nsCOMPtr<nsIDocument> document = GetDocument();
APZCCallbackHelper::SendSetTargetAPZCNotification(mPuppetWidget, document,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -594,19 +594,16 @@ private:
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn);
bool HasValidInnerSize();
- // Get the pres shell resolution of the document in this tab.
- float GetPresShellResolution() const;
-
void SetTabId(const TabId& aTabId);
ScreenIntRect GetOuterRect();
void SetUnscaledInnerSize(const CSSSize& aSize) {
mUnscaledInnerSize = aSize;
}
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -346,73 +346,97 @@ APZCCallbackHelper::AcknowledgeScrollUpd
nsCOMPtr<nsIRunnable> r1 = new AcknowledgeScrollUpdateEvent(aScrollId, aScrollGeneration);
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(r1);
} else {
r1->Run();
}
}
+static nsIPresShell*
+GetRootContentDocumentPresShellForContent(nsIContent* aContent)
+{
+ nsIDocument* doc = aContent->GetComposedDoc();
+ if (!doc) {
+ return nullptr;
+ }
+ nsIPresShell* shell = doc->GetShell();
+ if (!shell) {
+ return nullptr;
+ }
+ nsPresContext* context = shell->GetPresContext();
+ if (!context) {
+ return nullptr;
+ }
+ context = context->GetToplevelContentDocumentPresContext();
+ if (!context) {
+ return nullptr;
+ }
+ return context->PresShell();
+}
+
CSSPoint
APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
- const ScrollableLayerGuid& aGuid,
- float aPresShellResolution)
+ const ScrollableLayerGuid& aGuid)
{
- // 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;
+ CSSPoint input = aInput;
+ if (aGuid.mScrollId == FrameMetrics::NULL_SCROLL_ID) {
+ return input;
+ }
+ nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId);
+ if (!content) {
+ return input;
+ }
+
+ // First, scale inversely by the root content document's 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.
+ if (nsIPresShell* shell = GetRootContentDocumentPresShellForContent(content)) {
+ input = input / shell->GetResolution();
+ }
// 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
// where any of this matters, so I'm skipping it for now and just doing the single
// 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 input + delta;
- }
- }
+ void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform);
+ if (property) {
+ CSSPoint delta = (*static_cast<CSSPoint*>(property));
+ input += delta;
}
return input;
}
LayoutDeviceIntPoint
APZCCallbackHelper::ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
const ScrollableLayerGuid& aGuid,
- const CSSToLayoutDeviceScale& aScale,
- float aPresShellResolution)
+ const CSSToLayoutDeviceScale& aScale)
{
LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
- point = ApplyCallbackTransform(point / aScale, aGuid, aPresShellResolution) * aScale;
+ point = ApplyCallbackTransform(point / aScale, aGuid) * aScale;
return gfx::RoundedToInt(point);
}
void
APZCCallbackHelper::ApplyCallbackTransform(WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
- const CSSToLayoutDeviceScale& aScale,
- float aPresShellResolution)
+ const CSSToLayoutDeviceScale& aScale)
{
for (size_t i = 0; i < aEvent.touches.Length(); i++) {
aEvent.touches[i]->mRefPoint = ApplyCallbackTransform(
- aEvent.touches[i]->mRefPoint, aGuid, aScale, aPresShellResolution);
+ aEvent.touches[i]->mRefPoint, aGuid, aScale);
}
}
nsEventStatus
APZCCallbackHelper::DispatchWidgetEvent(WidgetGUIEvent& aEvent)
{
nsEventStatus status = nsEventStatus_eConsumeNoDefault;
if (aEvent.widget) {
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -81,34 +81,31 @@ public:
/* 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.
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,
- float aPresShellResolution);
+ const ScrollableLayerGuid& aGuid);
/* Same as above, but operates on LayoutDeviceIntPoint.
Requires an additonal |aScale| parameter to convert between CSS and
LayoutDevice space. */
static mozilla::LayoutDeviceIntPoint
ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
const ScrollableLayerGuid& aGuid,
- const CSSToLayoutDeviceScale& aScale,
- float aPresShellResolution);
+ const CSSToLayoutDeviceScale& aScale);
/* Convenience function for applying a callback transform to all touch
* points of a touch event. */
static void ApplyCallbackTransform(WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
- const CSSToLayoutDeviceScale& aScale,
- float aPresShellResolution);
+ const CSSToLayoutDeviceScale& aScale);
/* Dispatch a widget event via the widget stored in the event, if any.
* In a child process, allows the TabParent event-capture mechanism to
* intercept the event. */
static nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& aEvent);
/* Synthesize a mouse event with the given parameters, and dispatch it
* via the given widget. */
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -144,33 +144,32 @@ private:
nsCOMPtr<nsITimer> mTimer;
};
NS_IMPL_ISUPPORTS(DelayedFireSingleTapEvent, nsITimerCallback)
void
APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
- const ScrollableLayerGuid& aGuid,
- float aPresShellResolution)
+ const ScrollableLayerGuid& aGuid)
{
APZES_LOG("Handling single tap at %s on %s with %d\n",
Stringify(aPoint).c_str(), Stringify(aGuid).c_str(), mTouchEndCancelled);
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return;
}
if (mTouchEndCancelled) {
return;
}
LayoutDevicePoint currentPoint =
- APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, aPresShellResolution)
+ APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid)
* widget->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.
APZCCallbackHelper::FireSingleTapEvent(currentPoint, aModifiers, widget);
return;
}
@@ -189,44 +188,43 @@ APZEventState::ProcessSingleTap(const CS
}
}
void
APZEventState::ProcessLongTap(const nsCOMPtr<nsIPresShell>& aPresShell,
const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
- uint64_t aInputBlockId,
- float aPresShellResolution)
+ uint64_t aInputBlockId)
{
APZES_LOG("Handling long tap at %s\n", Stringify(aPoint).c_str());
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return;
}
SendPendingTouchPreventedResponse(false, aGuid);
// Converting the modifiers to DOM format for the DispatchMouseEvent call
// is the most useless thing ever because nsDOMWindowUtils::SendMouseEvent
// just converts them back to widget format, but that API has many callers,
// including in JS code, so it's not trivial to change.
bool eventHandled =
APZCCallbackHelper::DispatchMouseEvent(aPresShell, NS_LITERAL_STRING("contextmenu"),
- APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, aPresShellResolution),
+ APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid),
2, 1, WidgetModifiersToDOMModifiers(aModifiers), true,
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
APZES_LOG("Contextmenu event handled: %d\n", eventHandled);
// If no one handle context menu, fire MOZLONGTAP event
if (!eventHandled) {
LayoutDevicePoint currentPoint =
- APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, aPresShellResolution)
+ APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid)
* widget->GetDefaultScale();
int time = 0;
nsEventStatus status =
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, aModifiers, widget);
eventHandled = (status == nsEventStatus_eConsumeNoDefault);
APZES_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
}
--- a/gfx/layers/apz/util/APZEventState.h
+++ b/gfx/layers/apz/util/APZEventState.h
@@ -46,24 +46,22 @@ class APZEventState {
public:
APZEventState(nsIWidget* aWidget,
const nsRefPtr<ContentReceivedInputBlockCallback>& aCallback);
NS_INLINE_DECL_REFCOUNTING(APZEventState);
void ProcessSingleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
- const ScrollableLayerGuid& aGuid,
- float aPresShellResolution);
+ const ScrollableLayerGuid& aGuid);
void ProcessLongTap(const nsCOMPtr<nsIPresShell>& aUtils,
const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
- uint64_t aInputBlockId,
- float aPresShellResolution);
+ uint64_t aInputBlockId);
void ProcessTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
nsEventStatus aApzResponse);
void ProcessWheelEvent(const WidgetWheelEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
void ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -108,24 +108,16 @@ ChromeProcessController::Destroy()
NewRunnableMethod(this, &ChromeProcessController::Destroy));
return;
}
MOZ_ASSERT(MessageLoop::current() == mUILoop);
mWidget = nullptr;
}
-float
-ChromeProcessController::GetPresShellResolution() const
-{
- // The document in the chrome process cannot be zoomed, so its pres shell
- // resolution is 1.
- return 1.0f;
-}
-
nsIPresShell*
ChromeProcessController::GetPresShell() const
{
if (nsView* view = nsView::GetViewFor(mWidget)) {
return view->GetPresShell();
}
return nullptr;
}
@@ -157,34 +149,34 @@ ChromeProcessController::HandleSingleTap
if (MessageLoop::current() != mUILoop) {
mUILoop->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ChromeProcessController::HandleSingleTap,
aPoint, aModifiers, aGuid));
return;
}
- mAPZEventState->ProcessSingleTap(aPoint, aModifiers, aGuid, GetPresShellResolution());
+ mAPZEventState->ProcessSingleTap(aPoint, aModifiers, aGuid);
}
void
ChromeProcessController::HandleLongTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId)
{
if (MessageLoop::current() != mUILoop) {
mUILoop->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ChromeProcessController::HandleLongTap,
aPoint, aModifiers, aGuid, aInputBlockId));
return;
}
mAPZEventState->ProcessLongTap(GetPresShell(), aPoint, aModifiers, aGuid,
- aInputBlockId, GetPresShellResolution());
+ aInputBlockId);
}
void
ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
APZStateChange aChange,
int aArg)
{
if (MessageLoop::current() != mUILoop) {
--- a/gfx/layers/apz/util/ChromeProcessController.h
+++ b/gfx/layers/apz/util/ChromeProcessController.h
@@ -57,17 +57,16 @@ public:
virtual void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId,
const nsString& aEvent) override;
private:
nsCOMPtr<nsIWidget> mWidget;
nsRefPtr<APZEventState> mAPZEventState;
MessageLoop* mUILoop;
void InitializeRoot();
- float GetPresShellResolution() const;
nsIPresShell* GetPresShell() const;
nsIDocument* GetDocument() const;
already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils() const;
};
} // namespace layers
} // namespace mozilla
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1042,17 +1042,17 @@ nsBaseWidget::ProcessUntransformedAPZEve
// If this is a touch event and APZ has targeted it to an APZC in the root
// process, apply that APZC's callback-transform before dispatching the
// event. If the event is instead targeted to an APZC in the child process,
// the transform will be applied in the child process before dispatching
// the event there (see e.g. TabChild::RecvRealTouchEvent()).
// TODO: Do other types of events (than touch) need this?
if (aEvent->AsTouchEvent() && aGuid.mLayersId == mCompositorParent->RootLayerTreeId()) {
APZCCallbackHelper::ApplyCallbackTransform(*aEvent->AsTouchEvent(), aGuid,
- GetDefaultScale(), 1.0f);
+ GetDefaultScale());
}
nsEventStatus status;
DispatchEvent(aEvent, status);
if (mAPZC && !context.WasRoutedToChildProcess()) {
// EventStateManager did not route the event into the child process.
// It's safe to communicate to APZ that the event has been processed.