From e9ba40cf6bf22ea6ffc7bdb9d545acc296ca5b01 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Wed, 2 Feb 2022 12:04:50 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1178833 - Fix for unified builds when a new file is added to layout/base. r=mstange (bf961c00fd) - Bug 1178847 - Add a MobileViewportManager to manage setting the CSS viewport on B2G. r=botond,tn (937ba486fa) - Bug 1178847 - Don't use the MobileViewportManager code on Mulet or Fennec yet. r=botond (3061b2c617) - Bug 1168950. Add the document to DoProcessRestyles profile label. r=dbaron (2347b76411) - Bug 1187792 - Don't set the SPCSPS unless meta-viewport or zooming is enabled. r=botond (a8f5ed1006) - Bug 1193062 - Don't double-send target APZC confirmations that might race each other. r=kats (de48467401) - Bug 1186004 - Add a pref to enable/disable APZ zooming behaviour. r=botond (fc3653c979) - Bug 1193062 - Add a PAN_MOMENTUM state. r=kats (10c8bb1a5e) - Bug 1148350 - Have ConvertToGecko use a live screen-to-apzc transform to avoid transform mismatches. r=botond (9eee9ea6f2) - Bug 1169844 - Remove incorrect assertion and properly untransform wheel events for overscroll situations. r=botond (9b101b53bb) - Bug 1169690 - Accelerate flings correctly in the presence of overscroll handoff. r=kats (49d55c05f4) - Bug 1158424 - Extract a BreadthFirstSearch() helper function. r=kats (6a49498185) - Bug 1158424 - Add APZCTreeManager::FindRootContentApzcForLayersId(). r=kats (d6c7ecf781) - Bug 1158424 - Fix APZCTreeManager::GetMultitouchTarget(). r=kats (bf8571a4ca) - Bug 1174205 - Make sure to acquire the tree lock before finding the multitouch target. r=botond (bdbd98f2c7) - Bug 1211660 - Remove dead obj argument from two functions. r=Waldo. (efba5a2f8d) - Bug 1158424 - Undeprecate HasNoParentWithSameLayersId(). r=kats (d994ea28f8) - Fix AsyncCompositionManager not comparing layer tree IDs when finding scrollbar targets. (bug 1151169, r=kats) (c7dbc4776a) - Bug 1163259. Make sure we don't look at the parent ref layer when looking for a layer with the frame metrics for a scrollbar. r=kats (8b99d2c830) - Bug 1164340. Convert the scrollbar thumb ratio to a unitless ratio properly for non-zoomable scrollframes. r=botond (27f56cab56) - Bug 1164340. Fix up some scrollbar related comments in AsyncCompositionManager. r=botond (b9d540bea9) - Bug 1164767. Modify async scrollbar positioning code to deal with containerless root scrollables. r=botond (501d07592e) - Bug 1158424 - Remove FrameMetrics::IsRootScrollable() (it just duplicated IsRootContent()). r=kats (672fd034b3) - Bug 1120683 - Properly handle unapplying 3D projective transforms throughout APZ code. r=botond (a46612811a) - Bug 1148868 - Make APZ wheel handling handle pixel scrolling on OS X. r=dvander, r=kats (da3bd34135) - Bug 1193062 - Add fields to PanGestureInput and ScrollWheelInput. r=kats (716ba34e18) - Bug 1189565 - Send resize events when backing scale factor changes. r=mstange (4e81a7bbf7) - Bug 1193062 - Add nsCocoaUtils::ModifiersForEvent. r=smichaud (da67b22ff7) - Bug 1016035 - Remove the ability to swipe vertically. r=kats (fa315e0b97) - Bug 1016035 - Refactor the code that decides whether we want to start a swipe. r=kats (3091961328) - Bug 1016035 - Make the threshold in AxisPhysicsMSDModel::IsFinished controllable by the caller. r=kip (76df4d85a2) - Bug 1016035 - More swipe refactoring. r=kats (2abcd05b33) - Bug 1016035 - Implement the swipe animation ourselves instead of calling the NSEvent trackSwipe API. r=kats (4842b2a728) - Bug 1016035 - Move swipe tracking code into DispatchAPZWheelInputEvent. r=kats (bb1052b87c) - Bug 1016035 - Also mark widgetWheelEvents that are handled by APZ with mCanStartSwipe. r=kats (21809b902d) - Bug 1016035 - Put PanGestureInput events into a queue if they can end up as a swipe. r=kats (2ebac59047) - Bug 1016035 - Split up MaybeTrackScrollEventAsSwipe into SendMayStartSwipe and TrackScrollEventAsSwipe. r=kats (ced10d9671) - Bug 1016035 - Send MayStartSwipe event before sending the wheel event. r=kats (b3346b81fb) - Fix some fields missing in the widget event IPC glue. (bug 1139711, r=kats) (1298b25705) - Bug 1016035 - Add mCanTriggerSwipe and TriggersSwipe(). r=masayuki (664a059972) - Bug 1016035 - Make APZEventState report defaultPrevented=true when the event started a swipe. r=kats (128d627ac7) - Bug 1016035 - Set scroll overflow information on potential swipe start events that have been processed by APZ. r=masayuki (b5931f6320) - Bug 1206801 - fix broken CONFIG['DEBUG'] checks in moz.build files; r=mshal (292d5ac709) - Bug 1186424: Refactor AsmJSValidate.cpp in preparation for parallelization; r=luke (4868bc66ca) - Bug 1129267 - Fix by backing out patch for bug 1118615. r=mstange (ea8aaba04e) - Bug 1182411 Part 1: Make plugin quirks available to the Parent as well as the Child. r=jimm (1f2551a6b7) - Bug 1228462 - "PluginQuirks.* uses DOS CRLF". r=jmathies (b569a6c6c8) - Bug 1152300 - When focus shifts from a native plugin window to content, content needs to forward the request for focus change to chrome. r=enn (5bd811fadd) - Bug 1185529: On Windows, ensure that NPAPI child window has the correct parent before setwindow is called. r=jimm (9d94fdf2ff) - Bug 1182411 Part 2: Change winless popup surrogate to have its parent set in the chrome process. r=jimm (adee9bb012) --- b2g/app/b2g.js | 9 +- dom/base/nsDocument.cpp | 4 +- dom/base/nsFocusManager.cpp | 26 +- dom/base/nsViewportInfo.h | 6 + dom/events/EventStateManager.cpp | 23 +- dom/ipc/PBrowser.ipdl | 13 + dom/ipc/TabChild.cpp | 454 +--- dom/ipc/TabChild.h | 25 +- dom/ipc/TabParent.cpp | 50 +- dom/ipc/TabParent.h | 4 +- dom/plugins/base/nsNPAPIPlugin.cpp | 13 - dom/plugins/base/nsPluginInstanceOwner.cpp | 108 +- dom/plugins/base/nsPluginInstanceOwner.h | 9 + dom/plugins/ipc/PPluginInstance.ipdl | 17 +- dom/plugins/ipc/PluginInstanceChild.cpp | 153 +- dom/plugins/ipc/PluginInstanceChild.h | 10 +- dom/plugins/ipc/PluginInstanceParent.cpp | 123 +- dom/plugins/ipc/PluginInstanceParent.h | 10 + dom/plugins/ipc/PluginModuleChild.cpp | 49 +- dom/plugins/ipc/PluginModuleChild.h | 56 +- dom/plugins/ipc/PluginModuleParent.cpp | 16 +- dom/plugins/ipc/PluginModuleParent.h | 9 + dom/plugins/ipc/PluginQuirks.cpp | 69 + dom/plugins/ipc/PluginQuirks.h | 69 + dom/plugins/ipc/PluginWidgetParent.cpp | 5 +- dom/plugins/ipc/moz.build | 2 + gfx/layers/AxisPhysicsMSDModel.cpp | 25 +- gfx/layers/AxisPhysicsMSDModel.h | 2 +- gfx/layers/FrameMetrics.h | 5 - gfx/layers/apz/src/APZCTreeManager.cpp | 170 +- gfx/layers/apz/src/APZCTreeManager.h | 2 +- gfx/layers/apz/src/AsyncPanZoomController.cpp | 73 +- gfx/layers/apz/src/AsyncPanZoomController.h | 13 +- gfx/layers/apz/src/GestureEventListener.cpp | 4 +- gfx/layers/apz/src/HitTestingTreeNode.cpp | 5 +- gfx/layers/apz/util/APZCCallbackHelper.cpp | 71 +- gfx/layers/apz/util/APZCCallbackHelper.h | 3 + gfx/layers/apz/util/APZEventState.cpp | 6 +- .../composite/AsyncCompositionManager.cpp | 122 +- gfx/thebes/gfxPrefs.h | 1 + js/src/asmjs/AsmJSModule.h | 40 +- js/src/asmjs/AsmJSValidate.cpp | 2419 ++++++++++------- js/src/builtin/TypedObject.cpp | 4 +- js/src/devtools/rootAnalysis/annotations.js | 3 +- js/src/vm/HelperThreads.h | 2 +- js/src/vm/NativeObject.cpp | 20 +- js/src/vm/NativeObject.h | 4 +- js/src/vm/UnboxedObject.cpp | 4 +- layout/base/MobileViewportManager.cpp | 284 ++ layout/base/MobileViewportManager.h | 62 + layout/base/RestyleTracker.cpp | 14 +- layout/base/UnitTransforms.h | 39 + layout/base/ZoomConstraintsClient.cpp | 4 +- layout/base/moz.build | 1 + layout/base/nsIPresShell.h | 11 +- layout/base/nsPresShell.cpp | 32 + layout/base/nsPresShell.h | 10 +- layout/generic/nsGfxScrollFrame.cpp | 10 +- modules/libpref/init/all.js | 1 + widget/InputData.cpp | 123 +- widget/InputData.h | 54 +- widget/MouseEvents.h | 16 + widget/PuppetWidget.cpp | 17 + widget/PuppetWidget.h | 3 + widget/cocoa/SwipeTracker.h | 96 + widget/cocoa/SwipeTracker.mm | 219 ++ widget/cocoa/moz.build | 7 +- widget/cocoa/nsChildView.h | 29 +- widget/cocoa/nsChildView.mm | 403 +-- widget/cocoa/nsCocoaUtils.h | 8 +- widget/cocoa/nsCocoaUtils.mm | 41 +- widget/cocoa/nsCocoaWindow.mm | 3 + widget/nsGUIEventIPC.h | 8 +- widget/nsIWidget.h | 5 +- widget/windows/nsWindow.cpp | 33 +- xulrunner/app/moz.build | 2 +- 76 files changed, 3506 insertions(+), 2359 deletions(-) create mode 100644 dom/plugins/ipc/PluginQuirks.cpp create mode 100644 dom/plugins/ipc/PluginQuirks.h create mode 100644 layout/base/MobileViewportManager.cpp create mode 100644 layout/base/MobileViewportManager.h create mode 100644 widget/cocoa/SwipeTracker.h create mode 100644 widget/cocoa/SwipeTracker.mm diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index bdd0ea85d5..5e5c43c988 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -4,6 +4,8 @@ #filter substitution +// For the all MOZ_MULET ifdef conditions in this file: see bug 1174234 + #ifndef MOZ_MULET pref("toolkit.defaultChromeURI", "chrome://b2g/content/shell.html"); pref("browser.chromeURL", "chrome://b2g/content/"); @@ -385,7 +387,9 @@ pref("dom.ipc.processCount", 100000); pref("dom.ipc.browser_frames.oop_by_default", false); +#ifndef MOZ_MULET pref("dom.meta-viewport.enabled", true); +#endif // SMS/MMS pref("dom.sms.enabled", true); @@ -956,7 +960,10 @@ pref("security.exthelperapp.disable_background_handling", true); pref("osfile.reset_worker_delay", 5000); // APZC preferences. -// +#ifdef MOZ_WIDGET_GONK +pref("apz.allow_zooming", true); +#endif + // Gaia relies heavily on scroll events for now, so lets fire them // more often than the default value (100). pref("apz.asyncscroll.throttle", 40); diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index f3e9175fab..3223aa9494 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -7895,14 +7895,14 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize) return nsViewportInfo(aDisplaySize, defaultScale, /*allowZoom*/false, - /*allowDoubleTapZoom*/ true); + /*allowDoubleTapZoom*/ false); } if (!gfxPrefs::MetaViewportEnabled()) { return nsViewportInfo(aDisplaySize, defaultScale, /*allowZoom*/ false, - /*allowDoubleTapZoom*/ true); + /*allowDoubleTapZoom*/ false); } // In cases where the width of the CSS viewport is less than or equal to the width diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 5c69dbc44a..fc4c6f81f4 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1641,14 +1641,24 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear, nsIFrame* contentFrame = content->GetPrimaryFrame(); nsIObjectFrame* objectFrame = do_QueryFrame(contentFrame); if (aAdjustWidgets && objectFrame && !sTestMode) { - // note that the presshell's widget is being retrieved here, not the one - // for the object frame. - nsViewManager* vm = presShell->GetViewManager(); - if (vm) { - nsCOMPtr widget; - vm->GetRootWidget(getter_AddRefs(widget)); - if (widget) - widget->SetFocus(false); + if (XRE_IsContentProcess()) { + // set focus to the top level window via the chrome process. + nsCOMPtr tabChild = do_GetInterface(docShell); + if (tabChild) { + static_cast(tabChild.get())->SendDispatchFocusToTopLevelWindow(); + } + } else { + // note that the presshell's widget is being retrieved here, not the one + // for the object frame. + nsViewManager* vm = presShell->GetViewManager(); + if (vm) { + nsCOMPtr widget; + vm->GetRootWidget(getter_AddRefs(widget)); + if (widget) { + // set focus to the top level window but don't raise it. + widget->SetFocus(false); + } + } } } } diff --git a/dom/base/nsViewportInfo.h b/dom/base/nsViewportInfo.h index b0556b7163..b4f60b9d22 100644 --- a/dom/base/nsViewportInfo.h +++ b/dom/base/nsViewportInfo.h @@ -34,6 +34,9 @@ class MOZ_STACK_CLASS nsViewportInfo mAllowZoom(aAllowZoom), mAllowDoubleTapZoom(aAllowDoubleTapZoom) { + // Don't allow double-tap zooming unless zooming is also allowed + MOZ_ASSERT(mAllowZoom || !mAllowDoubleTapZoom); + mSize = mozilla::ScreenSize(aDisplaySize) / mDefaultZoom; mozilla::CSSToLayoutDeviceScale pixelRatio(1.0f); mMinZoom = pixelRatio * kViewportMinScale; @@ -56,6 +59,9 @@ class MOZ_STACK_CLASS nsViewportInfo mAllowZoom(aAllowZoom), mAllowDoubleTapZoom(aAllowDoubleTapZoom) { + // Don't allow double-tap zooming unless zooming is also allowed + MOZ_ASSERT(mAllowZoom || !mAllowDoubleTapZoom); + ConstrainViewportValues(); } diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index dc3b370c65..505a98f92c 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -3143,12 +3143,31 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, } case WheelPrefs::ACTION_NONE: default: - // If we don't handle the wheel event, all of the delta values must - // be overflown delta values. + bool allDeltaOverflown = false; + if (wheelEvent->mFlags.mHandledByAPZ) { + if (wheelEvent->mCanTriggerSwipe) { + // For events that can trigger swipes, APZ needs to know whether + // scrolling is possible in the requested direction. It does this + // by looking at the scroll overflow values on mCanTriggerSwipe + // events after they have been processed. + allDeltaOverflown = + !ComputeScrollTarget(aTargetFrame, wheelEvent, + COMPUTE_DEFAULT_ACTION_TARGET); + } + } else { + // The event was processed neither by APZ nor by us, so all of the + // delta values must be overflown delta values. + allDeltaOverflown = true; + } + + if (!allDeltaOverflown) { + break; + } wheelEvent->overflowDeltaX = wheelEvent->deltaX; wheelEvent->overflowDeltaY = wheelEvent->deltaY; WheelPrefs::GetInstance()-> CancelApplyingUserPrefsFromOverflowDelta(wheelEvent); + wheelEvent->mViewPortIsOverscrolled = true; break; } *aStatus = nsEventStatus_eConsumeNoDefault; diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index f66972fab2..fcdd22b6e5 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -141,6 +141,19 @@ parent: */ sync GetWidgetNativeData() returns (WindowsHandle value); + /** + * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the + * widget's shareable window on the chrome side. Only used on Windows. + */ + async SetNativeChildOfShareableWindow(uintptr_t childWindow); + + /** + * When content moves focus from a native plugin window that's a child + * of the native browser window we need to move native focus to the + * browser. Otherwise the plugin window will never relinquish focus. + */ + sync DispatchFocusToTopLevelWindow(); + parent: /** * When child sends this message, parent should move focus to diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 391c4c9f07..8c4e8d774e 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -165,8 +165,7 @@ NS_IMPL_ISUPPORTS(TabChild::DelayedFireContextMenuEvent, nsITimerCallback) TabChildBase::TabChildBase() - : mContentDocumentIsDisplayed(false) - , mTabChildGlobal(nullptr) + : mTabChildGlobal(nullptr) { mozilla::HoldJSObjects(this); } @@ -206,280 +205,6 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase) NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase) -// For the root frame, Screen and ParentLayer pixels are interchangeable. -// nsViewportInfo stores zoom values as CSSToScreenScale (because it's a -// data structure specific to the root frame), while FrameMetrics and -// ZoomConstraints store zoom values as CSSToParentLayerScale (because they -// are not specific to the root frame). We define convenience functions for -// converting between the two. As the name suggests, they should only be used -// when dealing with the root frame! -CSSToScreenScale ConvertScaleForRoot(CSSToParentLayerScale aScale) -{ - return ViewTargetAs(aScale, PixelCastJustification::ScreenIsParentLayerForRoot); -} -CSSToParentLayerScale ConvertScaleForRoot(CSSToScreenScale aScale) -{ - return ViewTargetAs(aScale, PixelCastJustification::ScreenIsParentLayerForRoot); -} - -// Calculate the scale needed to fit the given viewport into the given display. -CSSToScreenScale CalculateIntrinsicScale(const ScreenIntSize& aDisplaySize, const CSSSize& aViewportSize) -{ - return MaxScaleRatio(ScreenSize(aDisplaySize), aViewportSize); -} - -void -TabChildBase::InitializeRootMetrics() -{ - // Calculate a really simple resolution that we probably won't - // be keeping, as well as putting the scroll offset back to - // the top-left of the page. - mLastRootMetrics.SetViewport(CSSRect(CSSPoint(), kDefaultViewportSize)); - mLastRootMetrics.SetCompositionBounds(ParentLayerRect( - ParentLayerPoint(), - ParentLayerSize( - ViewAs(GetInnerSize(), - PixelCastJustification::ScreenIsParentLayerForRoot)))); - mLastRootMetrics.SetZoom(CSSToParentLayerScale2D( - ConvertScaleForRoot(CalculateIntrinsicScale(GetInnerSize(), kDefaultViewportSize)))); - mLastRootMetrics.SetDevPixelsPerCSSPixel(WebWidget()->GetDefaultScale()); - // We use ParentLayerToLayerScale(1) below in order to turn the - // async zoom amount into the gecko zoom amount. - mLastRootMetrics.SetCumulativeResolution(mLastRootMetrics.GetZoom() / mLastRootMetrics.GetDevPixelsPerCSSPixel() * ParentLayerToLayerScale(1)); - // This is the root layer, so the cumulative resolution is the same - // as the resolution. - mLastRootMetrics.SetPresShellResolution(mLastRootMetrics.GetCumulativeResolution().ToScaleFactor().scale); - - nsCOMPtr shell = GetPresShell(); - if (shell && shell->GetRootScrollFrameAsScrollable()) { - // The session history code might restore a scroll position when navigating - // back or forward, and we don't want to clobber that. - nsPoint pos = shell->GetRootScrollFrameAsScrollable()->GetScrollPosition(); - mLastRootMetrics.SetScrollOffset(CSSPoint::FromAppUnits(pos)); - } else { - mLastRootMetrics.SetScrollOffset(CSSPoint(0, 0)); - } - - TABC_LOG("After InitializeRootMetrics, mLastRootMetrics is %s\n", - Stringify(mLastRootMetrics).c_str()); -} - -void -TabChildBase::SetCSSViewport(const CSSSize& aSize) -{ - mOldViewportSize = aSize; - TABC_LOG("Setting CSS viewport to %s\n", Stringify(aSize).c_str()); - - if (mContentDocumentIsDisplayed) { - if (nsCOMPtr shell = GetPresShell()) { - nsLayoutUtils::SetCSSViewport(shell, aSize); - } - } -} - -CSSSize -TabChildBase::GetPageSize(nsCOMPtr aDocument, const CSSSize& aViewport) -{ - nsCOMPtr htmlDOMElement = aDocument->GetHtmlElement(); - HTMLBodyElement* bodyDOMElement = aDocument->GetBodyElement(); - - if (!htmlDOMElement && !bodyDOMElement) { - // For non-HTML content (e.g. SVG), just assume page size == viewport size. - return aViewport; - } - - int32_t htmlWidth = 0, htmlHeight = 0; - if (htmlDOMElement) { - htmlWidth = htmlDOMElement->ScrollWidth(); - htmlHeight = htmlDOMElement->ScrollHeight(); - } - int32_t bodyWidth = 0, bodyHeight = 0; - if (bodyDOMElement) { - bodyWidth = bodyDOMElement->ScrollWidth(); - bodyHeight = bodyDOMElement->ScrollHeight(); - } - return CSSSize(std::max(htmlWidth, bodyWidth), - std::max(htmlHeight, bodyHeight)); -} - -bool -TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize) -{ - PuppetWidget* widget = WebWidget(); - if (!widget || !widget->AsyncPanZoomEnabled()) { - return false; - } - - TABC_LOG("HandlePossibleViewportChange aOldScreenSize=%s mInnerSize=%s\n", - Stringify(aOldScreenSize).c_str(), Stringify(GetInnerSize()).c_str()); - - nsCOMPtr document(GetDocument()); - if (!document) { - return false; - } - - nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, GetInnerSize()); - uint32_t presShellId = 0; - mozilla::layers::FrameMetrics::ViewID viewId = FrameMetrics::NULL_SCROLL_ID; - APZCCallbackHelper::GetOrCreateScrollIdentifiers( - document->GetDocumentElement(), &presShellId, &viewId); - - float screenW = GetInnerSize().width; - float screenH = GetInnerSize().height; - CSSSize viewport(viewportInfo.GetSize()); - - // We're not being displayed in any way; don't bother doing anything because - // that will just confuse future adjustments. - if (!screenW || !screenH) { - return false; - } - - TABC_LOG("HandlePossibleViewportChange mOldViewportSize=%s viewport=%s\n", - Stringify(mOldViewportSize).c_str(), Stringify(viewport).c_str()); - CSSSize oldBrowserSize = mOldViewportSize; - mLastRootMetrics.SetViewport(CSSRect( - mLastRootMetrics.GetViewport().TopLeft(), viewport)); - if (oldBrowserSize == CSSSize()) { - oldBrowserSize = kDefaultViewportSize; - } - SetCSSViewport(viewport); - - // If this page has not been painted yet, then this must be getting run - // because a meta-viewport element was added (via the DOMMetaAdded handler). - // in this case, we should not do anything that forces a reflow (see bug - // 759678) such as requesting the page size or sending a viewport update. this - // code will get run again in the before-first-paint handler and that point we - // will run though all of it. the reason we even bother executing up to this - // point on the DOMMetaAdded handler is so that scripts that use - // window.innerWidth before they are painted have a correct value (bug - // 771575). - if (!mContentDocumentIsDisplayed) { - return false; - } - - ScreenIntSize oldScreenSize = aOldScreenSize; - if (oldScreenSize == ScreenIntSize()) { - oldScreenSize = GetInnerSize(); - } - - FrameMetrics metrics(mLastRootMetrics); - metrics.SetViewport(CSSRect(CSSPoint(), viewport)); - - // Calculate the composition bounds based on the inner size, excluding the sizes - // of the scrollbars if they are not overlay scrollbars. - ScreenSize compositionSize(GetInnerSize()); - nsCOMPtr shell = GetPresShell(); - if (shell) { - nsMargin scrollbarsAppUnits = - nsLayoutUtils::ScrollbarAreaToExcludeFromCompositionBoundsFor(shell->GetRootScrollFrame()); - // Scrollbars are not subject to scaling, so CSS pixels = screen pixels for them. - ScreenMargin scrollbars = CSSMargin::FromAppUnits(scrollbarsAppUnits) - * CSSToScreenScale(1.0f); - compositionSize.width -= scrollbars.LeftRight(); - compositionSize.height -= scrollbars.TopBottom(); - } - - metrics.SetCompositionBounds(ParentLayerRect( - ParentLayerPoint(), - ParentLayerSize( - ViewAs(GetInnerSize(), - PixelCastJustification::ScreenIsParentLayerForRoot)))); - metrics.SetRootCompositionSize( - ScreenSize(compositionSize) * ScreenToLayoutDeviceScale(1.0f) / metrics.GetDevPixelsPerCSSPixel()); - - // This change to the zoom accounts for all types of changes I can conceive: - // 1. screen size changes, CSS viewport does not (pages with no meta viewport - // or a fixed size viewport) - // 2. screen size changes, CSS viewport also does (pages with a device-width - // viewport) - // 3. screen size remains constant, but CSS viewport changes (meta viewport - // tag is added or removed) - // 4. neither screen size nor CSS viewport changes - // - // In all of these cases, we maintain how much actual content is visible - // within the screen width. Note that "actual content" may be different with - // respect to CSS pixels because of the CSS viewport size changing. - CSSToScreenScale oldIntrinsicScale = CalculateIntrinsicScale(oldScreenSize, oldBrowserSize); - CSSToScreenScale newIntrinsicScale = CalculateIntrinsicScale(GetInnerSize(), viewport); - metrics.ZoomBy(newIntrinsicScale.scale / oldIntrinsicScale.scale); - - // Changing the zoom when we're not doing a first paint will get ignored - // by AsyncPanZoomController and causes a blurry flash. - bool isFirstPaint = true; - if (shell) { - isFirstPaint = shell->GetIsFirstPaint(); - } - if (isFirstPaint) { - // FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of - // 0.0 to mean "did not calculate a zoom". In that case, we default - // it to the intrinsic scale. - if (viewportInfo.GetDefaultZoom().scale < 0.01f) { - viewportInfo.SetDefaultZoom(newIntrinsicScale); - } - - CSSToScreenScale defaultZoom = viewportInfo.GetDefaultZoom(); - MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom && - defaultZoom <= viewportInfo.GetMaxZoom()); - metrics.SetZoom(CSSToParentLayerScale2D(ConvertScaleForRoot(defaultZoom))); - - metrics.SetPresShellId(presShellId); - metrics.SetScrollId(viewId); - } - - if (shell) { - if (nsPresContext* context = shell->GetPresContext()) { - metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale( - (float)nsPresContext::AppUnitsPerCSSPixel() / context->AppUnitsPerDevPixel())); - } - } - - metrics.SetCumulativeResolution(metrics.GetZoom() - / metrics.GetDevPixelsPerCSSPixel() - * ParentLayerToLayerScale(1)); - // This is the root layer, so the cumulative resolution is the same - // as the resolution. - metrics.SetPresShellResolution(metrics.GetCumulativeResolution().ToScaleFactor().scale); - if (shell) { - nsLayoutUtils::SetResolutionAndScaleTo(shell, metrics.GetPresShellResolution()); - nsLayoutUtils::SetScrollPositionClampingScrollPortSize(shell, - metrics.CalculateCompositedSizeInCssPixels()); - } - - // The call to GetPageSize forces a resize event to content, so we need to - // make sure that we have the right CSS viewport and - // scrollPositionClampingScrollPortSize set up before that happens. - - CSSSize pageSize = GetPageSize(document, viewport); - if (!pageSize.width) { - // Return early rather than divide by 0. - return false; - } - metrics.SetScrollableRect(CSSRect(CSSPoint(), pageSize)); - - // Calculate a display port _after_ having a scrollable rect because the - // display port is clamped to the scrollable rect. - metrics.SetDisplayPortMargins(APZCTreeManager::CalculatePendingDisplayPort( - // The page must have been refreshed in some way such as a new document or - // new CSS viewport, so we know that there's no velocity, acceleration, and - // we have no idea how long painting will take. - metrics, ParentLayerPoint(0.0f, 0.0f), 0.0)); - metrics.SetUseDisplayPortMargins(); - - // Force a repaint with these metrics. This, among other things, sets the - // displayport, so we start with async painting. - mLastRootMetrics = ProcessUpdateFrame(metrics); - - return true; -} - -already_AddRefed -TabChildBase::GetDOMWindowUtils() -{ - nsCOMPtr window = do_GetInterface(WebNavigation()); - nsCOMPtr utils = do_GetInterface(window); - return utils.forget(); -} - already_AddRefed TabChildBase::GetDocument() const { @@ -535,7 +260,7 @@ TabChildBase::UpdateFrameHandler(const FrameMetrics& aFrameMetrics) // Guard against stale updates (updates meant for a pres shell which // has since been torn down and destroyed). if (aFrameMetrics.GetPresShellId() == shell->GetPresShellId()) { - mLastRootMetrics = ProcessUpdateFrame(aFrameMetrics); + ProcessUpdateFrame(aFrameMetrics); return true; } } @@ -549,11 +274,11 @@ TabChildBase::UpdateFrameHandler(const FrameMetrics& aFrameMetrics) return true; } -FrameMetrics +void TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics) { if (!mGlobal || !mTabChildGlobal) { - return aFrameMetrics; + return; } FrameMetrics newMetrics = aFrameMetrics; @@ -591,7 +316,6 @@ TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics) data.AppendLiteral(" }"); DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data); - return newMetrics; } NS_IMETHODIMP @@ -909,22 +633,6 @@ TabChild::TabChild(nsIContentChild* aManager, } } -NS_IMETHODIMP -TabChild::HandleEvent(nsIDOMEvent* aEvent) -{ - nsAutoString eventType; - aEvent->GetType(eventType); - if (eventType.EqualsLiteral("DOMMetaAdded")) { - // This meta data may or may not have been a meta viewport tag. If it was, - // we should handle it immediately. - HandlePossibleViewportChange(GetInnerSize()); - } else if (eventType.EqualsLiteral("FullZoomChange")) { - HandlePossibleViewportChange(GetInnerSize()); - } - - return NS_OK; -} - NS_IMETHODIMP TabChild::Observe(nsISupports *aSubject, const char *aTopic, @@ -957,19 +665,7 @@ TabChild::Observe(nsISupports *aSubject, shell->SetIsFirstPaint(true); } - mContentDocumentIsDisplayed = true; - - // In some cases before-first-paint gets called before - // RecvUpdateDimensions is called and therefore before we have an - // inner size value set. In such cases defer initializing the viewport - // until we we get an inner size. - if (HasValidInnerSize()) { - InitializeRootMetrics(); - if (shell) { - nsLayoutUtils::SetResolutionAndScaleTo(shell, mLastRootMetrics.GetPresShellResolution()); - } - HandlePossibleViewportChange(GetInnerSize()); - } + APZCCallbackHelper::InitializeRootDisplayport(shell); } } } @@ -1027,100 +723,6 @@ TabChild::Observe(nsISupports *aSubject, return NS_OK; } -NS_IMETHODIMP -TabChild::OnStateChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - uint32_t aStateFlags, - nsresult aStatus) -{ - NS_NOTREACHED("not implemented in TabChild"); - return NS_OK; -} - -NS_IMETHODIMP -TabChild::OnProgressChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - int32_t aCurSelfProgress, - int32_t aMaxSelfProgress, - int32_t aCurTotalProgress, - int32_t aMaxTotalProgress) -{ - NS_NOTREACHED("not implemented in TabChild"); - return NS_OK; -} - -NS_IMETHODIMP -TabChild::OnLocationChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsIURI *aLocation, - uint32_t aFlags) -{ - if (!AsyncPanZoomEnabled()) { - return NS_OK; - } - - nsCOMPtr window; - aWebProgress->GetDOMWindow(getter_AddRefs(window)); - if (!window) { - return NS_OK; - } - - nsCOMPtr progressDoc; - window->GetDocument(getter_AddRefs(progressDoc)); - if (!progressDoc) { - return NS_OK; - } - - nsCOMPtr domDoc; - WebNavigation()->GetDocument(getter_AddRefs(domDoc)); - if (!domDoc || !SameCOMIdentity(domDoc, progressDoc)) { - return NS_OK; - } - - nsCOMPtr urifixup(do_GetService(NS_URIFIXUP_CONTRACTID)); - if (!urifixup) { - return NS_OK; - } - - nsCOMPtr exposableURI; - urifixup->CreateExposableURI(aLocation, getter_AddRefs(exposableURI)); - if (!exposableURI) { - return NS_OK; - } - - if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) { - mContentDocumentIsDisplayed = false; - } else if (mLastURI != nullptr) { - bool exposableEqualsLast, exposableEqualsNew; - exposableURI->Equals(mLastURI.get(), &exposableEqualsLast); - exposableURI->Equals(aLocation, &exposableEqualsNew); - if (exposableEqualsLast && !exposableEqualsNew) { - mContentDocumentIsDisplayed = false; - } - } - - return NS_OK; -} - -NS_IMETHODIMP -TabChild::OnStatusChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsresult aStatus, - const char16_t* aMessage) -{ - NS_NOTREACHED("not implemented in TabChild"); - return NS_OK; -} - -NS_IMETHODIMP -TabChild::OnSecurityChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - uint32_t aState) -{ - NS_NOTREACHED("not implemented in TabChild"); - return NS_OK; -} - bool TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId, const ViewID& aViewId, @@ -1201,10 +803,6 @@ TabChild::Init() loadContext->SetRemoteTabs( mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW); - nsCOMPtr webProgress = do_GetInterface(docShell); - NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE); - webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION); - // Few lines before, baseWindow->Create() will end up creating a new // window root in nsGlobalWindow::SetDocShell. // Then this chrome event handler, will be inherited to inner windows. @@ -1249,8 +847,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TabChild) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIWindowProvider) - NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) - NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) NS_INTERFACE_MAP_ENTRY(nsITabChild) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) @@ -1651,12 +1247,6 @@ TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener, return NS_OK; } -bool -TabChild::HasValidInnerSize() -{ - return mHasValidInnerSize; -} - void TabChild::DestroyWindow() { @@ -2112,40 +1702,25 @@ TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, mUnscaledOuterRect = rect; mChromeDisp = chromeDisp; - bool initialSizing = !HasValidInnerSize() - && (size.width != 0 && size.height != 0); - mOrientation = orientation; - ScreenIntSize oldScreenSize = GetInnerSize(); SetUnscaledInnerSize(size); - ScreenIntSize screenSize = GetInnerSize(); - bool sizeChanged = true; - if (initialSizing) { + if (!mHasValidInnerSize && size.width != 0 && size.height != 0) { mHasValidInnerSize = true; - } else if (screenSize == oldScreenSize) { - sizeChanged = false; } + ScreenIntSize screenSize = GetInnerSize(); ScreenIntRect screenRect = GetOuterRect(); - mPuppetWidget->Resize(screenRect.x + chromeDisp.x, - screenRect.y + chromeDisp.y, - screenSize.width, screenSize.height, true); + // Set the size on the document viewer before we update the widget and + // trigger a reflow. Otherwise the MobileViewportManager reads the stale + // size from the content viewer when it computes a new CSS viewport. nsCOMPtr baseWin = do_QueryInterface(WebNavigation()); baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height, true); - if (initialSizing && mContentDocumentIsDisplayed) { - // If this is the first time we're getting a valid inner size, and the - // before-first-paint event has already been handled, then we need to set - // up our default viewport here. See the corresponding call to - // InitializeRootMetrics in the before-first-paint handler. - InitializeRootMetrics(); - } - - if (sizeChanged) { - HandlePossibleViewportChange(oldScreenSize); - } + mPuppetWidget->Resize(screenRect.x + chromeDisp.x, + screenRect.y + chromeDisp.y, + screenSize.width, screenSize.height, true); return true; } @@ -3000,9 +2575,6 @@ TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading) nsCOMPtr root = do_QueryInterface(chromeHandler); NS_ENSURE_TRUE(root, false); root->SetParentTarget(scope); - - chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false); - chromeHandler->AddEventListener(NS_LITERAL_STRING("FullZoomChange"), this, false); } if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 53051f4e6a..164630f82b 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -21,7 +21,6 @@ #include "nsIDocShell.h" #include "nsIInterfaceRequestorUtils.h" #include "nsFrameMessageManager.h" -#include "nsIWebProgressListener.h" #include "nsIPresShell.h" #include "nsIScriptObjectPrincipal.h" #include "nsWeakReference.h" @@ -183,12 +182,6 @@ public: virtual nsIWebNavigation* WebNavigation() const = 0; virtual PuppetWidget* WebWidget() = 0; nsIPrincipal* GetPrincipal() { return mPrincipal; } - // 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. - bool HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize); virtual bool DoUpdateZoomConstraints(const uint32_t& aPresShellId, const mozilla::layers::FrameMetrics::ViewID& aViewId, const Maybe& aConstraints) = 0; @@ -197,19 +190,12 @@ public: protected: virtual ~TabChildBase(); - CSSSize GetPageSize(nsCOMPtr aDocument, const CSSSize& aViewport); - // Get the DOMWindowUtils for the top-level window in this tab. - already_AddRefed GetDOMWindowUtils(); // Get the Document for the top-level window in this tab. already_AddRefed GetDocument() const; // Get the pres-shell of the document for the top-level window in this tab. already_AddRefed GetPresShell() 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. // @@ -218,17 +204,12 @@ protected: void DispatchMessageManagerMessage(const nsAString& aMessageName, const nsAString& aJSONData); - void InitializeRootMetrics(); - - mozilla::layers::FrameMetrics ProcessUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics); + void ProcessUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics); bool UpdateFrameHandler(const mozilla::layers::FrameMetrics& aFrameMetrics); protected: - CSSSize mOldViewportSize; - bool mContentDocumentIsDisplayed; nsRefPtr mTabChildGlobal; - mozilla::layers::FrameMetrics mLastRootMetrics; nsCOMPtr mWebBrowserChrome; }; @@ -239,8 +220,6 @@ class TabChild final : public TabChildBase, public nsIWebBrowserChromeFocus, public nsIInterfaceRequestor, public nsIWindowProvider, - public nsIDOMEventListener, - public nsIWebProgressListener, public nsSupportsWeakReference, public nsITabChild, public nsIObserver, @@ -288,8 +267,6 @@ public: NS_DECL_NSIWEBBROWSERCHROMEFOCUS NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIWINDOWPROVIDER - NS_DECL_NSIDOMEVENTLISTENER - NS_DECL_NSIWEBPROGRESSLISTENER NS_DECL_NSITABCHILD NS_DECL_NSIOBSERVER NS_DECL_NSITOOLTIPLISTENER diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 538f65906d..fe1e8127fe 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2521,10 +2521,9 @@ TabParent::RecvGetMaxTouchPoints(uint32_t* aTouchPoints) return true; } -bool -TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue) +already_AddRefed +TabParent::GetTopLevelWidget() { - *aValue = 0; nsCOMPtr content = do_QueryInterface(mFrameElement); if (content) { nsIPresShell* shell = content->OwnerDoc()->GetShell(); @@ -2532,12 +2531,49 @@ TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue) nsViewManager* vm = shell->GetViewManager(); nsCOMPtr widget; vm->GetRootWidget(getter_AddRefs(widget)); - if (widget) { - *aValue = reinterpret_cast( - widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)); - } + return widget.forget(); } } + return nullptr; +} + +bool +TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue) +{ + *aValue = 0; + nsCOMPtr widget = GetTopLevelWidget(); + if (widget) { + *aValue = reinterpret_cast( + widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)); + } + return true; +} + +bool +TabParent::RecvSetNativeChildOfShareableWindow(const uintptr_t& aChildWindow) +{ +#if defined(XP_WIN) + nsCOMPtr widget = GetTopLevelWidget(); + if (widget) { + // Note that this call will probably cause a sync native message to the + // process that owns the child window. + widget->SetNativeData(NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW, aChildWindow); + } + return true; +#else + NS_NOTREACHED( + "TabParent::RecvSetNativeChildOfShareableWindow not implemented!"); + return false; +#endif +} + +bool +TabParent::RecvDispatchFocusToTopLevelWindow() +{ + nsCOMPtr widget = GetTopLevelWidget(); + if (widget) { + widget->SetFocus(false); + } return true; } diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 1114edad78..23e8a4a696 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -116,7 +116,7 @@ public: } already_AddRefed GetLoadContext(); - + already_AddRefed GetTopLevelWidget(); nsIXULBrowserWindow* GetXULBrowserWindow(); void Destroy(); @@ -218,6 +218,8 @@ public: virtual bool RecvGetDefaultScale(double* aValue) override; virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override; virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override; + virtual bool RecvSetNativeChildOfShareableWindow(const uintptr_t& childWindow) override; + virtual bool RecvDispatchFocusToTopLevelWindow() override; virtual bool RecvZoomToRect(const uint32_t& aPresShellId, const ViewID& aViewId, const CSSRect& aRect) override; diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index 38aed2ca79..d27de8bb0d 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -2164,19 +2164,6 @@ _getvalue(NPP npp, NPNVariable variable, void *result) nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) (npp ? npp->ndata : nullptr); double scaleFactor = inst ? inst->GetContentsScaleFactor() : 1.0; - // Work around a Flash ActionScript bug that causes long hangs if - // Flash thinks HiDPI support is available. Adobe is tracking this as - // ADBE 3921114. If this turns out to be Adobe's fault and they fix it, - // we'll no longer need this quirk. See QUIRK_FLASH_HIDE_HIDPI_SUPPORT - // in PluginModuleChild.h, and also bug 1118615. - if (inst) { - const char *mimeType; - inst->GetMIMEType(&mimeType); - NS_NAMED_LITERAL_CSTRING(flash, "application/x-shockwave-flash"); - if (!PL_strncasecmp(mimeType, flash.get(), flash.Length())) { - scaleFactor = 1.0; - } - } *(double*)result = scaleFactor; return NPERR_NO_ERROR; } diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 7d6f94ba2f..c56f9014c5 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -622,23 +622,17 @@ nsPluginInstanceOwner::RedrawPlugin() return NS_OK; } -NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value) -{ - if (!mPluginFrame) { - NS_WARNING("plugin owner has no owner in getting doc's window handle"); - return NS_ERROR_FAILURE; - } - #if defined(XP_WIN) - void** pvalue = (void**)value; - nsViewManager* vm = mPluginFrame->PresContext()->GetPresShell()->GetViewManager(); - if (!vm) - return NS_ERROR_FAILURE; +nsIWidget* +nsPluginInstanceOwner::GetContainingWidgetIfOffset() +{ + MOZ_ASSERT(mPluginFrame, "Caller should have checked for null mPluginFrame."); + // This property is provided to allow a "windowless" plugin to determine the window it is drawing // in, so it can translate mouse coordinates it receives directly from the operating system // to coordinates relative to itself. - // The original code (outside this #if) returns the document's window, which is OK if the window the "windowless" plugin + // The original code returns the document's window, which is OK if the window the "windowless" plugin // is drawing into has the same origin as the document's window, but this is not the case for "windowless" plugins inside of scrolling DIVs etc // To make sure "windowless" plugins always get the right origin for translating mouse coordinates, this code @@ -672,17 +666,53 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value) if (offset.x || offset.y) { // in the case the two windows are offset from eachother, we do go ahead and return the correct enclosing window // so that mouse co-ordinates are not messed up. - *pvalue = (void*)win->GetNativeData(NS_NATIVE_WINDOW); - if (*pvalue) - return NS_OK; + return win; } } } + + return nullptr; +} + +static already_AddRefed +GetRootWidgetForPluginFrame(const nsPluginFrame* aPluginFrame) +{ + MOZ_ASSERT(aPluginFrame); + + nsViewManager* vm = + aPluginFrame->PresContext()->GetPresShell()->GetViewManager(); + if (!vm) { + NS_WARNING("Could not find view manager for plugin frame."); + return nullptr; + } + + nsCOMPtr rootWidget; + vm->GetRootWidget(getter_AddRefs(rootWidget)); + return rootWidget.forget(); +} +#endif + +NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value) +{ + if (!mPluginFrame) { + NS_WARNING("plugin owner has no owner in getting doc's window handle"); + return NS_ERROR_FAILURE; + } + +#if defined(XP_WIN) + void** pvalue = (void**)value; + nsIWidget* offsetContainingWidget = GetContainingWidgetIfOffset(); + if (offsetContainingWidget) { + *pvalue = (void*)offsetContainingWidget->GetNativeData(NS_NATIVE_WINDOW); + if (*pvalue) { + return NS_OK; + } + } + // simply return the topmost document window - nsCOMPtr widget; - vm->GetRootWidget(getter_AddRefs(widget)); + nsCOMPtr widget = GetRootWidgetForPluginFrame(mPluginFrame); if (widget) { - *pvalue = (void*)widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW); + *pvalue = widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW); } else { NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle"); } @@ -700,6 +730,48 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value) #endif } +#if defined(XP_WIN) +void +nsPluginInstanceOwner::SetWidgetWindowAsParent(HWND aWindowToAdopt) +{ + if (!mWidget) { + NS_ERROR("mWidget should exist before this gets called."); + return; + } + + mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, + reinterpret_cast(aWindowToAdopt)); +} + +nsresult +nsPluginInstanceOwner::SetNetscapeWindowAsParent(HWND aWindowToAdopt) +{ + if (!mPluginFrame) { + NS_WARNING("Plugin owner has no plugin frame."); + return NS_ERROR_FAILURE; + } + + // If there is a containing window that is offset then ask that to adopt. + nsIWidget* offsetWidget = GetContainingWidgetIfOffset(); + if (offsetWidget) { + offsetWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, + reinterpret_cast(aWindowToAdopt)); + return NS_OK; + } + + // Otherwise ask the topmost document window to adopt. + nsCOMPtr rootWidget = GetRootWidgetForPluginFrame(mPluginFrame); + if (!rootWidget) { + NS_ASSERTION(rootWidget, "Couldn't get topmost document's widget."); + return NS_ERROR_FAILURE; + } + + rootWidget->SetNativeData(NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW, + reinterpret_cast(aWindowToAdopt)); + return NS_OK; +} +#endif + NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel) { #ifdef XP_MACOSX diff --git a/dom/plugins/base/nsPluginInstanceOwner.h b/dom/plugins/base/nsPluginInstanceOwner.h index 2df4ee2af7..82eb32dadb 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.h +++ b/dom/plugins/base/nsPluginInstanceOwner.h @@ -111,6 +111,11 @@ public: void ReleasePluginPort(void* pluginPort); nsEventStatus ProcessEvent(const mozilla::WidgetGUIEvent& anEvent); + +#if defined(XP_WIN) + void SetWidgetWindowAsParent(HWND aWindowToAdopt); + nsresult SetNetscapeWindowAsParent(HWND aWindowToAdopt); +#endif #ifdef XP_MACOSX enum { ePluginPaintEnable, ePluginPaintDisable }; @@ -272,6 +277,10 @@ private: bool mFullScreen; void* mJavaView; #endif + +#if defined(XP_WIN) + nsIWidget* GetContainingWidgetIfOffset(); +#endif nsPluginNativeWindow *mPluginWindow; nsRefPtr mInstance; diff --git a/dom/plugins/ipc/PPluginInstance.ipdl b/dom/plugins/ipc/PPluginInstance.ipdl index 3a4a3d521d..48ee003a1d 100644 --- a/dom/plugins/ipc/PPluginInstance.ipdl +++ b/dom/plugins/ipc/PPluginInstance.ipdl @@ -68,10 +68,15 @@ intr protocol PPluginInstance child: intr __delete__(); - // Return value is only used on Windows and only when the window needs its - // parent set to the chrome widget native window. - intr NPP_SetWindow(NPRemoteWindow window) - returns (NPRemoteWindow childWindowToBeAdopted); + // This is only used on Windows and, for windowed plugins, must be called + // before the first call to NPP_SetWindow. + intr CreateChildPluginWindow() + returns (NativeWindowHandle childPluginWindow); + + // This is only used on Windows and, for windowless plugins. + async CreateChildPopupSurrogate(NativeWindowHandle netscapeWindow); + + intr NPP_SetWindow(NPRemoteWindow window); intr NPP_GetValue_NPPVpluginWantsAllNetworkStreams() returns (bool value, NPError result); @@ -213,6 +218,10 @@ parent: // Notifies the parent of its NPP_New result code. async AsyncNPP_NewResult(NPError aResult); + // Sends a native window to be adopted by the native window that would be + // returned by NPN_GetValue_NPNVnetscapeWindow. Only used on Windows. + async SetNetscapeWindowAsParent(NativeWindowHandle childWindow); + both: async PPluginScriptableObject(); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index 4a0ce514f6..2acfffdcb4 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -197,7 +197,7 @@ PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface, #endif // OS_WIN #if defined(OS_WIN) InitPopupMenuHook(); - if (GetQuirks() & PluginModuleChild::QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) { + if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) { SetUnityHooks(); } #endif // OS_WIN @@ -207,7 +207,7 @@ PluginInstanceChild::~PluginInstanceChild() { #if defined(OS_WIN) NS_ASSERTION(!mPluginWindowHWND, "Destroying PluginInstanceChild without NPP_Destroy?"); - if (GetQuirks() & PluginModuleChild::QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) { + if (GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE) { ClearUnityHooks(); } #endif @@ -405,7 +405,7 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar, } if (result == NPERR_NO_ERROR || (GetQuirks() & - PluginModuleChild::QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN)) { + QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN)) { *static_cast(aValue) = ToNewCString(v); } return result; @@ -494,11 +494,7 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar, #endif /* NP_NO_QUICKDRAW */ case NPNVcontentsScaleFactor: { - double scaleFactor = mContentsScaleFactor; - if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_HIDE_HIDPI_SUPPORT) { - scaleFactor = 1.0; - } - *static_cast(aValue) = scaleFactor; + *static_cast(aValue) = mContentsScaleFactor; return NPERR_NO_ERROR; } #endif /* XP_MACOSX */ @@ -1010,7 +1006,7 @@ PluginInstanceChild::AnswerNPP_HandleEvent_IOSurface(const NPRemoteEvent& event, mCARenderer->SetupRenderer(caLayer, mWindow.width, mWindow.height, mContentsScaleFactor, - GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ? + GetQuirks() & QUIRK_ALLOW_OFFLINE_RENDERER ? ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER); // Flash needs to have the window set again after this step @@ -1128,8 +1124,40 @@ void PluginInstanceChild::DeleteWindow() #endif bool -PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow, - NPRemoteWindow* aChildWindowToBeAdopted) +PluginInstanceChild::AnswerCreateChildPluginWindow(NativeWindowHandle* aChildPluginWindow) +{ +#if defined(XP_WIN) + MOZ_ASSERT(!mPluginWindowHWND); + + if (!CreatePluginWindow()) { + return false; + } + + MOZ_ASSERT(mPluginWindowHWND); + + *aChildPluginWindow = mPluginWindowHWND; + return true; +#else + NS_NOTREACHED("PluginInstanceChild::CreateChildPluginWindow not implemented!"); + return false; +#endif +} + +bool +PluginInstanceChild::RecvCreateChildPopupSurrogate(const NativeWindowHandle& aNetscapeWindow) +{ +#if defined(XP_WIN) + mCachedWinlessPluginHWND = aNetscapeWindow; + CreateWinlessPopupSurrogate(); + return true; +#else + NS_NOTREACHED("PluginInstanceChild::CreateChildPluginWindow not implemented!"); + return false; +#endif +} + +bool +PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow) { PLUGIN_LOG_DEBUG(("%s (aWindow=)", FULLFUNCTION, @@ -1210,42 +1238,22 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow, switch (aWindow.type) { case NPWindowTypeWindow: { - if ((GetQuirks() & PluginModuleChild::QUIRK_QUICKTIME_AVOID_SETWINDOW) && - aWindow.width == 0 && - aWindow.height == 0) { - // Skip SetWindow call for hidden QuickTime plugins - return true; - } + // This check is now done in PluginInstanceParent before this call, so + // we should never see it here. + MOZ_ASSERT(!(GetQuirks() & QUIRK_QUICKTIME_AVOID_SETWINDOW) || + aWindow.width != 0 || aWindow.height != 0); - if (!CreatePluginWindow()) - return false; + MOZ_ASSERT(mPluginWindowHWND, + "Child plugin window must exist before call to SetWindow"); + + HWND parentHWND = reinterpret_cast(aWindow.window); + if (mPluginWindowHWND != parentHWND) { + mPluginParentHWND = parentHWND; + ShowWindow(mPluginWindowHWND, SW_SHOWNA); + } SizePluginWindow(aWindow.width, aWindow.height); - // If the window is not our parent set the return child window so that - // it can be re-parented in the chrome process. Re-parenting now - // happens there as we might not have sufficient permission. - // Also, this needs to be after SizePluginWindow because SetWindowPos - // relies on things that it sets. - HWND parentWindow = reinterpret_cast(aWindow.window); - if (mPluginParentHWND != parentWindow && IsWindow(parentWindow)) { - mPluginParentHWND = parentWindow; - aChildWindowToBeAdopted->window = - reinterpret_cast(mPluginWindowHWND); - } else { - // Now we know that the window has the correct parent we can show - // it. The actual visibility is controlled by its parent. - // First time round, these calls are made by our caller after the - // parent is set. - ShowWindow(mPluginWindowHWND, SW_SHOWNA); - - // This used to be called in SizePluginWindow, but we need to make - // sure that mPluginWindowHWND has had it's parent set correctly, - // otherwise it can cause a focus issue. - SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, aWindow.width, - aWindow.height, SWP_NOZORDER | SWP_NOREPOSITION); - } - mWindow.window = (void*)mPluginWindowHWND; mWindow.x = aWindow.x; mWindow.y = aWindow.y; @@ -1272,9 +1280,7 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow, case NPWindowTypeDrawable: mWindow.type = aWindow.type; - if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) - CreateWinlessPopupSurrogate(); - if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS) + if (GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS) SetupFlashMsgThrottle(); return SharedSurfaceSetWindow(aWindow); break; @@ -1438,6 +1444,8 @@ PluginInstanceChild::SizePluginWindow(int width, if (mPluginWindowHWND) { mPluginSize.x = width; mPluginSize.y = height; + SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height, + SWP_NOZORDER | SWP_NOREPOSITION); } } @@ -1503,25 +1511,28 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd, } // The plugin received keyboard focus, let the parent know so the dom is up to date. - if (message == WM_MOUSEACTIVATE) + if (message == WM_MOUSEACTIVATE) { self->CallPluginFocusChange(true); + } // Prevent lockups due to plugins making rpc calls when the parent // is making a synchronous SendMessage call to the child window. Add // more messages as needed. if ((InSendMessageEx(nullptr)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { switch(message) { + case WM_CHILDACTIVATE: case WM_KILLFOCUS: ReplyMessage(0); break; } } - if (message == WM_KILLFOCUS) + if (message == WM_KILLFOCUS) { self->CallPluginFocusChange(false); + } if (message == WM_USER+1 && - (self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) { + (self->GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS)) { self->FlashThrottleMessage(hWnd, message, wParam, lParam, true); return 0; } @@ -1538,7 +1549,7 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd, // caused by a bug in flash, since we are not setting the capture // on the window. if (message == WM_LBUTTONDOWN && - self->GetQuirks() & PluginModuleChild::QUIRK_FLASH_FIXUP_MOUSE_CAPTURE) { + self->GetQuirks() & QUIRK_FLASH_FIXUP_MOUSE_CAPTURE) { wchar_t szClass[26]; HWND hwnd = GetForegroundWindow(); if (hwnd && GetClassNameW(hwnd, szClass, @@ -1549,11 +1560,13 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd, } } - if (message == WM_CLOSE) + if (message == WM_CLOSE) { self->DestroyPluginWindow(); + } - if (message == WM_NCDESTROY) + if (message == WM_NCDESTROY) { RemoveProp(hWnd, kPluginInstanceChildProperty); + } return res; } @@ -1697,7 +1710,7 @@ PluginInstanceChild::SetWindowLongWHook(HWND hWnd, void PluginInstanceChild::HookSetWindowLongPtr() { - if (!(GetQuirks() & PluginModuleChild::QUIRK_FLASH_HOOK_SETLONGPTR)) + if (!(GetQuirks() & QUIRK_FLASH_HOOK_SETLONGPTR)) return; sUser32Intercept.Init("user32.dll"); @@ -1784,7 +1797,7 @@ PluginInstanceChild::SetCaptureHook(HWND aHwnd) void PluginInstanceChild::SetUnityHooks() { - if (!(GetQuirks() & PluginModuleChild::QUIRK_UNITY_FIXUP_MOUSE_CAPTURE)) { + if (!(GetQuirks() & QUIRK_UNITY_FIXUP_MOUSE_CAPTURE)) { return; } @@ -1911,7 +1924,7 @@ PluginInstanceChild::TrackPopupHookProc(HMENU hMenu, void PluginInstanceChild::InitPopupMenuHook() { - if (!(GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) || + if (!(GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK) || sUser32TrackPopupMenuStub) return; @@ -1933,21 +1946,15 @@ PluginInstanceChild::CreateWinlessPopupSurrogate() if (mWinlessPopupSurrogateHWND) return; - HWND hwnd = nullptr; - NPError result; - if (!CallNPN_GetValue_NPNVnetscapeWindow(&hwnd, &result)) { - NS_ERROR("CallNPN_GetValue_NPNVnetscapeWindow failed."); - return; - } - mWinlessPopupSurrogateHWND = - CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", nullptr, WS_CHILD, - 0, 0, 0, 0, hwnd, 0, GetModuleHandle(nullptr), 0); + CreateWindowEx(WS_EX_NOPARENTNOTIFY, L"Static", nullptr, WS_POPUP, + 0, 0, 0, 0, nullptr, 0, GetModuleHandle(nullptr), 0); if (!mWinlessPopupSurrogateHWND) { NS_ERROR("CreateWindowEx failed for winless placeholder!"); return; } - return; + + SendSetNetscapeWindowAsParent(mWinlessPopupSurrogateHWND); } void @@ -1973,7 +1980,7 @@ PluginInstanceChild::WinlessHandleEvent(NPEvent& event) // TrackPopupMenu will fail if the parent window is not associated with // our ui thread. So we hook TrackPopupMenu so we can hand in a surrogate // parent created in the child process. - if ((GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default? + if ((GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK) && // XXX turn on by default? (event.event == WM_RBUTTONDOWN || // flash event.event == WM_RBUTTONUP)) { // silverlight sWinlessPopupSurrogateHWND = mWinlessPopupSurrogateHWND; @@ -2365,7 +2372,7 @@ PluginInstanceChild::AnswerSetPluginFocus() // this in response to a WM_SETFOCUS event on our parent, the parent // should have focus when we receive this. If not, ignore the call. if (::GetFocus() == mPluginWindowHWND || - ((GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT) && + ((GetQuirks() & QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT) && (::GetFocus() != mPluginParentHWND))) return true; ::SetFocus(mPluginWindowHWND); @@ -2794,7 +2801,7 @@ PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType, mContentsScaleFactor = aWindow.contentsScaleFactor; #endif - if (GetQuirks() & PluginModuleChild::QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT) + if (GetQuirks() & QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT) mIsTransparent = true; mLayersRendering = true; @@ -2802,9 +2809,7 @@ PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType, UpdateWindowAttributes(true); #ifdef XP_WIN - if (GetQuirks() & PluginModuleChild::QUIRK_WINLESS_TRACKPOPUP_HOOK) - CreateWinlessPopupSurrogate(); - if (GetQuirks() & PluginModuleChild::QUIRK_FLASH_THROTTLE_WMUSER_EVENTS) + if (GetQuirks() & QUIRK_FLASH_THROTTLE_WMUSER_EVENTS) SetupFlashMsgThrottle(); #endif @@ -2996,7 +3001,7 @@ PluginInstanceChild::EnsureCurrentBuffer(void) if (mDrawingModel == NPDrawingModelCoreGraphics) { if (!mCGLayer) { bool avoidCGCrashes = !nsCocoaFeatures::OnMountainLionOrLater() && - (GetQuirks() & PluginModuleChild::QUIRK_FLASH_AVOID_CGMODE_CRASHES); + (GetQuirks() & QUIRK_FLASH_AVOID_CGMODE_CRASHES); caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this, avoidCGCrashes, mContentsScaleFactor); @@ -3030,7 +3035,7 @@ PluginInstanceChild::EnsureCurrentBuffer(void) if (!mDoubleBufferCARenderer.HasFrontSurface()) { bool allocSurface = mDoubleBufferCARenderer.InitFrontSurface( mWindow.width, mWindow.height, mContentsScaleFactor, - GetQuirks() & PluginModuleChild::QUIRK_ALLOW_OFFLINE_RENDERER ? + GetQuirks() & QUIRK_ALLOW_OFFLINE_RENDERER ? ALLOW_OFFLINE_RENDERER : DISALLOW_OFFLINE_RENDERER); if (!allocSurface) { PLUGIN_LOG_DEBUG(("Fail to allocate front IOSurface")); @@ -3204,7 +3209,7 @@ PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect, nsIntRect plPaintRect(aRect); nsRefPtr renderSurface = aSurface; #ifdef MOZ_X11 - if (mIsTransparent && (GetQuirks() & PluginModuleChild::QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) { + if (mIsTransparent && (GetQuirks() & QUIRK_FLASH_EXPOSE_COORD_TRANSLATION)) { // Work around a bug in Flash up to 10.1 d51 at least, where expose event // top left coordinates within the plugin-rect and not at the drawable // origin are misinterpreted. (We can move the top left coordinate diff --git a/dom/plugins/ipc/PluginInstanceChild.h b/dom/plugins/ipc/PluginInstanceChild.h index b4dc88779b..0bc3b487b2 100644 --- a/dom/plugins/ipc/PluginInstanceChild.h +++ b/dom/plugins/ipc/PluginInstanceChild.h @@ -65,8 +65,14 @@ class PluginInstanceChild : public PPluginInstanceChild #endif protected: - bool AnswerNPP_SetWindow(const NPRemoteWindow& window, - NPRemoteWindow* aChildWindowToBeAdopted) override; + virtual bool + AnswerCreateChildPluginWindow(NativeWindowHandle* aChildPluginWindow) override; + + virtual bool + RecvCreateChildPopupSurrogate(const NativeWindowHandle& aNetscapeWindow) override; + + virtual bool + AnswerNPP_SetWindow(const NPRemoteWindow& window) override; virtual bool AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv) override; diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index d3d1ce2a64..57999dd1c2 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -51,6 +51,7 @@ #include "nsHashKeys.h" #include "nsIWidget.h" #include "nsPluginNativeWindow.h" +#include "PluginQuirks.h" extern const wchar_t* kFlashFullscreenClass; #elif defined(MOZ_WIDGET_GTK) #include @@ -117,6 +118,8 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent, , mDrawingModel(kDefaultDrawingModel) #if defined(OS_WIN) , mPluginHWND(nullptr) + , mChildPluginHWND(nullptr) + , mChildPluginsParentHWND(nullptr) , mPluginWndProc(nullptr) , mNestedEventState(false) #endif // defined(XP_WIN) @@ -665,6 +668,11 @@ PluginInstanceParent::AsyncSetWindow(NPWindow* aWindow) mNPNIface->getvalue(mNPP, NPNVcontentsScaleFactor, &scaleFactor); window.contentsScaleFactor = scaleFactor; #endif + +#if defined(OS_WIN) + MaybeCreateChildPopupSurrogate(); +#endif + if (!SendAsyncSetWindow(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(), window)) return NS_ERROR_FAILURE; @@ -953,16 +961,29 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow) if (!SharedSurfaceSetWindow(aWindow, window)) { return NPERR_OUT_OF_MEMORY_ERROR; } - } - else { + + MaybeCreateChildPopupSurrogate(); + } else { SubclassPluginWindow(reinterpret_cast(aWindow->window)); + // Skip SetWindow call for hidden QuickTime plugins. + if ((mParent->GetQuirks() & QUIRK_QUICKTIME_AVOID_SETWINDOW) && + aWindow->width == 0 && aWindow->height == 0) { + return NPERR_NO_ERROR; + } + window.window = reinterpret_cast(aWindow->window); window.x = aWindow->x; window.y = aWindow->y; window.width = aWindow->width; window.height = aWindow->height; window.type = aWindow->type; + + // On Windows we need to create and set the parent before we set the + // window on the plugin, or keyboard interaction will not work. + if (!MaybeCreateAndParentChildPluginWindow()) { + return NPERR_GENERIC_ERROR; + } } #else window.window = reinterpret_cast(aWindow->window); @@ -1013,31 +1034,10 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow) window.colormap = ws_info->colormap; #endif - NPRemoteWindow childWindow; - if (!CallNPP_SetWindow(window, &childWindow)) { + if (!CallNPP_SetWindow(window)) { return NPERR_GENERIC_ERROR; } -#if defined(XP_WIN) - // If a child window is returned it means that we need to re-parent it. - if (childWindow.window) { - nsCOMPtr widget; - static_cast(aWindow)-> - GetPluginWidget(getter_AddRefs(widget)); - if (widget) { - widget->SetNativeData(NS_NATIVE_CHILD_WINDOW, - static_cast(childWindow.window)); - } - - // Now it has got the correct parent, make sure it is visible. - // In subsequent calls to SetWindow these calls happen in the Child. - HWND childHWND = reinterpret_cast(childWindow.window); - ShowWindow(childHWND, SW_SHOWNA); - SetWindowPos(childHWND, nullptr, 0, 0, window.width, window.height, - SWP_NOZORDER | SWP_NOREPOSITION); - } -#endif - return NPERR_NO_ERROR; } @@ -1766,6 +1766,22 @@ PluginInstanceParent::RecvAsyncNPP_NewResult(const NPError& aResult) return true; } +bool +PluginInstanceParent::RecvSetNetscapeWindowAsParent(const NativeWindowHandle& childWindow) +{ +#if defined(XP_WIN) + nsPluginInstanceOwner* owner = GetOwner(); + if (!owner || NS_FAILED(owner->SetNetscapeWindowAsParent(childWindow))) { + NS_WARNING("Failed to set Netscape window as parent."); + } + + return true; +#else + NS_NOTREACHED("PluginInstanceParent::RecvSetNetscapeWindowAsParent not implemented!"); + return false; +#endif +} + #if defined(OS_WIN) /* @@ -2010,6 +2026,65 @@ PluginInstanceParent::SharedSurfaceAfterPaint(NPEvent* npevent) SRCCOPY); } +bool +PluginInstanceParent::MaybeCreateAndParentChildPluginWindow() +{ + // On Windows we need to create and set the parent before we set the + // window on the plugin, or keyboard interaction will not work. + if (!mChildPluginHWND) { + if (!CallCreateChildPluginWindow(&mChildPluginHWND) || + !mChildPluginHWND) { + return false; + } + } + + // It's not clear if the parent window would ever change, but when this + // was done in the NPAPI child it used to allow for this. + if (mPluginHWND == mChildPluginsParentHWND) { + return true; + } + + nsPluginInstanceOwner* owner = GetOwner(); + if (!owner) { + // We can't reparent without an owner, the plugin is probably shutting + // down, just return true to allow any calls to continue. + return true; + } + + // Note that this call will probably cause a sync native message to the + // process that owns the child window. + owner->SetWidgetWindowAsParent(mChildPluginHWND); + mChildPluginsParentHWND = mPluginHWND; + return true; +} + +void +PluginInstanceParent::MaybeCreateChildPopupSurrogate() +{ + // Already created or not required for this plugin. + if (mChildPluginHWND || mWindowType != NPWindowTypeDrawable || + !(mParent->GetQuirks() & QUIRK_WINLESS_TRACKPOPUP_HOOK)) { + return; + } + + // We need to pass the netscape window down to be cached as part of the call + // to create the surrogate, because the reparenting of the surrogate in the + // main process can cause sync Windows messages to the plugin process, which + // then cause sync messages from the plugin child for the netscape window + // which causes a deadlock. + NativeWindowHandle netscapeWindow; + NPError result = mNPNIface->getvalue(mNPP, NPNVnetscapeWindow, + &netscapeWindow); + if (NPERR_NO_ERROR != result) { + NS_WARNING("Can't get netscape window to pass to plugin child."); + return; + } + + if (!SendCreateChildPopupSurrogate(netscapeWindow)) { + NS_WARNING("Failed to create popup surrogate in child."); + } +} + #endif // defined(OS_WIN) bool diff --git a/dom/plugins/ipc/PluginInstanceParent.h b/dom/plugins/ipc/PluginInstanceParent.h index b85788b284..68e2465f59 100644 --- a/dom/plugins/ipc/PluginInstanceParent.h +++ b/dom/plugins/ipc/PluginInstanceParent.h @@ -218,6 +218,9 @@ public: virtual bool RecvAsyncNPP_NewResult(const NPError& aResult) override; + virtual bool + RecvSetNetscapeWindowAsParent(const NativeWindowHandle& childWindow) override; + NPError NPP_SetWindow(const NPWindow* aWindow); NPError NPP_GetValue(NPPVariable variable, void* retval); @@ -358,11 +361,18 @@ private: void SubclassPluginWindow(HWND aWnd); void UnsubclassPluginWindow(); + bool MaybeCreateAndParentChildPluginWindow(); + void MaybeCreateChildPopupSurrogate(); + private: gfx::SharedDIBWin mSharedSurfaceDib; nsIntRect mPluginPort; nsIntRect mSharedSize; HWND mPluginHWND; + // This is used for the normal child plugin HWND for windowed plugins and, + // if needed, also the child popup surrogate HWND for windowless plugins. + HWND mChildPluginHWND; + HWND mChildPluginsParentHWND; WNDPROC mPluginWndProc; bool mNestedEventState; diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index c1204f5636..f2b1c5f016 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -2087,56 +2087,11 @@ PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType, void PluginModuleChild::InitQuirksModes(const nsCString& aMimeType) { - if (mQuirks != QUIRKS_NOT_INITIALIZED) + if (mQuirks != QUIRKS_NOT_INITIALIZED) { return; - mQuirks = 0; - - nsPluginHost::SpecialType specialType = nsPluginHost::GetSpecialType(aMimeType); - - if (specialType == nsPluginHost::eSpecialType_Silverlight) { - mQuirks |= QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT; -#ifdef OS_WIN - mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK; - mQuirks |= QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT; -#endif } - if (specialType == nsPluginHost::eSpecialType_Flash) { - mQuirks |= QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN; -#ifdef OS_WIN - mQuirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK; - mQuirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS; - mQuirks |= QUIRK_FLASH_HOOK_SETLONGPTR; - mQuirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO; - mQuirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE; -#endif - } - -#ifdef OS_WIN - // QuickTime plugin usually loaded with audio/mpeg mimetype - NS_NAMED_LITERAL_CSTRING(quicktime, "npqtplugin"); - if (FindInReadable(quicktime, mPluginFilename)) { - mQuirks |= QUIRK_QUICKTIME_AVOID_SETWINDOW; - } -#endif - -#ifdef XP_MACOSX - // Whitelist Flash and Quicktime to support offline renderer - NS_NAMED_LITERAL_CSTRING(quicktime, "QuickTime Plugin.plugin"); - if (specialType == nsPluginHost::eSpecialType_Flash) { - mQuirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES; - mQuirks |= QUIRK_ALLOW_OFFLINE_RENDERER; - mQuirks |= QUIRK_FLASH_HIDE_HIDPI_SUPPORT; - } else if (FindInReadable(quicktime, mPluginFilename)) { - mQuirks |= QUIRK_ALLOW_OFFLINE_RENDERER; - } -#endif - -#ifdef OS_WIN - if (specialType == nsPluginHost::eSpecialType_Unity) { - mQuirks |= QUIRK_UNITY_FIXUP_MOUSE_CAPTURE; - } -#endif + mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename); } bool diff --git a/dom/plugins/ipc/PluginModuleChild.h b/dom/plugins/ipc/PluginModuleChild.h index ed6310c8e6..e9d8ec1fc1 100644 --- a/dom/plugins/ipc/PluginModuleChild.h +++ b/dom/plugins/ipc/PluginModuleChild.h @@ -31,6 +31,7 @@ #include "mozilla/plugins/PPluginModuleChild.h" #include "mozilla/plugins/PluginInstanceChild.h" #include "mozilla/plugins/PluginMessageUtils.h" +#include "mozilla/plugins/PluginQuirks.h" // NOTE: stolen from nsNPAPIPlugin.h @@ -226,61 +227,6 @@ public: } #endif - // Quirks mode support for various plugin mime types - enum PluginQuirks { - QUIRKS_NOT_INITIALIZED = 0, - // Silverlight assumes it is transparent in windowless mode. This quirk - // matches the logic in nsNPAPIPluginInstance::SetWindowless. - QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT = 1 << 0, - // Win32: Hook TrackPopupMenu api so that we can swap out parent - // hwnds. The api will fail with parents not associated with our - // child ui thread. See WinlessHandleEvent for details. - QUIRK_WINLESS_TRACKPOPUP_HOOK = 1 << 1, - // Win32: Throttle flash WM_USER+1 heart beat messages to prevent - // flooding chromium's dispatch loop, which can cause ipc traffic - // processing lag. - QUIRK_FLASH_THROTTLE_WMUSER_EVENTS = 1 << 2, - // Win32: Catch resets on our subclass by hooking SetWindowLong. - QUIRK_FLASH_HOOK_SETLONGPTR = 1 << 3, - // X11: Work around a bug in Flash up to 10.1 d51 at least, where - // expose event top left coordinates within the plugin-rect and - // not at the drawable origin are misinterpreted. - QUIRK_FLASH_EXPOSE_COORD_TRANSLATION = 1 << 4, - // Win32: Catch get window info calls on the browser and tweak the - // results so mouse input works when flash is displaying it's settings - // window. - QUIRK_FLASH_HOOK_GETWINDOWINFO = 1 << 5, - // Win: Addresses a flash bug with mouse capture and full screen - // windows. - QUIRK_FLASH_FIXUP_MOUSE_CAPTURE = 1 << 6, - // Win: QuickTime steals focus on SetWindow calls even if it's hidden. - // Avoid calling SetWindow in that case. - QUIRK_QUICKTIME_AVOID_SETWINDOW = 1 << 7, - // Win: Check to make sure the parent window has focus before calling - // set focus on the child. Addresses a full screen dialog prompt - // problem in Silverlight. - QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT = 1 << 8, - // Mac: Allow the plugin to use offline renderer mode. - // Use this only if the plugin is certified the support the offline renderer. - QUIRK_ALLOW_OFFLINE_RENDERER = 1 << 9, - // Mac: Work around a Flash bug that can cause plugin process crashes - // in CoreGraphics mode: The Flash plugin sometimes accesses the - // CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect) - // outside of that call. See bug 804606. - QUIRK_FLASH_AVOID_CGMODE_CRASHES = 1 << 10, - // Work around a Flash bug where it fails to check the error code of a - // NPN_GetValue(NPNVdocumentOrigin) call before trying to dereference - // its char* output. - QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN = 1 << 11, - // Win: Addresses a Unity bug with mouse capture. - QUIRK_UNITY_FIXUP_MOUSE_CAPTURE = 1 << 12, - // Mac: Work around a Flash ActionScript bug that causes long hangs if - // Flash thinks HiDPI support is available. Adobe is tracking this as - // ADBE 3921114. If this turns out to be Adobe's fault and they fix it, - // we'll no longer need this quirk. See bug 1118615. - QUIRK_FLASH_HIDE_HIDPI_SUPPORT = 1 << 13, - }; - int GetQuirks() { return mQuirks; } const PluginSettings& Settings() const { return mCachedSettings; } diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 57c1fd6618..f371781aa3 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -35,6 +35,7 @@ #include "nsNPAPIPlugin.h" #include "nsPrintfCString.h" #include "prsystem.h" +#include "PluginQuirks.h" #include "GeckoProfiler.h" #include "nsPluginTags.h" #include "nsUnicharUtils.h" @@ -596,7 +597,8 @@ PluginModuleChromeParent::WaitForIPCConnection() } PluginModuleParent::PluginModuleParent(bool aIsChrome) - : mIsChrome(aIsChrome) + : mQuirks(QUIRKS_NOT_INITIALIZED) + , mIsChrome(aIsChrome) , mShutdown(false) , mHadLocalInstance(false) , mClearSiteDataSupported(false) @@ -1135,10 +1137,21 @@ PluginModuleParent::GetPluginDetails() } mPluginName = pluginTag->Name(); mPluginVersion = pluginTag->Version(); + mPluginFilename = pluginTag->FileName(); mIsFlashPlugin = pluginTag->mIsFlashPlugin; return true; } +void +PluginModuleParent::InitQuirksModes(const nsCString& aMimeType) +{ + if (mQuirks != QUIRKS_NOT_INITIALIZED) { + return; + } + + mQuirks = GetQuirksFromMimeTypeAndFilename(aMimeType, mPluginFilename); +} + #ifdef XP_WIN void PluginModuleChromeParent::EvaluateHangUIState(const bool aReset) @@ -2226,6 +2239,7 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance, if (mPluginName.IsEmpty()) { GetPluginDetails(); + InitQuirksModes(nsDependentCString(pluginType)); /** mTimeBlocked measures the time that the main thread has been blocked * on plugin module initialization. As implemented, this is the sum of * plugin-container launch + toolhelp32 snapshot + NP_Initialize. diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index e4380bbe24..8f29495f1d 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -123,6 +123,8 @@ public: mHadLocalInstance = true; } + int GetQuirks() { return mQuirks; } + protected: virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace(const Message& parent, const Message& child) override @@ -248,6 +250,13 @@ protected: uint64_t maxAge) override; virtual nsresult NPP_GetSitesWithData(InfallibleTArray& result) override; +private: + + nsCString mPluginFilename; + int mQuirks; + void InitQuirksModes(const nsCString& aMimeType); + +public: #if defined(XP_MACOSX) virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing) override; virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) override; diff --git a/dom/plugins/ipc/PluginQuirks.cpp b/dom/plugins/ipc/PluginQuirks.cpp new file mode 100644 index 0000000000..86c890093e --- /dev/null +++ b/dom/plugins/ipc/PluginQuirks.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: sw=4 ts=4 et : + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PluginQuirks.h" + +#include "nsPluginHost.h" + +namespace mozilla { +namespace plugins { + +int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType, + const nsCString& aPluginFilename) +{ + int quirks = 0; + + nsPluginHost::SpecialType specialType = nsPluginHost::GetSpecialType(aMimeType); + + if (specialType == nsPluginHost::eSpecialType_Silverlight) { + quirks |= QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT; +#ifdef OS_WIN + quirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK; + quirks |= QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT; +#endif + } + + if (specialType == nsPluginHost::eSpecialType_Flash) { + quirks |= QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN; +#ifdef OS_WIN + quirks |= QUIRK_WINLESS_TRACKPOPUP_HOOK; + quirks |= QUIRK_FLASH_THROTTLE_WMUSER_EVENTS; + quirks |= QUIRK_FLASH_HOOK_SETLONGPTR; + quirks |= QUIRK_FLASH_HOOK_GETWINDOWINFO; + quirks |= QUIRK_FLASH_FIXUP_MOUSE_CAPTURE; +#endif + } + +#ifdef OS_WIN + // QuickTime plugin usually loaded with audio/mpeg mimetype + NS_NAMED_LITERAL_CSTRING(quicktime, "npqtplugin"); + if (FindInReadable(quicktime, aPluginFilename)) { + quirks |= QUIRK_QUICKTIME_AVOID_SETWINDOW; + } +#endif + +#ifdef XP_MACOSX + // Whitelist Flash and Quicktime to support offline renderer + NS_NAMED_LITERAL_CSTRING(quicktime, "QuickTime Plugin.plugin"); + if (specialType == nsPluginHost::eSpecialType_Flash) { + quirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES; + quirks |= QUIRK_ALLOW_OFFLINE_RENDERER; + } else if (FindInReadable(quicktime, aPluginFilename)) { + quirks |= QUIRK_ALLOW_OFFLINE_RENDERER; + } +#endif + +#ifdef OS_WIN + if (specialType == nsPluginHost::eSpecialType_Unity) { + quirks |= QUIRK_UNITY_FIXUP_MOUSE_CAPTURE; + } +#endif + + return quirks; +} + +} /* namespace plugins */ +} /* namespace mozilla */ diff --git a/dom/plugins/ipc/PluginQuirks.h b/dom/plugins/ipc/PluginQuirks.h new file mode 100644 index 0000000000..fb77afd74c --- /dev/null +++ b/dom/plugins/ipc/PluginQuirks.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: sw=4 ts=4 et : + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef dom_plugins_PluginQuirks_h +#define dom_plugins_PluginQuirks_h + +namespace mozilla { +namespace plugins { + +// Quirks mode support for various plugin mime types +enum PluginQuirks { + QUIRKS_NOT_INITIALIZED = 0, + // Silverlight assumes it is transparent in windowless mode. This quirk + // matches the logic in nsNPAPIPluginInstance::SetWindowless. + QUIRK_SILVERLIGHT_DEFAULT_TRANSPARENT = 1 << 0, + // Win32: Hook TrackPopupMenu api so that we can swap out parent + // hwnds. The api will fail with parents not associated with our + // child ui thread. See WinlessHandleEvent for details. + QUIRK_WINLESS_TRACKPOPUP_HOOK = 1 << 1, + // Win32: Throttle flash WM_USER+1 heart beat messages to prevent + // flooding chromium's dispatch loop, which can cause ipc traffic + // processing lag. + QUIRK_FLASH_THROTTLE_WMUSER_EVENTS = 1 << 2, + // Win32: Catch resets on our subclass by hooking SetWindowLong. + QUIRK_FLASH_HOOK_SETLONGPTR = 1 << 3, + // X11: Work around a bug in Flash up to 10.1 d51 at least, where + // expose event top left coordinates within the plugin-rect and + // not at the drawable origin are misinterpreted. + QUIRK_FLASH_EXPOSE_COORD_TRANSLATION = 1 << 4, + // Win32: Catch get window info calls on the browser and tweak the + // results so mouse input works when flash is displaying it's settings + // window. + QUIRK_FLASH_HOOK_GETWINDOWINFO = 1 << 5, + // Win: Addresses a flash bug with mouse capture and full screen + // windows. + QUIRK_FLASH_FIXUP_MOUSE_CAPTURE = 1 << 6, + // Win: QuickTime steals focus on SetWindow calls even if it's hidden. + // Avoid calling SetWindow in that case. + QUIRK_QUICKTIME_AVOID_SETWINDOW = 1 << 7, + // Win: Check to make sure the parent window has focus before calling + // set focus on the child. Addresses a full screen dialog prompt + // problem in Silverlight. + QUIRK_SILVERLIGHT_FOCUS_CHECK_PARENT = 1 << 8, + // Mac: Allow the plugin to use offline renderer mode. + // Use this only if the plugin is certified the support the offline renderer. + QUIRK_ALLOW_OFFLINE_RENDERER = 1 << 9, + // Mac: Work around a Flash bug that can cause plugin process crashes + // in CoreGraphics mode: The Flash plugin sometimes accesses the + // CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect) + // outside of that call. See bug 804606. + QUIRK_FLASH_AVOID_CGMODE_CRASHES = 1 << 10, + // Work around a Flash bug where it fails to check the error code of a + // NPN_GetValue(NPNVdocumentOrigin) call before trying to dereference + // its char* output. + QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN = 1 << 11, + // Win: Addresses a Unity bug with mouse capture. + QUIRK_UNITY_FIXUP_MOUSE_CAPTURE = 1 << 12, +}; + +int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType, + const nsCString& aPluginFilename); + +} /* namespace plugins */ +} /* namespace mozilla */ + +#endif // ifndef dom_plugins_PluginQuirks_h diff --git a/dom/plugins/ipc/PluginWidgetParent.cpp b/dom/plugins/ipc/PluginWidgetParent.cpp index e3f1298378..6891324ab4 100644 --- a/dom/plugins/ipc/PluginWidgetParent.cpp +++ b/dom/plugins/ipc/PluginWidgetParent.cpp @@ -70,6 +70,9 @@ PluginWidgetParent::GetTabParent() void PluginWidgetParent::SetParent(nsIWidget* aParent) { + // This will trigger sync send messages to the plugin process window + // procedure and a cascade of events to that window related to focus + // and activation. if (mWidget && aParent) { mWidget->SetParent(aParent); } @@ -216,7 +219,7 @@ PluginWidgetParent::RecvSetNativeChildWindow(const uintptr_t& aChildWindow) #if defined(XP_WIN) ENSURE_CHANNEL; PWLOG("PluginWidgetParent::RecvSetNativeChildWindow(%p)\n", - static_cast(aChildWindow)); + (void*)aChildWindow); mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, aChildWindow); return true; #else diff --git a/dom/plugins/ipc/moz.build b/dom/plugins/ipc/moz.build index 4894fa9111..87a4cedadd 100644 --- a/dom/plugins/ipc/moz.build +++ b/dom/plugins/ipc/moz.build @@ -31,6 +31,7 @@ EXPORTS.mozilla.plugins += [ 'PluginModuleParent.h', 'PluginProcessChild.h', 'PluginProcessParent.h', + 'PluginQuirks.h', 'PluginScriptableObjectChild.h', 'PluginScriptableObjectParent.h', 'PluginScriptableObjectUtils-inl.h', @@ -86,6 +87,7 @@ UNIFIED_SOURCES += [ 'PluginModuleParent.cpp', 'PluginProcessChild.cpp', 'PluginProcessParent.cpp', + 'PluginQuirks.cpp', 'PluginScriptableObjectChild.cpp', 'PluginScriptableObjectParent.cpp', 'PluginStreamChild.cpp', diff --git a/gfx/layers/AxisPhysicsMSDModel.cpp b/gfx/layers/AxisPhysicsMSDModel.cpp index f200ad4884..f9232d5f1a 100644 --- a/gfx/layers/AxisPhysicsMSDModel.cpp +++ b/gfx/layers/AxisPhysicsMSDModel.cpp @@ -70,30 +70,23 @@ AxisPhysicsMSDModel::SetDestination(double aDestination) } bool -AxisPhysicsMSDModel::IsFinished() +AxisPhysicsMSDModel::IsFinished(double aSmallestVisibleIncrement) { // In order to satisfy the condition of reaching the destination, the distance // between the simulation position and the destination must be less than - // kFinishDistance while the speed is simultaneously less than - // kFinishVelocity. This enables an under-damped system to overshoot the + // aSmallestVisibleIncrement while the speed is simultaneously less than + // finishVelocity. This enables an under-damped system to overshoot the // destination when desired without prematurely triggering the finished state. - - // As the number of app units per css pixel is 60 and retina / HiDPI displays - // may display two pixels for every css pixel, setting kFinishDistance to 30.0 - // ensures that there will be no perceptable shift in position at the end - // of the animation. - const double kFinishDistance = 30.0; - - // If kFinishVelocity is set too low, the animation may end long after + // If finishVelocity is set too low, the animation may end long after // oscillation has finished, resulting in unnecessary processing. // If set too high, the animation may prematurely terminate when expected // to overshoot the destination in an under-damped system. - // 60.0 was selected through experimentation that revealed that a - // critically damped system will terminate within 100ms. - const double kFinishVelocity = 60.0; + // aSmallestVisibleIncrement * 2 was selected through experimentation that + // revealed that a critically damped system will terminate within 100ms. + const double finishVelocity = aSmallestVisibleIncrement * 2; - return fabs(mDestination - GetPosition ()) < kFinishDistance - && fabs(GetVelocity()) <= kFinishVelocity; + return fabs(mDestination - GetPosition ()) < aSmallestVisibleIncrement + && fabs(GetVelocity()) <= finishVelocity; } } // namespace layers diff --git a/gfx/layers/AxisPhysicsMSDModel.h b/gfx/layers/AxisPhysicsMSDModel.h index 42cc64f2bb..838007a510 100644 --- a/gfx/layers/AxisPhysicsMSDModel.h +++ b/gfx/layers/AxisPhysicsMSDModel.h @@ -38,7 +38,7 @@ public: * Returns true when the position is close to the destination and the * velocity is low. */ - bool IsFinished(); + bool IsFinished(double aSmallestVisibleIncrement); protected: virtual double Acceleration(const State &aState); diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index 7442e50612..b9957596bc 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -120,11 +120,6 @@ public: return (def == *this); } - bool IsRootScrollable() const - { - return mIsRootContent; - } - bool IsScrollable() const { return mScrollId != NULL_SCROLL_ID; diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 93ffdf6233..d0b67bcb6e 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -601,12 +601,13 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // want to pass to gecko should be the pre-scroll event coordinates, // transformed into the gecko space. (pre-scroll because the mouse // cursor is stationary during wheel scrolling, unlike touchmove - // events). Also, since we just flushed the pending repaints the - // transform to gecko space is a no-op so we can just skip it. - MOZ_ASSERT( - (GetScreenToApzcTransform(apzc) * GetApzcToGeckoTransform(apzc)) - .NudgeToIntegersFixedEpsilon() - .IsIdentity()); + // events). Since we just flushed the pending repaints the transform to + // gecko space should only consist of overscroll-cancelling transforms. + Matrix4x4 transformToGecko = GetScreenToApzcTransform(apzc) + * GetApzcToGeckoTransform(apzc); + MOZ_ASSERT(transformToGecko.Is2D()); + ScreenPoint untransformedOrigin = TransformTo( + transformToGecko, wheelInput.mOrigin); result = mInputQueue->ReceiveInputEvent( apzc, @@ -615,6 +616,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // Update the out-parameters so they are what the caller expects. apzc->GetGuid(aOutTargetGuid); + wheelInput.mOrigin = untransformedOrigin; } break; } case PANGESTURE_INPUT: { @@ -633,6 +635,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, apzc->GetGuid(aOutTargetGuid); Matrix4x4 transformToGecko = GetScreenToApzcTransform(apzc) * GetApzcToGeckoTransform(apzc); + MOZ_ASSERT(transformToGecko.Is2D()); panInput.mPanStartPoint = TransformTo( transformToGecko, panInput.mPanStartPoint); panInput.mPanDisplacement = TransformVector( @@ -655,6 +658,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, apzc->GetGuid(aOutTargetGuid); Matrix4x4 outTransform = GetScreenToApzcTransform(apzc) * GetApzcToGeckoTransform(apzc); + MOZ_ASSERT(outTransform.Is2D()); pinchInput.mFocusPoint = TransformTo( outTransform, pinchInput.mFocusPoint); } @@ -675,6 +679,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, apzc->GetGuid(aOutTargetGuid); Matrix4x4 outTransform = GetScreenToApzcTransform(apzc) * GetApzcToGeckoTransform(apzc); + MOZ_ASSERT(outTransform.Is2D()); tapInput.mPoint = TransformTo(outTransform, tapInput.mPoint); } break; @@ -784,12 +789,8 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput, Matrix4x4 transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock); Matrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock); Matrix4x4 outTransform = transformToApzc * transformToGecko; - if (aInput.mType == MultiTouchInput::MULTITOUCH_START) { - // For touch-start events we should have flushed all pending repaints - // above as part of the GetTouchInputBlockAPZC call, and so we expect - // the apzc-to-gecko transform to be empty. - MOZ_ASSERT(outTransform.NudgeToIntegersFixedEpsilon().IsIdentity()); - } + MOZ_ASSERT(outTransform.Is2D()); + for (size_t i = 0; i < aInput.mTouches.Length(); i++) { SingleTouchData& touchData = aInput.mTouches[i]; touchData.mScreenPoint = TransformTo( @@ -830,6 +831,7 @@ APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint, Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc); Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc); Matrix4x4 outTransform = transformToApzc * transformToGecko; + MOZ_ASSERT(outTransform.Is2D()); *aOutTransformedPoint = TransformTo(outTransform, aPoint); } } @@ -899,6 +901,7 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent, Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc); Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc); Matrix4x4 outTransform = transformToApzc * transformToGecko; + MOZ_ASSERT(outTransform.Is2D()); aEvent.refPoint = TransformTo(outTransform, aEvent.refPoint); } return result; @@ -910,14 +913,15 @@ APZCTreeManager::ProcessWheelEvent(WidgetWheelEvent& aEvent, uint64_t* aOutInputBlockId) { ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT; - if (gfxPrefs::SmoothScrollEnabled() && gfxPrefs::WheelSmoothScrollEnabled()) { + if (aEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE && + gfxPrefs::SmoothScrollEnabled() && gfxPrefs::WheelSmoothScrollEnabled()) { scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH; } ScreenPoint origin(aEvent.refPoint.x, aEvent.refPoint.y); ScrollWheelInput input(aEvent.time, aEvent.timeStamp, 0, scrollMode, - ScrollWheelInput::SCROLLDELTA_LINE, + ScrollWheelInput::DeltaTypeForDeltaMode(aEvent.deltaMode), origin, aEvent.deltaX, aEvent.deltaY); @@ -938,8 +942,15 @@ APZCTreeManager::ProcessWheelEvent(WidgetWheelEvent& aEvent, static bool WillHandleWheelEvent(WidgetWheelEvent* aEvent) { + // Only support pixel units on OS X for now because it causes more test + // failures when APZ is turned on, and we want to do that on Windows very + // soon. return EventStateManager::WheelEventIsScrollAction(aEvent) && - aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE && + (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE +#ifdef XP_MACOSX + || aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL +#endif + ) && !EventStateManager::WheelEventNeedsDeltaMultipliers(aEvent); } @@ -1187,8 +1198,9 @@ APZCTreeManager::GetRootNode() const * @param aTarget the target APZC * @param aStartPoint the start point of the displacement * @param aEndPoint the end point of the displacement + * @return true on success, false if aStartPoint or aEndPoint cannot be transformed into target's coordinate space */ -static void +static bool TransformDisplacement(APZCTreeManager* aTreeManager, AsyncPanZoomController* aSource, AsyncPanZoomController* aTarget, @@ -1199,10 +1211,18 @@ TransformDisplacement(APZCTreeManager* aTreeManager, ScreenPoint screenStart = TransformTo(untransformToApzc, aStartPoint); ScreenPoint screenEnd = TransformTo(untransformToApzc, aEndPoint); + // Convert start and end points to aTarget's ParentLayer coordinates. Matrix4x4 transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget); - aStartPoint = TransformTo(transformToApzc, screenStart); - aEndPoint = TransformTo(transformToApzc, screenEnd); + Maybe startPoint = UntransformTo(transformToApzc, screenStart); + Maybe endPoint = UntransformTo(transformToApzc, screenEnd); + if (!startPoint || !endPoint) { + return false; + } + aEndPoint = *endPoint; + aStartPoint = *startPoint; + + return true; } bool @@ -1233,7 +1253,9 @@ APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev, // scroll grabbing to grab the scroll from it), don't bother doing the // transformations in that case. if (next != aPrev) { - TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint); + if (!TransformDisplacement(this, aPrev, next, aStartPoint, aEndPoint)) { + return false; + } } // Scroll |next|. If this causes overscroll, it will call DispatchScroll() @@ -1286,19 +1308,20 @@ APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev, // Only transform when current apcz can be transformed with previous if (startIndex > 0) { - TransformDisplacement(this, + if (!TransformDisplacement(this, aOverscrollHandoffChain->GetApzcAtIndex(startIndex - 1), current, startPoint, - endPoint); + endPoint)) { + return false; + } } transformedVelocity = endPoint - startPoint; - bool handoff = (startIndex < 1) ? aHandoff : true; if (current->AttemptFling(transformedVelocity, aOverscrollHandoffChain, - handoff)) { + aHandoff)) { return true; } } @@ -1519,26 +1542,30 @@ APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode, return nullptr; } -AsyncPanZoomController* -APZCTreeManager::FindRootApzcForLayersId(uint64_t aLayersId) const +/* + * Do a breadth-first search of the tree rooted at |aRoot|, and return the + * first visited node that satisfies |aCondition|, or nullptr if no such node + * was found. + * + * |Node| should have methods GetLastChild() and GetPrevSibling(). + */ +template +static const Node* BreadthFirstSearch(const Node* aRoot, const Condition& aCondition) { - mTreeLock.AssertCurrentThreadOwns(); - - if (!mRootNode) { + if (!aRoot) { return nullptr; } - std::deque queue; - queue.push_back(mRootNode); + std::deque queue; + queue.push_back(aRoot); while (!queue.empty()) { - const HitTestingTreeNode* node = queue.front(); + const Node* node = queue.front(); queue.pop_front(); - AsyncPanZoomController* apzc = node->GetApzc(); - if (apzc && apzc->GetLayersId() == aLayersId && apzc->IsRootForLayersId()) { - return apzc; + if (aCondition(node)) { + return node; } - for (HitTestingTreeNode* child = node->GetLastChild(); + for (const Node* child = node->GetLastChild(); child; child = child->GetPrevSibling()) { queue.push_back(child); @@ -1548,6 +1575,44 @@ APZCTreeManager::FindRootApzcForLayersId(uint64_t aLayersId) const return nullptr; } +AsyncPanZoomController* +APZCTreeManager::FindRootApzcForLayersId(uint64_t aLayersId) const +{ + mTreeLock.AssertCurrentThreadOwns(); + + struct RootForLayersIdMatcher { + uint64_t mLayersId; + bool operator()(const HitTestingTreeNode* aNode) const { + AsyncPanZoomController* apzc = aNode->GetApzc(); + return apzc + && apzc->GetLayersId() == mLayersId + && apzc->IsRootForLayersId(); + } + }; + const HitTestingTreeNode* resultNode = BreadthFirstSearch(mRootNode.get(), + RootForLayersIdMatcher{aLayersId}); + return resultNode ? resultNode->GetApzc() : nullptr; +} + +AsyncPanZoomController* +APZCTreeManager::FindRootContentApzcForLayersId(uint64_t aLayersId) const +{ + mTreeLock.AssertCurrentThreadOwns(); + + struct RootContentForLayersIdMatcher { + uint64_t mLayersId; + bool operator()(const HitTestingTreeNode* aNode) const { + AsyncPanZoomController* apzc = aNode->GetApzc(); + return apzc + && apzc->GetLayersId() == mLayersId + && apzc->IsRootContent(); + } + }; + const HitTestingTreeNode* resultNode = BreadthFirstSearch(mRootNode.get(), + RootContentForLayersIdMatcher{aLayersId}); + return resultNode ? resultNode->GetApzc() : nullptr; +} + /* The methods GetScreenToApzcTransform() and GetApzcToGeckoTransform() return some useful transformations that input events may need applied. This is best illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L @@ -1716,17 +1781,31 @@ APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) co already_AddRefed APZCTreeManager::GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const { - nsRefPtr apzc = CommonAncestor(aApzc1, aApzc2); - // For now, we only ever want to do pinching on the root APZC for a given layers id. So - // when we find the common ancestor of multiple points, also walk up to the root APZC. - apzc = RootAPZCForLayersId(apzc); + MonitorAutoLock lock(mTreeLock); + nsRefPtr apzc; + // For now, we only ever want to do pinching on the root-content APZC for + // a given layers id. + if (aApzc1 && aApzc2 && aApzc1->GetLayersId() == aApzc2->GetLayersId()) { + // If the two APZCs have the same layers id, find the root-content APZC + // for that layers id. Don't call CommonAncestor() because there may not + // be a common ancestor for the layers id (e.g. if one APZCs is inside a + // fixed-position element). + apzc = FindRootContentApzcForLayersId(aApzc1->GetLayersId()); + } else { + // Otherwise, find the common ancestor (to reach a common layers id), and + // get the root-content APZC for that layers id. + apzc = CommonAncestor(aApzc1, aApzc2); + if (apzc) { + apzc = FindRootContentApzcForLayersId(apzc->GetLayersId()); + } + } return apzc.forget(); } already_AddRefed APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const { - MonitorAutoLock lock(mTreeLock); + mTreeLock.AssertCurrentThreadOwns(); nsRefPtr ancestor; // If either aApzc1 or aApzc2 is null, min(depth1, depth2) will be 0 and this function @@ -1769,16 +1848,5 @@ APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomCont return ancestor.forget(); } -already_AddRefed -APZCTreeManager::RootAPZCForLayersId(AsyncPanZoomController* aApzc) const -{ - MonitorAutoLock lock(mTreeLock); - nsRefPtr apzc = aApzc; - while (apzc && !apzc->HasNoParentWithSameLayersId()) { - apzc = apzc->GetParent(); - } - return apzc.forget(); -} - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index ae3b678e26..9a9269dc47 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -425,9 +425,9 @@ private: const ParentLayerPoint& aHitTestPoint, HitTestResult* aOutHitResult); AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId) const; + AsyncPanZoomController* FindRootContentApzcForLayersId(uint64_t aLayersId) const; already_AddRefed GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const; already_AddRefed CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const; - already_AddRefed RootAPZCForLayersId(AsyncPanZoomController* aApzc) const; already_AddRefed GetTouchInputBlockAPZC(const MultiTouchInput& aEvent, HitTestResult* aOutHitResult); nsEventStatus ProcessTouchInput(MultiTouchInput& aInput, diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 3e7262a482..3af27e95d4 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -693,7 +693,10 @@ public: * or false if the smooth scroll has ended. */ bool DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) { - if (mXAxisModel.IsFinished() && mYAxisModel.IsFinished()) { + nsPoint oneParentLayerPixel = + CSSPoint::ToAppUnits(ParentLayerPoint(1, 1) / aFrameMetrics.GetZoom()); + if (mXAxisModel.IsFinished(oneParentLayerPixel.x) && + mYAxisModel.IsFinished(oneParentLayerPixel.y)) { return false; } @@ -710,12 +713,12 @@ public: // Keep the velocity updated for the Axis class so that any animations // chained off of the smooth scroll will inherit it. - if (mXAxisModel.IsFinished()) { + if (mXAxisModel.IsFinished(oneParentLayerPixel.x)) { mApzc.mX.SetVelocity(0); } else { mApzc.mX.SetVelocity(velocity.x); } - if (mYAxisModel.IsFinished()) { + if (mYAxisModel.IsFinished(oneParentLayerPixel.y)) { mApzc.mY.SetVelocity(0); } else { mApzc.mY.SetVelocity(velocity.y); @@ -958,7 +961,9 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent, switch (aEvent.mInputType) { case MULTITOUCH_INPUT: { MultiTouchInput multiTouchInput = aEvent.AsMultiTouchInput(); - multiTouchInput.TransformToLocal(aTransformToApzc); + if (!multiTouchInput.TransformToLocal(aTransformToApzc)) { + return rv; + } nsRefPtr listener = GetGestureEventListener(); if (listener) { @@ -979,7 +984,9 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent, } case PANGESTURE_INPUT: { PanGestureInput panGestureInput = aEvent.AsPanGestureInput(); - panGestureInput.TransformToLocal(aTransformToApzc); + if (!panGestureInput.TransformToLocal(aTransformToApzc)) { + return rv; + } switch (panGestureInput.mType) { case PanGestureInput::PANGESTURE_MAYSTART: rv = OnPanMayBegin(panGestureInput); break; @@ -996,21 +1003,27 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent, } case SCROLLWHEEL_INPUT: { ScrollWheelInput scrollInput = aEvent.AsScrollWheelInput(); - scrollInput.TransformToLocal(aTransformToApzc); + if (!scrollInput.TransformToLocal(aTransformToApzc)) { + return rv; + } rv = OnScrollWheel(scrollInput); break; } case PINCHGESTURE_INPUT: { PinchGestureInput pinchInput = aEvent.AsPinchGestureInput(); - pinchInput.TransformToLocal(aTransformToApzc); + if (!pinchInput.TransformToLocal(aTransformToApzc)) { + return rv; + } rv = HandleGestureEvent(pinchInput); break; } case TAPGESTURE_INPUT: { TapGestureInput tapInput = aEvent.AsTapGestureInput(); - tapInput.TransformToLocal(aTransformToApzc); + if (!tapInput.TransformToLocal(aTransformToApzc)) { + return rv; + } rv = HandleGestureEvent(tapInput); break; @@ -1068,6 +1081,7 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent case SMOOTH_SCROLL: case OVERSCROLL_ANIMATION: case WHEEL_SCROLL: + case PAN_MOMENTUM: CurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll); // Fall through. case NOTHING: { @@ -1138,6 +1152,7 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent) case PANNING: case PANNING_LOCKED_X: case PANNING_LOCKED_Y: + case PAN_MOMENTUM: TrackTouch(aEvent); return nsEventStatus_eConsumeNoDefault; @@ -1202,6 +1217,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) case PANNING: case PANNING_LOCKED_X: case PANNING_LOCKED_Y: + case PAN_MOMENTUM: { CurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints(); mX.EndTouch(aEvent.mTime); @@ -1294,7 +1310,7 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) { // would have to be adjusted (as e.g. it would no longer be valid to take // the minimum or maximum of the ratios of the widths and heights of the // page rect and the composition bounds). - MOZ_ASSERT(mFrameMetrics.IsRootScrollable()); + MOZ_ASSERT(mFrameMetrics.IsRootContent()); MOZ_ASSERT(mFrameMetrics.GetZoom().AreScalesSame()); float prevSpan = aEvent.mPreviousSpan; @@ -1400,13 +1416,18 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent } bool -AsyncPanZoomController::ConvertToGecko(const ParentLayerPoint& aPoint, CSSPoint* aOut) +AsyncPanZoomController::ConvertToGecko(const ScreenIntPoint& aPoint, CSSPoint* aOut) { if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) { - Matrix4x4 transformToGecko = treeManagerLocal->GetApzcToGeckoTransform(this); + Matrix4x4 transformScreenToGecko = treeManagerLocal->GetScreenToApzcTransform(this) + * treeManagerLocal->GetApzcToGeckoTransform(this); + // NOTE: This isn't *quite* LayoutDevicePoint, we just don't have a name // for this coordinate space and it maps the closest to LayoutDevicePoint. - LayoutDevicePoint layoutPoint = TransformTo(transformToGecko, aPoint); + MOZ_ASSERT(transformScreenToGecko.Is2D()); + LayoutDevicePoint layoutPoint = TransformTo( + transformScreenToGecko, aPoint); + { // scoped lock to access mFrameMetrics ReentrantMonitorAutoEnter lock(mMonitor); *aOut = layoutPoint / mFrameMetrics.GetDevPixelsPerCSSPixel(); @@ -1429,6 +1450,10 @@ AsyncPanZoomController::GetScrollWheelDelta(const ScrollWheelInput& aEvent) cons delta.y *= scrollAmount.height; break; } + case ScrollWheelInput::SCROLLDELTA_PIXEL: { + // aOutDeltaX is already in CSS pixels. + break; + } default: MOZ_ASSERT_UNREACHABLE("unexpected scroll delta type"); } @@ -1694,6 +1719,7 @@ nsEventStatus AsyncPanZoomController::OnPanMomentumStart(const PanGestureInput& } mPanGestureState = MakeUnique(this, true); + SetState(PAN_MOMENTUM); return nsEventStatus_eConsumeNoDefault; } @@ -1708,6 +1734,7 @@ nsEventStatus AsyncPanZoomController::OnPanMomentumEnd(const PanGestureInput& aE // animation started, but I guess it doesn't really matter for now. mX.CancelTouch(); mY.CancelTouch(); + SetState(NOTHING); RequestContentRepaint(); @@ -1719,7 +1746,7 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) nsRefPtr controller = GetGeckoContentController(); if (controller) { CSSPoint geckoScreenPoint; - if (ConvertToGecko(aEvent.mLocalPoint, &geckoScreenPoint)) { + if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) { if (CurrentTouchBlock()->IsDuringFastMotion()) { APZC_LOG("%p dropping long-press because of fast motion\n", this); return nsEventStatus_eIgnore; @@ -1734,10 +1761,10 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) nsEventStatus AsyncPanZoomController::OnLongPressUp(const TapGestureInput& aEvent) { APZC_LOG("%p got a long-tap-up in state %d\n", this, mState); - return GenerateSingleTap(aEvent.mLocalPoint, aEvent.modifiers); + return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers); } -nsEventStatus AsyncPanZoomController::GenerateSingleTap(const ParentLayerPoint& aPoint, mozilla::Modifiers aModifiers) { +nsEventStatus AsyncPanZoomController::GenerateSingleTap(const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers) { nsRefPtr controller = GetGeckoContentController(); if (controller) { CSSPoint geckoScreenPoint; @@ -1773,14 +1800,14 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven // If mZoomConstraints.mAllowDoubleTapZoom is true we wait for a call to OnSingleTapConfirmed before // sending event to content if (!(mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom())) { - return GenerateSingleTap(aEvent.mLocalPoint, aEvent.modifiers); + return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers); } return nsEventStatus_eIgnore; } nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) { APZC_LOG("%p got a single-tap-confirmed in state %d\n", this, mState); - return GenerateSingleTap(aEvent.mLocalPoint, aEvent.modifiers); + return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers); } nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) { @@ -1789,7 +1816,7 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) if (controller) { if (mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom()) { CSSPoint geckoScreenPoint; - if (ConvertToGecko(aEvent.mLocalPoint, &geckoScreenPoint)) { + if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) { controller->HandleDoubleTap(geckoScreenPoint, aEvent.modifiers, GetGuid()); } } @@ -1817,6 +1844,7 @@ ScreenPoint AsyncPanZoomController::ToScreenCoordinates(const ParentLayerPoint& return TransformVector(GetTransformToThis().Inverse(), aVector, aAnchor); } +// TODO: figure out a good way to check the w-coordinate is positive and return the result ParentLayerPoint AsyncPanZoomController::ToParentLayerCoordinates(const ScreenPoint& aVector, const ScreenPoint& aAnchor) const { return TransformVector(GetTransformToThis(), aVector, aAnchor); @@ -1825,14 +1853,17 @@ ParentLayerPoint AsyncPanZoomController::ToParentLayerCoordinates(const ScreenPo bool AsyncPanZoomController::Contains(const ScreenIntPoint& aPoint) const { Matrix4x4 transformToThis = GetTransformToThis(); - ParentLayerIntPoint point = TransformTo(transformToThis, aPoint); + Maybe point = UntransformTo(transformToThis, aPoint); + if (!point) { + return false; + } ParentLayerIntRect cb; { ReentrantMonitorAutoEnter lock(mMonitor); GetFrameMetrics().GetCompositionBounds().ToIntRect(&cb); } - return cb.Contains(point); + return cb.Contains(*point); } ScreenCoord AsyncPanZoomController::PanDistance() const { @@ -2977,7 +3008,7 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) { // would have to be adjusted (as e.g. it would no longer be valid to take // the minimum or maximum of the ratios of the widths and heights of the // page rect and the composition bounds). - MOZ_ASSERT(mFrameMetrics.IsRootScrollable()); + MOZ_ASSERT(mFrameMetrics.IsRootContent()); MOZ_ASSERT(mFrameMetrics.GetZoom().AreScalesSame()); SetState(ANIMATING_ZOOM); diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index 766b5dc04c..30d463fcdf 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -601,12 +601,12 @@ protected: void FireAsyncScrollOnTimeout(); /** - * Convert ScreenPoint relative to this APZC to CSSPoint relative + * Convert ScreenPoint relative to the screen to CSSPoint relative * to the parent document. This excludes the transient compositor transform. * NOTE: This must be converted to CSSPoint relative to the child - * document before sending over IPC. + * document before sending over IPC to a child process. */ - bool ConvertToGecko(const ParentLayerPoint& aPoint, CSSPoint* aOut); + bool ConvertToGecko(const ScreenIntPoint& aPoint, CSSPoint* aOut); enum AxisLockMode { FREE, /* No locking at all */ @@ -617,7 +617,7 @@ protected: static AxisLockMode GetAxisLockMode(); // Helper function for OnSingleTapUp() and OnSingleTapConfirmed(). - nsEventStatus GenerateSingleTap(const ParentLayerPoint& aPoint, mozilla::Modifiers aModifiers); + nsEventStatus GenerateSingleTap(const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers); // Common processing at the end of a touch block. void OnTouchEndOrCancel(); @@ -728,6 +728,8 @@ protected: PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */ PANNING_LOCKED_Y, /* as above for Y axis */ + PAN_MOMENTUM, /* like PANNING, but controlled by momentum PanGestureInput events */ + CROSS_SLIDING_X, /* Panning disabled while user does a horizontal gesture on a vertically-scrollable view. This used for the Windows Metro "cross-slide" gesture. */ @@ -885,8 +887,7 @@ public: } /* Returns true if there is no APZC higher in the tree with the same - * layers id. Deprecated. New code shouldn't use this. Old code should be - * updated to not use this. + * layers id. */ bool HasNoParentWithSameLayersId() const { return !mParent || (mParent->mLayersId != mLayersId); diff --git a/gfx/layers/apz/src/GestureEventListener.cpp b/gfx/layers/apz/src/GestureEventListener.cpp index 628e7fd1e6..7ef09e48a7 100644 --- a/gfx/layers/apz/src/GestureEventListener.cpp +++ b/gfx/layers/apz/src/GestureEventListener.cpp @@ -54,9 +54,7 @@ TapGestureInput CreateTapEvent(const MultiTouchInput& aTouch, TapGestureInput::T return TapGestureInput(aType, aTouch.mTime, aTouch.mTimeStamp, - // Use mLocalScreenPoint as this goes directly to APZC - // without being transformed in APZCTreeManager. - aTouch.mTouches[0].mLocalScreenPoint, + aTouch.mTouches[0].mScreenPoint, aTouch.modifiers); } diff --git a/gfx/layers/apz/src/HitTestingTreeNode.cpp b/gfx/layers/apz/src/HitTestingTreeNode.cpp index 9a8693d49f..cb3308e963 100644 --- a/gfx/layers/apz/src/HitTestingTreeNode.cpp +++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp @@ -207,10 +207,7 @@ HitTestingTreeNode::Untransform(const ParentLayerPoint& aPoint) const if (mApzc) { localTransform = localTransform * mApzc->GetCurrentAsyncTransformWithOverscroll(); } - gfx::Point4D point = localTransform.Inverse().ProjectPoint(aPoint.ToUnknownPoint()); - return point.HasPositiveWCoord() - ? Some(ViewAs(point.As2DPoint())) - : Nothing(); + return UntransformTo(localTransform.Inverse(), aPoint); } HitTestResult diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index 88053cf65c..1cce2be322 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -7,8 +7,10 @@ #include "ContentHelper.h" #include "gfxPlatform.h" // For gfxPlatform::UseTiling +#include "gfxPrefs.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/TabParent.h" +#include "mozilla/IntegerPrintfMacros.h" #include "mozilla/layers/LayerTransactionChild.h" #include "mozilla/layers/ShadowLayers.h" #include "mozilla/TouchEvents.h" @@ -31,6 +33,8 @@ namespace layers { using dom::TabParent; +uint64_t APZCCallbackHelper::sLastTargetAPZCNotificationInputBlock = uint64_t(-1); + static void AdjustDisplayPortForScrollDelta(mozilla::layers::FrameMetrics& aFrameMetrics, const CSSPoint& aActualScrollOffset) @@ -194,34 +198,41 @@ APZCCallbackHelper::UpdateRootFrame(FrameMetrics& aMetrics) MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins()); - float presShellResolution = nsLayoutUtils::GetResolution(shell); + if (gfxPrefs::APZAllowZooming()) { + // If zooming is disabled then we don't really want to let APZ fiddle + // with these things. In theory setting the resolution here should be a + // no-op, but setting the SPCSPS is bad because it can cause a stale value + // to be returned by window.innerWidth/innerHeight (see bug 1187792). - // If the pres shell resolution has changed on the content side side - // the time this repaint request was fired, consider this request out of date - // and drop it; setting a zoom based on the out-of-date resolution can have - // the effect of getting us stuck with the stale resolution. - if (presShellResolution != aMetrics.GetPresShellResolution()) { - return; + float presShellResolution = nsLayoutUtils::GetResolution(shell); + + // If the pres shell resolution has changed on the content side side + // the time this repaint request was fired, consider this request out of date + // and drop it; setting a zoom based on the out-of-date resolution can have + // the effect of getting us stuck with the stale resolution. + if (presShellResolution != aMetrics.GetPresShellResolution()) { + return; + } + + // Set the scroll port size, which determines the scroll range. For example if + // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would + // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent + // overscroll). Note that if the content here was zoomed to 2x, the document would + // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum + // scroll range would be 900. Therefore this calculation depends on the zoom applied + // to the content relative to the container. + // Note that this needs to happen before scrolling the frame (in UpdateFrameCommon), + // otherwise the scroll position may get clamped incorrectly. + CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); + nsLayoutUtils::SetScrollPositionClampingScrollPortSize(shell, scrollPort); + + // The pres shell resolution is updated by the the async zoom since the + // last paint. + presShellResolution = aMetrics.GetPresShellResolution() + * aMetrics.GetAsyncZoom().scale; + nsLayoutUtils::SetResolutionAndScaleTo(shell, presShellResolution); } - // Set the scroll port size, which determines the scroll range. For example if - // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would - // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent - // overscroll). Note that if the content here was zoomed to 2x, the document would - // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum - // scroll range would be 900. Therefore this calculation depends on the zoom applied - // to the content relative to the container. - // Note that this needs to happen before scrolling the frame (in UpdateFrameCommon), - // otherwise the scroll position may get clamped incorrectly. - CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); - nsLayoutUtils::SetScrollPositionClampingScrollPortSize(shell, scrollPort); - - // The pres shell resolution is updated by the the async zoom since the - // last paint. - presShellResolution = aMetrics.GetPresShellResolution() - * aMetrics.GetAsyncZoom().scale; - nsLayoutUtils::SetResolutionAndScaleTo(shell, presShellResolution); - // Do this as late as possible since scrolling can flush layout. It also // adjusts the display port margins, so do it before we set those. ScrollFrame(content, aMetrics); @@ -718,6 +729,16 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget, if (!aWidget || !aDocument) { return; } + if (aInputBlockId == sLastTargetAPZCNotificationInputBlock) { + // We have already confirmed the target APZC for a previous event of this + // input block. If we activated a scroll frame for this input block, + // sending another target APZC confirmation would be harmful, as it might + // race the original confirmation (which needs to go through a layers + // transaction). + APZCCH_LOG("Not resending target APZC confirmation for input block %" PRIu64 "\n", aInputBlockId); + return; + } + sLastTargetAPZCNotificationInputBlock = aInputBlockId; if (nsIPresShell* shell = aDocument->GetShell()) { if (nsIFrame* rootFrame = shell->GetRootFrame()) { bool waitForRefresh = false; diff --git a/gfx/layers/apz/util/APZCCallbackHelper.h b/gfx/layers/apz/util/APZCCallbackHelper.h index d3fcf91c6d..6e476530b1 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.h +++ b/gfx/layers/apz/util/APZCCallbackHelper.h @@ -166,6 +166,9 @@ public: /* Notify content that the repaint flush is complete. */ static void NotifyFlushComplete(); + +private: + static uint64_t sLastTargetAPZCNotificationInputBlock; }; } // namespace layers diff --git a/gfx/layers/apz/util/APZEventState.cpp b/gfx/layers/apz/util/APZEventState.cpp index b84ae622d7..cbed59c695 100644 --- a/gfx/layers/apz/util/APZEventState.cpp +++ b/gfx/layers/apz/util/APZEventState.cpp @@ -319,7 +319,11 @@ APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent, const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId) { - mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, aEvent.mFlags.mDefaultPrevented); + // If this event starts a swipe, indicate that it shouldn't result in a + // scroll by setting defaultPrevented to true. + bool defaultPrevented = + aEvent.mFlags.mDefaultPrevented || aEvent.TriggersSwipe(); + mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, defaultPrevented); } void diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 7c0dccae03..4056c9b32c 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -813,17 +813,17 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar, // fraction of the whole srollable rect that is in view. const float yScale = 1.f / asyncZoomY; - // Note: |metrics.GetZoom()| doesn't yet include the async zoom, so - // |metrics.CalculateCompositedSizeInCssPixels()| would not give a correct - // result. + // Note: |metrics.GetZoom()| doesn't yet include the async zoom. const CSSToParentLayerScale effectiveZoom(metrics.GetZoom().yScale * asyncZoomY); - const LayoutDeviceToParentLayerScale nonLayoutScale = effectiveZoom / - metrics.GetDevPixelsPerCSSPixel(); // Here we convert the scrollbar thumb ratio into a true unitless ratio by // dividing out the conversion factor from the scrollframe's parent's space // to the scrollframe's space. - const float ratio = aScrollbar->GetScrollbarThumbRatio() / nonLayoutScale.scale; + const float ratio = aScrollbar->GetScrollbarThumbRatio() / + (metrics.GetPresShellResolution() * asyncZoomY); + // The scroll thumb needs to be translated in opposite direction of the + // async scroll. This is because scrolling down, which translates the layer + // content up, should result in moving the scroll thumb down. ParentLayerCoord yTranslation = -asyncScrollY * ratio; // The scroll thumb additionally needs to be translated to compensate for @@ -843,14 +843,13 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar, const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom; yTranslation -= thumbOriginDeltaPL; - if (aScrollbarIsDescendant) { - // In cases where the scrollbar is a descendant of the content, the - // scrollbar gets painted at the same resolution as the content. Since the - // coordinate space we apply this transform in includes the resolution, we - // need to adjust for it as well here. Note that in another - // aScrollbarIsDescendant hunk below we apply a resolution-cancelling - // transform which ensures the scroll thumb isn't actually rendered - // at a larger scale. + if (metrics.IsRootContent()) { + // Scrollbar for the root are painted at the same resolution as the + // content. Since the coordinate space we apply this transform in includes + // the resolution, we need to adjust for it as well here. Note that in + // another metrics.IsRootContent() hunk below we apply a + // resolution-cancelling transform which ensures the scroll thumb isn't + // actually rendered at a larger scale. yTranslation *= metrics.GetPresShellResolution(); } @@ -867,9 +866,8 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar, const CSSToParentLayerScale effectiveZoom(metrics.GetZoom().xScale * asyncZoomX); - const LayoutDeviceToParentLayerScale nonLayoutScale = effectiveZoom / - metrics.GetDevPixelsPerCSSPixel(); - const float ratio = aScrollbar->GetScrollbarThumbRatio() / nonLayoutScale.scale; + const float ratio = aScrollbar->GetScrollbarThumbRatio() / + (metrics.GetPresShellResolution() * asyncZoomX); ParentLayerCoord xTranslation = -asyncScrollX * ratio; const CSSCoord thumbOrigin = (metrics.GetScrollOffset().x * ratio); @@ -878,7 +876,7 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar, const ParentLayerCoord thumbOriginDeltaPL = thumbOriginDelta * effectiveZoom; xTranslation -= thumbOriginDeltaPL; - if (aScrollbarIsDescendant) { + if (metrics.IsRootContent()) { xTranslation *= metrics.GetPresShellResolution(); } @@ -888,39 +886,38 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar, Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform(); - if (aScrollbarIsDescendant) { - // If the scrollbar layer is a child of the content it is a scrollbar for, - // then we need to make a couple of adjustments to the scrollbar's transform. - // - // - First, the content's resolution applies to the scrollbar as well. - // Since we don't actually want the scroll thumb's size to vary with - // the zoom (other than its length reflecting the fraction of the - // scrollable length that's in view, which is taken care of above), - // we apply a transform to cancel out this resolution. - // - // - Second, if there is any async transform (including an overscroll - // transform) on the content, this needs to be cancelled out because - // layout positions and sizes the scrollbar on the assumption that there - // is no async transform, and without this adjustment the scrollbar will - // end up in the wrong place. - // - // Note that since the async transform is applied on top of the content's - // regular transform, we need to make sure to unapply the async transform - // in the same coordinate space. This requires applying the content - // transform and then unapplying it after unapplying the async transform. - Matrix4x4 resolutionCancellingTransform = + Matrix4x4 compensation; + // If the scrollbar layer is for the root then the content's resolution + // applies to the scrollbar as well. Since we don't actually want the scroll + // thumb's size to vary with the zoom (other than its length reflecting the + // fraction of the scrollable length that's in view, which is taken care of + // above), we apply a transform to cancel out this resolution. + if (metrics.IsRootContent()) { + compensation = Matrix4x4::Scaling(metrics.GetPresShellResolution(), metrics.GetPresShellResolution(), 1.0f).Inverse(); + } + // If the scrollbar layer is a child of the content it is a scrollbar for, + // then we need to adjust for any async transform (including an overscroll + // transform) on the content. This needs to be cancelled out because layout + // positions and sizes the scrollbar on the assumption that there is no async + // transform, and without this adjustment the scrollbar will end up in the + // wrong place. + // + // Note that since the async transform is applied on top of the content's + // regular transform, we need to make sure to unapply the async transform in + // the same coordinate space. This requires applying the content transform + // and then unapplying it after unapplying the async transform. + if (aScrollbarIsDescendant) { Matrix4x4 asyncUntransform = (asyncTransform * apzc->GetOverscrollTransform()).Inverse(); Matrix4x4 contentTransform = aContent.GetTransform(); Matrix4x4 contentUntransform = contentTransform.Inverse(); - Matrix4x4 compensation = resolutionCancellingTransform - * contentTransform - * asyncUntransform - * contentUntransform; - transform = transform * compensation; + compensation = compensation + * contentTransform + * asyncUntransform + * contentUntransform; // We also need to make a corresponding change on the clip rect of all the // layers on the ancestor chain from the scrollbar layer up to but not @@ -930,6 +927,7 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar, TransformClipRect(ancestor, compensation); } } + transform = transform * compensation; SetShadowTransform(aScrollbar, transform); } @@ -940,8 +938,17 @@ FindScrolledLayerRecursive(Layer* aScrollbar, const LayerMetricsWrapper& aSubtre if (LayerIsScrollbarTarget(aSubtreeRoot, aScrollbar)) { return aSubtreeRoot; } - for (LayerMetricsWrapper child = aSubtreeRoot.GetFirstChild(); child; - child = child.GetNextSibling()) { + + for (LayerMetricsWrapper child = aSubtreeRoot.GetFirstChild(); + child; + child = child.GetNextSibling()) + { + // Do not recurse into RefLayers, since our initial aSubtreeRoot is the + // root (or RefLayer root) of a single layer space to search. + if (child.AsRefLayer()) { + continue; + } + LayerMetricsWrapper target = FindScrolledLayerRecursive(aScrollbar, child); if (target) { return target; @@ -953,22 +960,25 @@ FindScrolledLayerRecursive(Layer* aScrollbar, const LayerMetricsWrapper& aSubtre static LayerMetricsWrapper FindScrolledLayerForScrollbar(Layer* aScrollbar, bool* aOutIsAncestor) { - // Search ancestors first. - LayerMetricsWrapper scrollbar(aScrollbar); - for (LayerMetricsWrapper ancestor = scrollbar; ancestor; ancestor = ancestor.GetParent()) { + // First check if the scrolled layer is an ancestor of the scrollbar layer. + LayerMetricsWrapper root(aScrollbar->Manager()->GetRoot()); + LayerMetricsWrapper prevAncestor(aScrollbar); + for (LayerMetricsWrapper ancestor(aScrollbar); ancestor; ancestor = ancestor.GetParent()) { + // Don't walk into remote layer trees; the scrollbar will always be in + // the same layer space. + if (ancestor.AsRefLayer()) { + root = prevAncestor; + break; + } + prevAncestor = ancestor; + if (LayerIsScrollbarTarget(ancestor, aScrollbar)) { *aOutIsAncestor = true; return ancestor; } } - // If the scrolled target is not an ancestor, search the whole layer tree. - // XXX It would be much better to search the APZC tree instead of the layer - // tree. That way we would ignore non-scrollable layers, and we'd only visit - // each scroll ID once. In the end we only need the APZC and the FrameMetrics - // of the scrolled target. - *aOutIsAncestor = false; - LayerMetricsWrapper root(aScrollbar->Manager()->GetRoot()); + // Search the entire layer space of the scrollbar. return FindScrolledLayerRecursive(aScrollbar, root); } diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 5c391bd7ca..df4bcb793c 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -135,6 +135,7 @@ private: // The apz prefs are explained in AsyncPanZoomController.cpp DECL_GFX_PREF(Live, "apz.allow_checkerboarding", APZAllowCheckerboarding, bool, true); + DECL_GFX_PREF(Live, "apz.allow_zooming", APZAllowZooming, bool, false); DECL_GFX_PREF(Live, "apz.asyncscroll.throttle", APZAsyncScrollThrottleTime, int32_t, 100); DECL_GFX_PREF(Live, "apz.asyncscroll.timeout", APZAsyncScrollTimeout, int32_t, 300); DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle", APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */); diff --git a/js/src/asmjs/AsmJSModule.h b/js/src/asmjs/AsmJSModule.h index 3f291efbe6..81878d7766 100644 --- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -99,7 +99,7 @@ enum AsmJSSimdOperation // These labels describe positions in the prologue/epilogue of functions while // compiling an AsmJSModule. -struct AsmJSFunctionLabels +struct MOZ_STACK_CLASS AsmJSFunctionLabels { AsmJSFunctionLabels(jit::Label& entry, jit::Label& overflowExit) : entry(entry), overflowExit(overflowExit) {} @@ -542,7 +542,10 @@ class AsmJSModule class CodeRange { + protected: uint32_t nameIndex_; + + private: uint32_t lineNumber_; uint32_t begin_; uint32_t profilingReturn_; @@ -627,6 +630,24 @@ class AsmJSModule } }; + class FunctionCodeRange : public CodeRange + { + private: + PropertyName* name_; + + public: + FunctionCodeRange(PropertyName* name, uint32_t lineNumber, const AsmJSFunctionLabels& l) + : CodeRange(UINT32_MAX, lineNumber, l), name_(name) + {} + + PropertyName* name() const { return name_; } + + void initNameIndex(uint32_t nameIndex) { + MOZ_ASSERT(nameIndex_ == UINT32_MAX); + nameIndex_ = nameIndex; + } + }; + class FuncPtrTable { uint32_t globalDataOffset_; @@ -1137,15 +1158,14 @@ class AsmJSModule bool addCodeRange(CodeRange::Kind kind, uint32_t begin, uint32_t pret, uint32_t end) { return codeRanges_.append(CodeRange(kind, begin, pret, end)); } - bool addFunctionCodeRange(PropertyName* name, uint32_t lineNumber, - const AsmJSFunctionLabels& labels) + bool addFunctionCodeRange(PropertyName* name, FunctionCodeRange&& codeRange) { MOZ_ASSERT(!isFinished()); MOZ_ASSERT(name->isTenured()); if (names_.length() >= UINT32_MAX) return false; - uint32_t nameIndex = names_.length(); - return names_.append(name) && codeRanges_.append(CodeRange(nameIndex, lineNumber, labels)); + codeRange.initNameIndex(names_.length()); + return names_.append(name) && codeRanges_.append(Move(codeRange)); } bool addBuiltinThunkCodeRange(AsmJSExit::BuiltinKind builtin, uint32_t begin, uint32_t profilingReturn, uint32_t end) @@ -1191,12 +1211,10 @@ class AsmJSModule return functionCounts_.append(counts); } #if defined(MOZ_VTUNE) || defined(JS_ION_PERF) - bool addProfiledFunction(PropertyName* name, unsigned codeStart, unsigned codeEnd, - unsigned line, unsigned column) + bool addProfiledFunction(ProfiledFunction&& func) { MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies()); - ProfiledFunction func(name, codeStart, codeEnd, line, column); - return profiledFunctions_.append(func); + return profiledFunctions_.append(mozilla::Move(func)); } unsigned numProfiledFunctions() const { MOZ_ASSERT(isFinishedWithModulePrologue()); @@ -1208,11 +1226,9 @@ class AsmJSModule } #endif #ifdef JS_ION_PERF - bool addProfiledBlocks(PropertyName* name, unsigned codeBegin, unsigned inlineEnd, - unsigned codeEnd, jit::BasicBlocksVector& basicBlocks) + bool addProfiledBlocks(ProfiledBlocksFunction&& func) { MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies()); - ProfiledBlocksFunction func(name, codeBegin, inlineEnd, codeEnd, basicBlocks); return perfProfiledBlocksFunctions_.append(mozilla::Move(func)); } unsigned numPerfBlocksFunctions() const { diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 9272c6285d..1ed230d2f6 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -29,7 +29,6 @@ #include "jsprf.h" #include "jsutil.h" - #include "asmjs/AsmJSLink.h" #include "asmjs/AsmJSModule.h" #include "asmjs/AsmJSSignalHandlers.h" @@ -968,7 +967,7 @@ class ABIArgIter typedef Vector MIRTypeVector; typedef ABIArgIter ABIArgMIRTypeIter; -typedef Vector > VarTypeVector; +typedef Vector> VarTypeVector; typedef ABIArgIter ABIArgTypeIter; class Signature @@ -1003,6 +1002,27 @@ class Signature RetType retType() const { return retType_; } }; +// Signature that can be only allocated with a LifoAlloc. +class LifoSignature : public Signature +{ + explicit LifoSignature(Signature&& rhs) + : Signature(Move(rhs)) + {} + + LifoSignature(const LifoSignature&) = delete; + LifoSignature(const LifoSignature&&) = delete; + LifoSignature& operator=(const LifoSignature&) = delete; + LifoSignature& operator=(const LifoSignature&&) = delete; + + public: + static LifoSignature* new_(LifoAlloc& lifo, Signature&& sig) { + void* mem = lifo.alloc(sizeof(LifoSignature)); + if (!mem) + return nullptr; + return new (mem) LifoSignature(Move(sig)); + } +}; + } // namespace @@ -1056,73 +1076,329 @@ enum NeedsBoundsCheck { namespace { -// ModuleCompiler encapsulates the compilation of an entire asm.js module. Over -// the course of an ModuleCompiler object's lifetime, many FunctionCompiler -// objects will be created and destroyed in sequence, one for each function in -// the module. +class AsmFunction +{ + public: + typedef Vector> VarInitializerVector; + + private: + typedef Vector> Bytecode; + + VarInitializerVector varInitializers_; + Bytecode bytecode_; + + VarTypeVector argTypes_; + RetType returnedType_; + + PropertyName* name_; + + unsigned funcIndex_; + unsigned srcBegin_; + unsigned compileTime_; + + + public: + + explicit AsmFunction(LifoAlloc& alloc) + : varInitializers_(alloc), + bytecode_(alloc), + argTypes_(alloc), + returnedType_(RetType::Which(-1)), + name_(nullptr), + funcIndex_(-1), + srcBegin_(-1), + compileTime_(-1) + {} + + bool init(const VarTypeVector& args) { + if (!argTypes_.initCapacity(args.length())) + return false; + for (size_t i = 0; i < args.length(); i++) + argTypes_.append(args[i]); + return true; + } + + bool finish(const VarTypeVector& args, PropertyName* name, unsigned funcIndex, + unsigned srcBegin, unsigned compileTime) + { + if (!argTypes_.initCapacity(args.length())) + return false; + for (size_t i = 0; i < args.length(); i++) + argTypes_.infallibleAppend(args[i]); + + MOZ_ASSERT(name_ == nullptr); + name_ = name; + + MOZ_ASSERT(funcIndex_ == unsigned(-1)); + funcIndex_ = funcIndex; + + MOZ_ASSERT(srcBegin_ == unsigned(-1)); + srcBegin_ = srcBegin; + + MOZ_ASSERT(compileTime_ == unsigned(-1)); + compileTime_ = compileTime; + return true; + } + + private: + AsmFunction(const AsmFunction&) = delete; + AsmFunction(AsmFunction&& other) = delete; + AsmFunction& operator=(const AsmFunction&) = delete; + + // Helper functions + template size_t writePrimitive(T v) { + size_t writeAt = bytecode_.length(); + if (!bytecode_.append(reinterpret_cast(&v), sizeof(T))) + return -1; + return writeAt; + } + + template T readPrimitive(size_t* pc) const { + MOZ_ASSERT(*pc + sizeof(T) <= bytecode_.length()); + T ret; + memcpy(&ret, &bytecode_[*pc], sizeof(T)); + *pc += sizeof(T); + return ret; + } + + public: + size_t writeU8(uint8_t i) { return writePrimitive(i); } + size_t writeI32(int32_t i) { return writePrimitive(i); } + size_t writeU32(uint32_t i) { return writePrimitive(i); } + size_t writeF32(float f) { return writePrimitive(f); } + size_t writeF64(double d) { return writePrimitive(d); } + + size_t writeI32X4(const int32_t* i4) { + size_t pos = bytecode_.length(); + for (size_t i = 0; i < 4; i++) + writePrimitive(i4[i]); + return pos; + } + size_t writeF32X4(const float* f4) { + size_t pos = bytecode_.length(); + for (size_t i = 0; i < 4; i++) + writePrimitive(f4[i]); + return pos; + } + + uint8_t readU8 (size_t* pc) const { return readPrimitive(pc); } + int32_t readI32(size_t* pc) const { return readPrimitive(pc); } + float readF32(size_t* pc) const { return readPrimitive(pc); } + uint32_t readU32(size_t* pc) const { return readPrimitive(pc); } + double readF64(size_t* pc) const { return readPrimitive(pc); } + LifoSignature* readSignature(size_t* pc) const { return readPrimitive(pc); } + + SimdConstant readI32X4(size_t* pc) const { + int32_t x = readI32(pc); + int32_t y = readI32(pc); + int32_t z = readI32(pc); + int32_t w = readI32(pc); + return SimdConstant::CreateX4(x, y, z, w); + } + SimdConstant readF32X4(size_t* pc) const { + float x = readF32(pc); + float y = readF32(pc); + float z = readF32(pc); + float w = readF32(pc); + return SimdConstant::CreateX4(x, y, z, w); + } + +#ifdef DEBUG + inline bool pcIsPatchable(size_t pc, unsigned size) const; +#endif // DEBUG + + void patchU8(size_t pc, uint8_t i) { + MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint8_t))); + bytecode_[pc] = i; + } + + template + void patch32(size_t pc, T i) { + static_assert(sizeof(T) == sizeof(uint32_t), + "patch32 must be used with 32-bits wide types"); + MOZ_ASSERT(pcIsPatchable(pc, sizeof(uint32_t))); + memcpy(&bytecode_[pc], &i, sizeof(uint32_t)); + } + + void patchSignature(size_t pc, const LifoSignature* ptr) { + MOZ_ASSERT(pcIsPatchable(pc, sizeof(LifoSignature*))); + memcpy(&bytecode_[pc], &ptr, sizeof(LifoSignature*)); + } + + // Setters + void accumulateCompileTime(unsigned ms) { + compileTime_ += ms; + } + bool addVariable(const AsmJSNumLit& init) { + return varInitializers_.append(init); + } + void setReturnedType(RetType retType) { + MOZ_ASSERT(returnedType_ == RetType::Which(-1)); + returnedType_ = retType; + } + + // Read-only interface + PropertyName* name() const { return name_; } + unsigned funcIndex() const { return funcIndex_; } + unsigned srcBegin() const { return srcBegin_; } + unsigned compileTime() const { return compileTime_; } + + size_t size() const { return bytecode_.length(); } + + const VarTypeVector& argTypes() const { return argTypes_; } + + const VarInitializerVector& varInitializers() const { return varInitializers_; } + size_t numLocals() const { return argTypes_.length() + varInitializers_.length(); } + RetType returnedType() const { + MOZ_ASSERT(returnedType_ != RetType::Which(-1)); + return returnedType_; + } +}; + +struct ModuleCompileInputs +{ + bool usesSignalHandlersForInterrupt; + bool usesSignalHandlersForOOB; + + ModuleCompileInputs(bool usesSignalHandlersForInterrupt, bool usesSignalHandlersForOOB) + : usesSignalHandlersForInterrupt(usesSignalHandlersForInterrupt), + usesSignalHandlersForOOB(usesSignalHandlersForOOB) + {} +}; + +class ModuleCompileResults +{ + public: + struct SlowFunction + { + SlowFunction(PropertyName* name, unsigned ms, unsigned line, unsigned column) + : name(name), ms(ms), line(line), column(column) + {} + + PropertyName* name; + unsigned ms; + unsigned line; + unsigned column; + }; + + typedef Vector SlowFunctionVector; + typedef Vector LabelVector; + + private: + LifoAlloc lifo_; + MacroAssembler masm_; + + SlowFunctionVector slowFunctions_; + LabelVector functionEntries_; + Vector codeRanges_; + Vector functionCounts_; +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) + Vector profiledFunctions_; +#endif // defined(MOZ_VTUNE) || defined(JS_ION_PERF) +#if defined(JS_ION_PERF) + Vector perfProfiledBlocksFunctions_; +#endif + + NonAssertingLabel stackOverflowLabel_; + NonAssertingLabel asyncInterruptLabel_; + NonAssertingLabel syncInterruptLabel_; + NonAssertingLabel onDetachedLabel_; + NonAssertingLabel onConversionErrorLabel_; + NonAssertingLabel onOutOfBoundsLabel_; + int64_t usecBefore_; + + public: + explicit ModuleCompileResults(ExclusiveContext* cx) + : lifo_(LIFO_ALLOC_PRIMARY_CHUNK_SIZE), + masm_(MacroAssembler::AsmJSToken()), + slowFunctions_(cx), + functionEntries_(cx), + codeRanges_(cx), + functionCounts_(cx), +#if defined(MOZ_VTUNE) || defined(JS_ION_PERF) + profiledFunctions_(cx), +#endif // defined(MOZ_VTUNE) || defined(JS_ION_PERF) +#if defined(JS_ION_PERF) + perfProfiledBlocksFunctions_(cx), +#endif // defined(JS_ION_PERF) + usecBefore_(PRMJ_Now()) + {} + + MacroAssembler& masm() { return masm_; } + Label& stackOverflowLabel() { return stackOverflowLabel_; } + Label& asyncInterruptLabel() { return asyncInterruptLabel_; } + Label& syncInterruptLabel() { return syncInterruptLabel_; } + Label& onOutOfBoundsLabel() { return onOutOfBoundsLabel_; } + Label& onDetachedLabel() { return onDetachedLabel_; } + Label& onConversionErrorLabel() { return onConversionErrorLabel_; } + int64_t usecBefore() { return usecBefore_; } + + SlowFunctionVector& slowFunctions() { return slowFunctions_; } + + size_t numFunctionEntries() const { return functionEntries_.length(); } + Label* functionEntry(unsigned i) { return functionEntries_[i]; } + + bool getOrCreateFunctionEntry(unsigned i, Label** label) { + if (i == UINT32_MAX) + return false; + while (functionEntries_.length() <= i) { + Label* newEntry = lifo_.new_