mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:23:07 +00:00
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)
This commit is contained in:
+8
-1
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<nsIWidget> 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<nsITabChild> tabChild = do_GetInterface(docShell);
|
||||
if (tabChild) {
|
||||
static_cast<TabChild*>(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<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
// set focus to the top level window but don't raise it.
|
||||
widget->SetFocus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+13
-441
@@ -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<ScreenPixel>(aScale, PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
}
|
||||
CSSToParentLayerScale ConvertScaleForRoot(CSSToScreenScale aScale)
|
||||
{
|
||||
return ViewTargetAs<ParentLayerPixel>(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<ParentLayerPixel>(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<nsIPresShell> 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<nsIPresShell> shell = GetPresShell()) {
|
||||
nsLayoutUtils::SetCSSViewport(shell, aSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CSSSize
|
||||
TabChildBase::GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport)
|
||||
{
|
||||
nsCOMPtr<Element> 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<nsIDocument> 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<nsIPresShell> 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<ParentLayerPixel>(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<nsIDOMWindowUtils>
|
||||
TabChildBase::GetDOMWindowUtils()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
||||
return utils.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument>
|
||||
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<nsIDOMWindow> window;
|
||||
aWebProgress->GetDOMWindow(getter_AddRefs(window));
|
||||
if (!window) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> progressDoc;
|
||||
window->GetDocument(getter_AddRefs(progressDoc));
|
||||
if (!progressDoc) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
WebNavigation()->GetDocument(getter_AddRefs(domDoc));
|
||||
if (!domDoc || !SameCOMIdentity(domDoc, progressDoc)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID));
|
||||
if (!urifixup) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> 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<nsIWebProgress> 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<nsIBaseWindow> 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<nsPIWindowRoot> 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) {
|
||||
|
||||
+1
-24
@@ -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<mozilla::layers::ZoomConstraints>& aConstraints) = 0;
|
||||
@@ -197,19 +190,12 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ~TabChildBase();
|
||||
CSSSize GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport);
|
||||
|
||||
// Get the DOMWindowUtils for the top-level window in this tab.
|
||||
already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils();
|
||||
// Get the Document for the top-level window in this tab.
|
||||
already_AddRefed<nsIDocument> GetDocument() const;
|
||||
// Get the pres-shell of the document for the top-level window in this tab.
|
||||
already_AddRefed<nsIPresShell> 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<TabChildGlobal> mTabChildGlobal;
|
||||
mozilla::layers::FrameMetrics mLastRootMetrics;
|
||||
nsCOMPtr<nsIWebBrowserChrome3> 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
|
||||
|
||||
+43
-7
@@ -2521,10 +2521,9 @@ TabParent::RecvGetMaxTouchPoints(uint32_t* aTouchPoints)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
already_AddRefed<nsIWidget>
|
||||
TabParent::GetTopLevelWidget()
|
||||
{
|
||||
*aValue = 0;
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
|
||||
if (content) {
|
||||
nsIPresShell* shell = content->OwnerDoc()->GetShell();
|
||||
@@ -2532,12 +2531,49 @@ TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
nsViewManager* vm = shell->GetViewManager();
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
*aValue = reinterpret_cast<WindowsHandle>(
|
||||
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
|
||||
}
|
||||
return widget.forget();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
{
|
||||
*aValue = 0;
|
||||
nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
|
||||
if (widget) {
|
||||
*aValue = reinterpret_cast<WindowsHandle>(
|
||||
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvSetNativeChildOfShareableWindow(const uintptr_t& aChildWindow)
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
nsCOMPtr<nsIWidget> 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<nsIWidget> widget = GetTopLevelWidget();
|
||||
if (widget) {
|
||||
widget->SetFocus(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -116,7 +116,7 @@ public:
|
||||
}
|
||||
|
||||
already_AddRefed<nsILoadContext> GetLoadContext();
|
||||
|
||||
already_AddRefed<nsIWidget> 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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<nsIWidget>
|
||||
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<nsIWidget> 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<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
nsCOMPtr<nsIWidget> 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<uintptr_t>(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<uintptr_t>(aWindowToAdopt));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise ask the topmost document window to adopt.
|
||||
nsCOMPtr<nsIWidget> 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<uintptr_t>(aWindowToAdopt));
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(int32_t eventModel)
|
||||
{
|
||||
#ifdef XP_MACOSX
|
||||
|
||||
@@ -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<nsNPAPIPluginInstance> mInstance;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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<char**>(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<double*>(aValue) = scaleFactor;
|
||||
*static_cast<double*>(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=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
|
||||
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<HWND>(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<HWND>(aWindow.window);
|
||||
if (mPluginParentHWND != parentWindow && IsWindow(parentWindow)) {
|
||||
mPluginParentHWND = parentWindow;
|
||||
aChildWindowToBeAdopted->window =
|
||||
reinterpret_cast<uint64_t>(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<gfxASurface> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <gdk/gdk.h>
|
||||
@@ -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<HWND>(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<uint64_t>(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<uint64_t>(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<nsIWidget> widget;
|
||||
static_cast<const nsPluginNativeWindow*>(aWindow)->
|
||||
GetPluginWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
widget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
|
||||
static_cast<uintptr_t>(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<HWND>(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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<nsCString>& 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;
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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<void*>(aChildWindow));
|
||||
(void*)aChildWindow);
|
||||
mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, aChildWindow);
|
||||
return true;
|
||||
#else
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -120,11 +120,6 @@ public:
|
||||
return (def == *this);
|
||||
}
|
||||
|
||||
bool IsRootScrollable() const
|
||||
{
|
||||
return mIsRootContent;
|
||||
}
|
||||
|
||||
bool IsScrollable() const
|
||||
{
|
||||
return mScrollId != NULL_SCROLL_ID;
|
||||
|
||||
@@ -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<ScreenPixel>(
|
||||
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<ScreenPixel>(
|
||||
transformToGecko, panInput.mPanStartPoint);
|
||||
panInput.mPanDisplacement = TransformVector<ScreenPixel>(
|
||||
@@ -655,6 +658,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
Matrix4x4 outTransform = GetScreenToApzcTransform(apzc)
|
||||
* GetApzcToGeckoTransform(apzc);
|
||||
MOZ_ASSERT(outTransform.Is2D());
|
||||
pinchInput.mFocusPoint = TransformTo<ScreenPixel>(
|
||||
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<ScreenPixel>(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<ScreenPixel>(
|
||||
@@ -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<LayoutDevicePixel>(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<LayoutDevicePixel>(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<ScreenPixel>(untransformToApzc, aStartPoint);
|
||||
ScreenPoint screenEnd = TransformTo<ScreenPixel>(untransformToApzc, aEndPoint);
|
||||
|
||||
|
||||
// Convert start and end points to aTarget's ParentLayer coordinates.
|
||||
Matrix4x4 transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget);
|
||||
aStartPoint = TransformTo<ParentLayerPixel>(transformToApzc, screenStart);
|
||||
aEndPoint = TransformTo<ParentLayerPixel>(transformToApzc, screenEnd);
|
||||
Maybe<ParentLayerPoint> startPoint = UntransformTo<ParentLayerPixel>(transformToApzc, screenStart);
|
||||
Maybe<ParentLayerPoint> endPoint = UntransformTo<ParentLayerPixel>(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 <typename Node, typename Condition>
|
||||
static const Node* BreadthFirstSearch(const Node* aRoot, const Condition& aCondition)
|
||||
{
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
|
||||
if (!mRootNode) {
|
||||
if (!aRoot) {
|
||||
return nullptr;
|
||||
}
|
||||
std::deque<const HitTestingTreeNode*> queue;
|
||||
queue.push_back(mRootNode);
|
||||
std::deque<const Node*> 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<AsyncPanZoomController>
|
||||
APZCTreeManager::GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> 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<AsyncPanZoomController> 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<AsyncPanZoomController>
|
||||
APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
mTreeLock.AssertCurrentThreadOwns();
|
||||
nsRefPtr<AsyncPanZoomController> 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<AsyncPanZoomController>
|
||||
APZCTreeManager::RootAPZCForLayersId(AsyncPanZoomController* aApzc) const
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
nsRefPtr<AsyncPanZoomController> apzc = aApzc;
|
||||
while (apzc && !apzc->HasNoParentWithSameLayersId()) {
|
||||
apzc = apzc->GetParent();
|
||||
}
|
||||
return apzc.forget();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -425,9 +425,9 @@ private:
|
||||
const ParentLayerPoint& aHitTestPoint,
|
||||
HitTestResult* aOutHitResult);
|
||||
AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId) const;
|
||||
AsyncPanZoomController* FindRootContentApzcForLayersId(uint64_t aLayersId) const;
|
||||
already_AddRefed<AsyncPanZoomController> GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
|
||||
already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
|
||||
already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc) const;
|
||||
already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
|
||||
HitTestResult* aOutHitResult);
|
||||
nsEventStatus ProcessTouchInput(MultiTouchInput& aInput,
|
||||
|
||||
@@ -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<GestureEventListener> 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<LayoutDevicePixel>(transformToGecko, aPoint);
|
||||
MOZ_ASSERT(transformScreenToGecko.Is2D());
|
||||
LayoutDevicePoint layoutPoint = TransformTo<LayoutDevicePixel>(
|
||||
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<InputBlockState>(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<GeckoContentController> 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<GeckoContentController> 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<ScreenPixel>(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<ParentLayerPixel>(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<ParentLayerPixel>(transformToThis, aPoint);
|
||||
Maybe<ParentLayerIntPoint> point = UntransformTo<ParentLayerPixel>(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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<LayerPixel>(point.As2DPoint()))
|
||||
: Nothing();
|
||||
return UntransformTo<LayerPixel>(localTransform.Inverse(), aPoint);
|
||||
}
|
||||
|
||||
HitTestResult
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -166,6 +166,9 @@ public:
|
||||
|
||||
/* Notify content that the repaint flush is complete. */
|
||||
static void NotifyFlushComplete();
|
||||
|
||||
private:
|
||||
static uint64_t sLastTargetAPZCNotificationInputBlock;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */);
|
||||
|
||||
+28
-12
@@ -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 {
|
||||
|
||||
+1361
-1058
File diff suppressed because it is too large
Load Diff
@@ -1922,7 +1922,7 @@ TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, Handl
|
||||
uint32_t index;
|
||||
if (IdIsIndex(id, &index)) {
|
||||
if (!receiver.isObject() || obj != &receiver.toObject())
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
|
||||
if (index >= uint32_t(typedObj->length())) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage,
|
||||
@@ -1948,7 +1948,7 @@ TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, Handl
|
||||
break;
|
||||
|
||||
if (!receiver.isObject() || obj != &receiver.toObject())
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
|
||||
size_t offset = descr->fieldOffset(fieldIndex);
|
||||
Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
|
||||
|
||||
@@ -291,7 +291,8 @@ function isRootedGCPointerTypeName(name)
|
||||
name == "WrappableJSErrorResult" ||
|
||||
name == "frontend::TokenStream" ||
|
||||
name == "frontend::TokenStream::Position" ||
|
||||
name == "ModuleCompiler")
|
||||
name == "ModuleCompiler" ||
|
||||
name == "ModuleValidator")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ struct AsmJSParallelTask
|
||||
{
|
||||
JSRuntime* runtime; // Associated runtime.
|
||||
LifoAlloc lifo; // Provider of all heap memory used for compilation.
|
||||
void* func; // Really, a ModuleCompiler::Func*
|
||||
void* func; // Really, an AsmFunction*
|
||||
jit::MIRGenerator* mir; // Passed from main thread to helper.
|
||||
jit::LIRGraph* lir; // Passed from helper to main thread.
|
||||
unsigned compileTime;
|
||||
|
||||
+10
-10
@@ -2057,8 +2057,8 @@ NativeSetExistingDataProperty(JSContext* cx, HandleNativeObject obj, HandleShape
|
||||
* is really old code and there are a few barnacles.
|
||||
*/
|
||||
bool
|
||||
js::SetPropertyByDefining(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
||||
HandleValue receiverValue, ObjectOpResult& result)
|
||||
js::SetPropertyByDefining(JSContext* cx, HandleId id, HandleValue v, HandleValue receiverValue,
|
||||
ObjectOpResult& result)
|
||||
{
|
||||
// Step 5.b.
|
||||
if (!receiverValue.isObject())
|
||||
@@ -2141,7 +2141,7 @@ js::SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue
|
||||
RootedObject proto(cx, obj->getProto());
|
||||
if (proto)
|
||||
return SetProperty(cx, proto, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2152,8 +2152,8 @@ js::SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue
|
||||
* steps 4.d.i and 5.
|
||||
*/
|
||||
static bool
|
||||
SetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
|
||||
HandleValue receiver, QualifiedBool qualified, ObjectOpResult& result)
|
||||
SetNonexistentProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
|
||||
QualifiedBool qualified, ObjectOpResult& result)
|
||||
{
|
||||
// We should never add properties to lexical blocks.
|
||||
MOZ_ASSERT_IF(receiver.isObject(), !receiver.toObject().is<BlockObject>());
|
||||
@@ -2163,7 +2163,7 @@ SetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handl
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2224,7 +2224,7 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
|
||||
return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), v, result);
|
||||
|
||||
// Steps 5.b-f.
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
}
|
||||
|
||||
// Step 5 for all other properties.
|
||||
@@ -2262,7 +2262,7 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
|
||||
|
||||
// Shadow pobj[id] by defining a new data property receiver[id].
|
||||
// Delegate everything to SetPropertyByDefining.
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
}
|
||||
|
||||
// Steps 6-11.
|
||||
@@ -2319,7 +2319,7 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle
|
||||
RootedObject proto(cx, done ? nullptr : pobj->getProto());
|
||||
if (!proto) {
|
||||
// Step 4.d.i (and step 5).
|
||||
return SetNonexistentProperty(cx, obj, id, v, receiver, qualified, result);
|
||||
return SetNonexistentProperty(cx, id, v, receiver, qualified, result);
|
||||
}
|
||||
|
||||
// Step 4.c.i. If the prototype is also native, this step is a
|
||||
@@ -2336,7 +2336,7 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle
|
||||
if (!HasProperty(cx, proto, id, &found))
|
||||
return false;
|
||||
if (!found)
|
||||
return SetNonexistentProperty(cx, obj, id, v, receiver, qualified, result);
|
||||
return SetNonexistentProperty(cx, id, v, receiver, qualified, result);
|
||||
}
|
||||
|
||||
return SetProperty(cx, proto, id, v, receiver, result);
|
||||
|
||||
@@ -1314,8 +1314,8 @@ NativeGetElement(JSContext* cx, HandleNativeObject obj, uint32_t index, MutableH
|
||||
}
|
||||
|
||||
bool
|
||||
SetPropertyByDefining(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult& result);
|
||||
SetPropertyByDefining(JSContext* cx, HandleId id, HandleValue v, HandleValue receiver,
|
||||
ObjectOpResult& result);
|
||||
|
||||
bool
|
||||
SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
||||
|
||||
@@ -826,7 +826,7 @@ UnboxedPlainObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id
|
||||
return SetProperty(cx, obj, id, v, receiver, result);
|
||||
}
|
||||
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
}
|
||||
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
|
||||
@@ -1533,7 +1533,7 @@ UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id
|
||||
return SetProperty(cx, obj, id, v, receiver, result);
|
||||
}
|
||||
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, result);
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
}
|
||||
|
||||
return SetPropertyOnProto(cx, obj, id, v, receiver, result);
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "MobileViewportManager.h"
|
||||
|
||||
#include "LayersLogging.h"
|
||||
#include "nsViewManager.h"
|
||||
#include "nsViewportInfo.h"
|
||||
|
||||
#define MVM_LOG(...)
|
||||
// #define MVM_LOG(...) printf_stderr("MVM: " __VA_ARGS__)
|
||||
|
||||
NS_IMPL_ISUPPORTS(MobileViewportManager, nsIDOMEventListener, nsIObserver)
|
||||
|
||||
static const nsLiteralString DOM_META_ADDED = NS_LITERAL_STRING("DOMMetaAdded");
|
||||
static const nsLiteralString FULL_ZOOM_CHANGE = NS_LITERAL_STRING("FullZoomChange");
|
||||
static const nsLiteralCString BEFORE_FIRST_PAINT = NS_LITERAL_CSTRING("before-first-paint");
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
MobileViewportManager::MobileViewportManager(nsIPresShell* aPresShell,
|
||||
nsIDocument* aDocument)
|
||||
: mDocument(aDocument)
|
||||
, mPresShell(aPresShell)
|
||||
, mIsFirstPaint(false)
|
||||
{
|
||||
MOZ_ASSERT(mPresShell);
|
||||
MOZ_ASSERT(mDocument);
|
||||
|
||||
MVM_LOG("%p: creating with presShell %p document %p\n", this, mPresShell, aDocument);
|
||||
|
||||
if (nsCOMPtr<nsPIDOMWindow> window = mDocument->GetWindow()) {
|
||||
mEventTarget = window->GetChromeEventHandler();
|
||||
}
|
||||
if (mEventTarget) {
|
||||
mEventTarget->AddEventListener(DOM_META_ADDED, this, false);
|
||||
mEventTarget->AddEventListener(FULL_ZOOM_CHANGE, this, false);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, BEFORE_FIRST_PAINT.Data(), false);
|
||||
}
|
||||
}
|
||||
|
||||
MobileViewportManager::~MobileViewportManager()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MobileViewportManager::Destroy()
|
||||
{
|
||||
MVM_LOG("%p: destroying\n", this);
|
||||
|
||||
if (mEventTarget) {
|
||||
mEventTarget->RemoveEventListener(DOM_META_ADDED, this, false);
|
||||
mEventTarget->RemoveEventListener(FULL_ZOOM_CHANGE, this, false);
|
||||
mEventTarget = nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->RemoveObserver(this, BEFORE_FIRST_PAINT.Data());
|
||||
}
|
||||
|
||||
mDocument = nullptr;
|
||||
mPresShell = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MobileViewportManager::RequestReflow()
|
||||
{
|
||||
MVM_LOG("%p: got a reflow request\n", this);
|
||||
RefreshViewportSize(false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileViewportManager::HandleEvent(nsIDOMEvent* event)
|
||||
{
|
||||
nsAutoString type;
|
||||
event->GetType(type);
|
||||
|
||||
if (type.Equals(DOM_META_ADDED)) {
|
||||
MVM_LOG("%p: got a dom-meta-added event\n", this);
|
||||
RefreshViewportSize(true);
|
||||
} else if (type.Equals(FULL_ZOOM_CHANGE)) {
|
||||
MVM_LOG("%p: got a full-zoom-change event\n", this);
|
||||
RefreshViewportSize(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileViewportManager::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
||||
{
|
||||
if (SameCOMIdentity(aSubject, mDocument) && BEFORE_FIRST_PAINT.EqualsASCII(aTopic)) {
|
||||
MVM_LOG("%p: got a before-first-paint event\n", this);
|
||||
mIsFirstPaint = true;
|
||||
RefreshViewportSize(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CSSToScreenScale
|
||||
MobileViewportManager::UpdateResolution(const nsViewportInfo& aViewportInfo,
|
||||
const ScreenIntSize& aDisplaySize,
|
||||
const CSSSize& aViewport,
|
||||
const Maybe<float>& aDisplayWidthChangeRatio)
|
||||
{
|
||||
CSSToLayoutDeviceScale cssToDev((float)nsPresContext::AppUnitsPerCSSPixel()
|
||||
/ mPresShell->GetPresContext()->AppUnitsPerDevPixel());
|
||||
LayoutDeviceToLayerScale res(nsLayoutUtils::GetResolution(mPresShell));
|
||||
|
||||
if (!gfxPrefs::APZAllowZooming()) {
|
||||
return ViewTargetAs<ScreenPixel>(cssToDev * res / ParentLayerToLayerScale(1),
|
||||
PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
}
|
||||
|
||||
if (mIsFirstPaint) {
|
||||
CSSToScreenScale defaultZoom = aViewportInfo.GetDefaultZoom();
|
||||
MVM_LOG("%p: default zoom from viewport is %f\n", this, defaultZoom.scale);
|
||||
// FIXME/bug 799585(?): GetViewportInfo() returns a default zoom of
|
||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
if (defaultZoom.scale < 0.01f) {
|
||||
defaultZoom = MaxScaleRatio(ScreenSize(aDisplaySize), aViewport);
|
||||
MVM_LOG("%p: Intrinsic computed zoom is %f\n", this, defaultZoom.scale);
|
||||
}
|
||||
MOZ_ASSERT(aViewportInfo.GetMinZoom() <= defaultZoom &&
|
||||
defaultZoom <= aViewportInfo.GetMaxZoom());
|
||||
|
||||
CSSToParentLayerScale zoom = ViewTargetAs<ParentLayerPixel>(defaultZoom,
|
||||
PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
|
||||
LayoutDeviceToLayerScale resolution = zoom / cssToDev * ParentLayerToLayerScale(1);
|
||||
MVM_LOG("%p: setting resolution %f\n", this, resolution.scale);
|
||||
nsLayoutUtils::SetResolutionAndScaleTo(mPresShell, resolution.scale);
|
||||
|
||||
return defaultZoom;
|
||||
}
|
||||
|
||||
// If this is not a first paint, then in some cases we want to update the pre-
|
||||
// existing resolution so as to maintain how much actual content is visible
|
||||
// within the display width. Note that "actual content" may be different with
|
||||
// respect to CSS pixels because of the CSS viewport size changing.
|
||||
//
|
||||
// aDisplayWidthChangeRatio is non-empty if:
|
||||
// (a) The meta-viewport tag information changes, and so the CSS viewport
|
||||
// might change as a result. In this case, we want to adjust the zoom to
|
||||
// compensate. OR
|
||||
// (b) The display size changed from a nonzero value to another nonzero value.
|
||||
// This covers the case where e.g. the device was rotated, and again we
|
||||
// want to adjust the zoom to compensate.
|
||||
// Note in particular that aDisplayWidthChangeRatio will be None if all that
|
||||
// happened was a change in the full-zoom. In this case, we still want to
|
||||
// compute a new CSS viewport, but we don't want to update the resolution.
|
||||
//
|
||||
// Given the above, the algorithm below accounts for all types of changes I
|
||||
// can conceive of:
|
||||
// 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
|
||||
if (aDisplayWidthChangeRatio) {
|
||||
float cssViewportChangeRatio = (mMobileViewportSize.width == 0)
|
||||
? 1.0f : aViewport.width / mMobileViewportSize.width;
|
||||
LayoutDeviceToLayerScale newRes(res.scale * aDisplayWidthChangeRatio.value()
|
||||
/ cssViewportChangeRatio);
|
||||
MVM_LOG("%p: Old resolution was %f, changed by %f/%f to %f\n", this, res.scale,
|
||||
aDisplayWidthChangeRatio.value(), cssViewportChangeRatio, newRes.scale);
|
||||
nsLayoutUtils::SetResolutionAndScaleTo(mPresShell, newRes.scale);
|
||||
res = newRes;
|
||||
}
|
||||
|
||||
return ViewTargetAs<ScreenPixel>(cssToDev * res / ParentLayerToLayerScale(1),
|
||||
PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
}
|
||||
|
||||
void
|
||||
MobileViewportManager::UpdateSPCSPS(const ScreenIntSize& aDisplaySize,
|
||||
const CSSToScreenScale& aZoom)
|
||||
{
|
||||
ScreenSize compositionSize(aDisplaySize);
|
||||
ScreenMargin scrollbars =
|
||||
CSSMargin::FromAppUnits(
|
||||
nsLayoutUtils::ScrollbarAreaToExcludeFromCompositionBoundsFor(
|
||||
mPresShell->GetRootScrollFrame()))
|
||||
* CSSToScreenScale(1.0f); // Scrollbars are not subject to scaling, so
|
||||
// CSS pixels = layer pixels for them (modulo bug 1168487).
|
||||
compositionSize.width -= scrollbars.LeftRight();
|
||||
compositionSize.height -= scrollbars.TopBottom();
|
||||
CSSSize compSize = compositionSize / aZoom;
|
||||
MVM_LOG("%p: Setting SPCSPS %s\n", this, Stringify(compSize).c_str());
|
||||
nsLayoutUtils::SetScrollPositionClampingScrollPortSize(mPresShell, compSize);
|
||||
}
|
||||
|
||||
void
|
||||
MobileViewportManager::UpdateDisplayPortMargins()
|
||||
{
|
||||
if (nsIScrollableFrame* root = mPresShell->GetRootScrollFrameAsScrollable()) {
|
||||
nsLayoutUtils::CalculateAndSetDisplayPortMargins(root,
|
||||
nsLayoutUtils::RepaintMode::DoNotRepaint);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MobileViewportManager::RefreshViewportSize(bool aForceAdjustResolution)
|
||||
{
|
||||
// This function gets called by the various triggers that may result in a
|
||||
// change of the CSS viewport. In some of these cases (e.g. the meta-viewport
|
||||
// tag changes) we want to update the resolution and in others (e.g. the full
|
||||
// zoom changing) we don't want to update the resolution. See the comment in
|
||||
// UpdateResolution for some more detail on this. An important assumption we
|
||||
// make here is that this RefreshViewportSize function will be called
|
||||
// separately for each trigger that changes. For instance it should never get
|
||||
// called such that both the full zoom and the meta-viewport tag have changed;
|
||||
// instead it would get called twice - once after each trigger changes. This
|
||||
// assumption is what allows the aForceAdjustResolution parameter to work as
|
||||
// intended; if this assumption is violated then we will need to add extra
|
||||
// complicated logic in UpdateResolution to ensure we only do the resolution
|
||||
// update in the right scenarios.
|
||||
|
||||
Maybe<float> displayWidthChangeRatio;
|
||||
LayoutDeviceIntSize newDisplaySize;
|
||||
if (nsLayoutUtils::GetContentViewerSize(mPresShell->GetPresContext(), newDisplaySize)) {
|
||||
// See the comment in UpdateResolution for why we're doing this.
|
||||
if (mDisplaySize.width > 0) {
|
||||
if (aForceAdjustResolution || mDisplaySize.width != newDisplaySize.width) {
|
||||
displayWidthChangeRatio = Some((float)newDisplaySize.width / (float)mDisplaySize.width);
|
||||
}
|
||||
} else if (aForceAdjustResolution) {
|
||||
displayWidthChangeRatio = Some(1.0f);
|
||||
}
|
||||
|
||||
MVM_LOG("%p: Display width change ratio is %f\n", this, displayWidthChangeRatio.valueOr(0.0f));
|
||||
mDisplaySize = newDisplaySize;
|
||||
}
|
||||
|
||||
MVM_LOG("%p: Computing CSS viewport using %d,%d\n", this,
|
||||
mDisplaySize.width, mDisplaySize.height);
|
||||
if (mDisplaySize.width == 0 || mDisplaySize.height == 0) {
|
||||
// We can't do anything useful here, we should just bail out
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenIntSize displaySize = ViewAs<ScreenPixel>(
|
||||
mDisplaySize, PixelCastJustification::LayoutDeviceIsScreenForBounds);
|
||||
nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(
|
||||
mDocument, displaySize);
|
||||
|
||||
CSSSize viewport = viewportInfo.GetSize();
|
||||
MVM_LOG("%p: Computed CSS viewport %s\n", this, Stringify(viewport).c_str());
|
||||
|
||||
if (!mIsFirstPaint && mMobileViewportSize == viewport) {
|
||||
// Nothing changed, so no need to do a reflow
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's the first-paint or the viewport changed, we need to update
|
||||
// various APZ properties (the zoom and some things that might depend on it)
|
||||
MVM_LOG("%p: Updating properties because %d || %d\n", this,
|
||||
mIsFirstPaint, mMobileViewportSize != viewport);
|
||||
|
||||
CSSToScreenScale zoom = UpdateResolution(viewportInfo, displaySize, viewport,
|
||||
displayWidthChangeRatio);
|
||||
MVM_LOG("%p: New zoom is %f\n", this, zoom.scale);
|
||||
UpdateSPCSPS(displaySize, zoom);
|
||||
UpdateDisplayPortMargins();
|
||||
|
||||
// Update internal state.
|
||||
mIsFirstPaint = false;
|
||||
mMobileViewportSize = viewport;
|
||||
|
||||
// Kick off a reflow.
|
||||
mPresShell->ResizeReflowIgnoreOverride(
|
||||
nsPresContext::CSSPixelsToAppUnits(viewport.width),
|
||||
nsPresContext::CSSPixelsToAppUnits(viewport.height));
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 MobileViewportManager_h_
|
||||
#define MobileViewportManager_h_
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "Units.h"
|
||||
|
||||
class nsIDOMEventTarget;
|
||||
class nsIDocument;
|
||||
class nsIPresShell;
|
||||
|
||||
class MobileViewportManager final : public nsIDOMEventListener
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
MobileViewportManager(nsIPresShell* aPresShell,
|
||||
nsIDocument* aDocument);
|
||||
void Destroy();
|
||||
|
||||
/* Notify the MobileViewportManager that a reflow was requested in the
|
||||
* presShell.*/
|
||||
void RequestReflow();
|
||||
|
||||
private:
|
||||
~MobileViewportManager();
|
||||
|
||||
/* Main helper method to update the CSS viewport and any other properties that
|
||||
* need updating. */
|
||||
void RefreshViewportSize(bool aForceAdjustResolution);
|
||||
|
||||
/* Updates the presShell resolution and returns the new zoom. */
|
||||
mozilla::CSSToScreenScale UpdateResolution(const nsViewportInfo& aViewportInfo,
|
||||
const mozilla::ScreenIntSize& aDisplaySize,
|
||||
const mozilla::CSSSize& aViewport,
|
||||
const mozilla::Maybe<float>& aDisplayWidthChangeRatio);
|
||||
/* Updates the scroll-position-clamping scrollport size */
|
||||
void UpdateSPCSPS(const mozilla::ScreenIntSize& aDisplaySize,
|
||||
const mozilla::CSSToScreenScale& aZoom);
|
||||
/* Updates the displayport margins for the presShell's root scrollable frame */
|
||||
void UpdateDisplayPortMargins();
|
||||
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsIPresShell* MOZ_NON_OWNING_REF mPresShell; // raw ref since the presShell owns this
|
||||
nsCOMPtr<nsIDOMEventTarget> mEventTarget;
|
||||
bool mIsFirstPaint;
|
||||
mozilla::LayoutDeviceIntSize mDisplaySize;
|
||||
mozilla::CSSSize mMobileViewportSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "RestyleTracker.h"
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
@@ -227,8 +228,17 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
|
||||
void
|
||||
RestyleTracker::DoProcessRestyles()
|
||||
{
|
||||
PROFILER_LABEL("RestyleTracker", "ProcessRestyles",
|
||||
js::ProfileEntry::Category::CSS);
|
||||
nsAutoCString docURL;
|
||||
if (profiler_is_active()) {
|
||||
nsIURI *uri = Document()->GetDocumentURI();
|
||||
if (uri) {
|
||||
uri->GetSpec(docURL);
|
||||
} else {
|
||||
docURL = "N/A";
|
||||
}
|
||||
}
|
||||
PROFILER_LABEL_PRINTF("RestyleTracker", "ProcessRestyles",
|
||||
js::ProfileEntry::Category::CSS, "(%s)", docURL.get());
|
||||
|
||||
bool isTimelineRecording = false;
|
||||
nsDocShell* docShell =
|
||||
|
||||
@@ -145,6 +145,45 @@ static gfx::PointTyped<TargetUnits> TransformVector(const gfx::Matrix4x4& aTrans
|
||||
return transformedEnd - transformedStart;
|
||||
}
|
||||
|
||||
// UntransformTo() and UntransformVector() are like TransformTo() and
|
||||
// TransformVector(), respectively, but are intended for cases where
|
||||
// the transformation matrix is the inverse of a 3D projection. When
|
||||
// using such transforms, the resulting Point4D is only meaningful
|
||||
// if it has a positive w-coordinate. To handle this, these functions
|
||||
// return a Maybe object which contains a value if and only if the
|
||||
// result is meaningful
|
||||
template <typename TargetUnits, typename SourceUnits>
|
||||
static Maybe<gfx::PointTyped<TargetUnits>> UntransformTo(const gfx::Matrix4x4& aTransform,
|
||||
const gfx::PointTyped<SourceUnits>& aPoint)
|
||||
{
|
||||
gfx::Point4D point = aTransform.ProjectPoint(aPoint.ToUnknownPoint());
|
||||
if (!point.HasPositiveWCoord()) {
|
||||
return Nothing();
|
||||
}
|
||||
return Some(ViewAs<TargetUnits>(point.As2DPoint()));
|
||||
}
|
||||
template <typename TargetUnits, typename SourceUnits>
|
||||
static Maybe<gfx::IntPointTyped<TargetUnits>> UntransformTo(const gfx::Matrix4x4& aTransform,
|
||||
const gfx::IntPointTyped<SourceUnits>& aPoint)
|
||||
{
|
||||
gfx::Point4D point = aTransform.ProjectPoint(aPoint.ToUnknownPoint());
|
||||
if (!point.HasPositiveWCoord()) {
|
||||
return Nothing();
|
||||
}
|
||||
return Some(RoundedToInt(ViewAs<TargetUnits>(point.As2DPoint())));
|
||||
}
|
||||
template <typename TargetUnits, typename SourceUnits>
|
||||
static Maybe<gfx::PointTyped<TargetUnits>> UntransformVector(const gfx::Matrix4x4& aTransform,
|
||||
const gfx::PointTyped<SourceUnits>& aVector,
|
||||
const gfx::PointTyped<SourceUnits>& aAnchor) {
|
||||
gfx::Point4D point = aTransform.ProjectPoint(aAnchor.ToUnknownPoint() + aVector.ToUnknownPoint())
|
||||
- aTransform.ProjectPoint(aAnchor.ToUnknownPoint());
|
||||
if (!point.HasPositiveWCoord()){
|
||||
return Nothing();
|
||||
}
|
||||
return Some(ViewAs<TargetUnits>(point.As2DPoint()));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
||||
@@ -137,8 +137,8 @@ mozilla::layers::ZoomConstraints
|
||||
ComputeZoomConstraintsFromViewportInfo(const nsViewportInfo& aViewportInfo)
|
||||
{
|
||||
mozilla::layers::ZoomConstraints constraints;
|
||||
constraints.mAllowZoom = aViewportInfo.IsZoomAllowed();
|
||||
constraints.mAllowDoubleTapZoom = aViewportInfo.IsDoubleTapZoomAllowed();
|
||||
constraints.mAllowZoom = aViewportInfo.IsZoomAllowed() && gfxPrefs::APZAllowZooming();
|
||||
constraints.mAllowDoubleTapZoom = aViewportInfo.IsDoubleTapZoomAllowed() && gfxPrefs::APZAllowZooming();
|
||||
constraints.mMinZoom.scale = aViewportInfo.GetMinZoom().scale;
|
||||
constraints.mMaxZoom.scale = aViewportInfo.GetMaxZoom().scale;
|
||||
return constraints;
|
||||
|
||||
@@ -112,6 +112,7 @@ UNIFIED_SOURCES += [
|
||||
'GeometryUtils.cpp',
|
||||
'LayoutLogging.cpp',
|
||||
'MaskLayerImageCache.cpp',
|
||||
'MobileViewportManager.cpp',
|
||||
'nsBidi.cpp',
|
||||
'nsBidiPresUtils.cpp',
|
||||
'nsCaret.cpp',
|
||||
|
||||
@@ -139,10 +139,10 @@ typedef struct CapturingContentInfo {
|
||||
mozilla::StaticRefPtr<nsIContent> mContent;
|
||||
} CapturingContentInfo;
|
||||
|
||||
// 7f0ae6b1-5fa1-4ba7-885e-a93e17d72cd2
|
||||
// 4f512d0b-c58c-4fc9-ae42-8aa6d992e7ae
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x7f0ae6b1, 0x5fa1, 0x4ba7, \
|
||||
{ 0x88, 0x5e, 0xa9, 0x3e, 0x17, 0xd7, 0x2c, 0xd2 } }
|
||||
{ 0x4f512d0b, 0xc58c, 0x4fc9, \
|
||||
{ 0xae, 0x42, 0x8a, 0xa6, 0xd9, 0x92, 0xe7, 0xae } }
|
||||
|
||||
// debug VerifyReflow flags
|
||||
#define VERIFY_REFLOW_ON 0x01
|
||||
@@ -410,6 +410,11 @@ public:
|
||||
* ResizeReflow() calls are ignored after ResizeReflowOverride().
|
||||
*/
|
||||
virtual nsresult ResizeReflowOverride(nscoord aWidth, nscoord aHeight) = 0;
|
||||
/**
|
||||
* Do the same thing as ResizeReflow but even if ResizeReflowOverride was
|
||||
* called previously.
|
||||
*/
|
||||
virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight) = 0;
|
||||
|
||||
/**
|
||||
* Returns true if ResizeReflowOverride has been called.
|
||||
|
||||
@@ -984,6 +984,12 @@ PresShell::Init(nsIDocument* aDocument,
|
||||
if (mPresContext->IsRootContentDocument()) {
|
||||
mZoomConstraintsClient = new ZoomConstraintsClient();
|
||||
mZoomConstraintsClient->Init(this, mDocument);
|
||||
#ifndef MOZ_WIDGET_ANDROID
|
||||
// Fennec will need some work to use this code; see bug 1180267.
|
||||
if (gfxPrefs::MetaViewportEnabled() || gfxPrefs::APZAllowZooming()) {
|
||||
mMobileViewportManager = new MobileViewportManager(this, mDocument);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1102,6 +1108,10 @@ PresShell::Destroy()
|
||||
mZoomConstraintsClient->Destroy();
|
||||
mZoomConstraintsClient = nullptr;
|
||||
}
|
||||
if (mMobileViewportManager) {
|
||||
mMobileViewportManager->Destroy();
|
||||
mMobileViewportManager = nullptr;
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
if (mDocAccessible) {
|
||||
@@ -1765,6 +1775,19 @@ nsresult
|
||||
PresShell::ResizeReflowOverride(nscoord aWidth, nscoord aHeight)
|
||||
{
|
||||
mViewportOverridden = true;
|
||||
|
||||
if (mMobileViewportManager) {
|
||||
// Once the viewport is explicitly overridden, we don't need the
|
||||
// MobileViewportManager any more (in this presShell at least). Destroying
|
||||
// it simplifies things because then it can maintain an invariant that any
|
||||
// time it gets a meta-viewport change (for example) it knows it must
|
||||
// recompute the CSS viewport and do a reflow. If we didn't destroy it here
|
||||
// then there would be times where a meta-viewport change would have no
|
||||
// effect.
|
||||
mMobileViewportManager->Destroy();
|
||||
mMobileViewportManager = nullptr;
|
||||
}
|
||||
|
||||
return ResizeReflowIgnoreOverride(aWidth, aHeight);
|
||||
}
|
||||
|
||||
@@ -1776,6 +1799,15 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
|
||||
// didn't ask to ignore the override. Pretend it didn't happen.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mMobileViewportManager) {
|
||||
// If we have a mobile viewport manager, request a reflow from it. It can
|
||||
// recompute the final CSS viewport and trigger a call to
|
||||
// ResizeReflowIgnoreOverride if it changed.
|
||||
mMobileViewportManager->RequestReflow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return ResizeReflowIgnoreOverride(aWidth, aHeight);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "MobileViewportManager.h"
|
||||
#include "ZoomConstraintsClient.h"
|
||||
|
||||
class nsRange;
|
||||
@@ -105,6 +106,7 @@ public:
|
||||
virtual nsresult Initialize(nscoord aWidth, nscoord aHeight) override;
|
||||
virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight) override;
|
||||
virtual nsresult ResizeReflowOverride(nscoord aWidth, nscoord aHeight) override;
|
||||
virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight) override;
|
||||
virtual nsIPageSequenceFrame* GetPageSequenceFrame() const override;
|
||||
virtual nsCanvasFrame* GetCanvasFrame() const override;
|
||||
virtual nsIFrame* GetRealPrimaryFrameFor(nsIContent* aContent) const override;
|
||||
@@ -352,7 +354,9 @@ public:
|
||||
|
||||
virtual nsresult SetIsActive(bool aIsActive) override;
|
||||
|
||||
virtual bool GetIsViewportOverridden() override { return mViewportOverridden; }
|
||||
virtual bool GetIsViewportOverridden() override {
|
||||
return mViewportOverridden || (mMobileViewportManager != nullptr);
|
||||
}
|
||||
|
||||
virtual bool IsLayoutFlushObserver() override
|
||||
{
|
||||
@@ -444,9 +448,6 @@ protected:
|
||||
// sets up.
|
||||
void ScheduleReflow();
|
||||
|
||||
// Reflow regardless of whether the override bit has been set.
|
||||
nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight);
|
||||
|
||||
// DoReflow returns whether the reflow finished without interruption
|
||||
bool DoReflow(nsIFrame* aFrame, bool aInterruptible);
|
||||
#ifdef DEBUG
|
||||
@@ -811,6 +812,7 @@ protected:
|
||||
TouchManager mTouchManager;
|
||||
|
||||
nsRefPtr<ZoomConstraintsClient> mZoomConstraintsClient;
|
||||
nsRefPtr<MobileViewportManager> mMobileViewportManager;
|
||||
|
||||
// TouchCaret
|
||||
nsRefPtr<mozilla::TouchCaret> mTouchCaret;
|
||||
|
||||
@@ -1469,7 +1469,8 @@ public:
|
||||
const nsPoint &aInitialDestination,
|
||||
const nsSize &aInitialVelocity,
|
||||
const nsRect &aRange,
|
||||
const mozilla::TimeStamp &aStartTime)
|
||||
const mozilla::TimeStamp &aStartTime,
|
||||
nsPresContext* aPresContext)
|
||||
: mXAxisModel(aInitialPosition.x, aInitialDestination.x,
|
||||
aInitialVelocity.width,
|
||||
gfxPrefs::ScrollBehaviorSpringConstant(),
|
||||
@@ -1481,6 +1482,7 @@ public:
|
||||
, mRange(aRange)
|
||||
, mLastRefreshTime(aStartTime)
|
||||
, mCallee(nullptr)
|
||||
, mOneDevicePixelInAppUnits(aPresContext->DevPixelsToAppUnits(1))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1537,7 +1539,8 @@ public:
|
||||
|
||||
bool IsFinished()
|
||||
{
|
||||
return mXAxisModel.IsFinished() && mYAxisModel.IsFinished();
|
||||
return mXAxisModel.IsFinished(mOneDevicePixelInAppUnits) &&
|
||||
mYAxisModel.IsFinished(mOneDevicePixelInAppUnits);
|
||||
}
|
||||
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime) override {
|
||||
@@ -1590,6 +1593,7 @@ private:
|
||||
nsRect mRange;
|
||||
mozilla::TimeStamp mLastRefreshTime;
|
||||
ScrollFrameHelper *mCallee;
|
||||
nscoord mOneDevicePixelInAppUnits;
|
||||
};
|
||||
|
||||
// AsyncScroll has ref counting.
|
||||
@@ -2064,7 +2068,7 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition,
|
||||
mAsyncSmoothMSDScroll =
|
||||
new AsyncSmoothMSDScroll(GetScrollPosition(), mDestination,
|
||||
currentVelocity, GetScrollRangeForClamping(),
|
||||
now);
|
||||
now, presContext);
|
||||
|
||||
if (!mAsyncSmoothMSDScroll->SetRefreshObserver(this)) {
|
||||
// Observer setup failed. Scroll the normal way.
|
||||
|
||||
@@ -533,6 +533,7 @@ pref("layout.event-regions.enabled", false);
|
||||
// APZ preferences. For documentation/details on what these prefs do, check
|
||||
// gfx/layers/apz/src/AsyncPanZoomController.cpp.
|
||||
pref("apz.allow_checkerboarding", true);
|
||||
pref("apz.allow_zooming", false);
|
||||
pref("apz.asyncscroll.throttle", 100);
|
||||
pref("apz.asyncscroll.timeout", 300);
|
||||
|
||||
|
||||
+110
-13
@@ -212,37 +212,134 @@ MultiTouchInput::MultiTouchInput(const WidgetMouseEvent& aMouseEvent)
|
||||
1.0f));
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
MultiTouchInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
for (size_t i = 0; i < mTouches.Length(); i++) {
|
||||
mTouches[i].mLocalScreenPoint = TransformTo<ParentLayerPixel>(aTransform, ScreenPoint(mTouches[i].mScreenPoint));
|
||||
Maybe<ParentLayerIntPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mTouches[i].mScreenPoint);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mTouches[i].mLocalScreenPoint = *point;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PanGestureInput::IsMomentum() const
|
||||
{
|
||||
switch (mType) {
|
||||
case PanGestureInput::PANGESTURE_MOMENTUMSTART:
|
||||
case PanGestureInput::PANGESTURE_MOMENTUMPAN:
|
||||
case PanGestureInput::PANGESTURE_MOMENTUMEND:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WidgetWheelEvent
|
||||
PanGestureInput::ToWidgetWheelEvent(nsIWidget* aWidget) const
|
||||
{
|
||||
WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, aWidget);
|
||||
wheelEvent.modifiers = this->modifiers;
|
||||
wheelEvent.time = mTime;
|
||||
wheelEvent.timeStamp = mTimeStamp;
|
||||
wheelEvent.refPoint =
|
||||
RoundedToInt(ViewAs<LayoutDevicePixel>(mPanStartPoint,
|
||||
PixelCastJustification::LayoutDeviceToScreenForUntransformedEvent));
|
||||
wheelEvent.buttons = 0;
|
||||
wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_PIXEL;
|
||||
wheelEvent.isMomentum = IsMomentum();
|
||||
wheelEvent.lineOrPageDeltaX = mLineOrPageDeltaX;
|
||||
wheelEvent.lineOrPageDeltaY = mLineOrPageDeltaY;
|
||||
wheelEvent.deltaX = mPanDisplacement.x;
|
||||
wheelEvent.deltaY = mPanDisplacement.y;
|
||||
wheelEvent.mFlags.mHandledByAPZ = true;
|
||||
return wheelEvent;
|
||||
}
|
||||
|
||||
bool
|
||||
PanGestureInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalPanStartPoint = TransformTo<ParentLayerPixel>(aTransform, mPanStartPoint);
|
||||
mLocalPanDisplacement = TransformVector<ParentLayerPixel>(aTransform, mPanDisplacement, mPanStartPoint);
|
||||
{
|
||||
Maybe<ParentLayerPoint> panStartPoint = UntransformTo<ParentLayerPixel>(aTransform, mPanStartPoint);
|
||||
if (!panStartPoint) {
|
||||
return false;
|
||||
}
|
||||
mLocalPanStartPoint = *panStartPoint;
|
||||
|
||||
Maybe<ParentLayerPoint> panDisplacement = UntransformVector<ParentLayerPixel>(aTransform, mPanDisplacement, mPanStartPoint);
|
||||
if (!panDisplacement) {
|
||||
return false;
|
||||
}
|
||||
mLocalPanDisplacement = *panDisplacement;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
PinchGestureInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalFocusPoint = TransformTo<ParentLayerPixel>(aTransform, mFocusPoint);
|
||||
{
|
||||
Maybe<ParentLayerPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mFocusPoint);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mLocalFocusPoint = *point;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
TapGestureInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalPoint = TransformTo<ParentLayerPixel>(aTransform, mPoint);
|
||||
Maybe<ParentLayerIntPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mPoint);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mLocalPoint = *point;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static uint32_t
|
||||
DeltaModeForDeltaType(ScrollWheelInput::ScrollDeltaType aDeltaType)
|
||||
{
|
||||
switch (aDeltaType) {
|
||||
case ScrollWheelInput::SCROLLDELTA_LINE:
|
||||
return nsIDOMWheelEvent::DOM_DELTA_LINE;
|
||||
case ScrollWheelInput::SCROLLDELTA_PIXEL:
|
||||
default:
|
||||
return nsIDOMWheelEvent::DOM_DELTA_PIXEL;
|
||||
}
|
||||
}
|
||||
|
||||
WidgetWheelEvent
|
||||
ScrollWheelInput::ToWidgetWheelEvent(nsIWidget* aWidget) const
|
||||
{
|
||||
WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, aWidget);
|
||||
wheelEvent.modifiers = this->modifiers;
|
||||
wheelEvent.time = mTime;
|
||||
wheelEvent.timeStamp = mTimeStamp;
|
||||
wheelEvent.refPoint =
|
||||
RoundedToInt(ViewAs<LayoutDevicePixel>(mOrigin,
|
||||
PixelCastJustification::LayoutDeviceToScreenForUntransformedEvent));
|
||||
wheelEvent.buttons = 0;
|
||||
wheelEvent.deltaMode = DeltaModeForDeltaType(mDeltaType);
|
||||
wheelEvent.isMomentum = mIsMomentum;
|
||||
wheelEvent.deltaX = mDeltaX;
|
||||
wheelEvent.deltaY = mDeltaY;
|
||||
wheelEvent.lineOrPageDeltaX = mLineOrPageDeltaX;
|
||||
wheelEvent.lineOrPageDeltaY = mLineOrPageDeltaY;
|
||||
wheelEvent.mFlags.mHandledByAPZ = true;
|
||||
return wheelEvent;
|
||||
}
|
||||
|
||||
bool
|
||||
ScrollWheelInput::TransformToLocal(const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
mLocalOrigin = TransformTo<ParentLayerPixel>(aTransform, mOrigin);
|
||||
Maybe<ParentLayerPoint> point = UntransformTo<ParentLayerPixel>(aTransform, mOrigin);
|
||||
if (!point) {
|
||||
return false;
|
||||
}
|
||||
mLocalOrigin = *point;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
+45
-9
@@ -6,6 +6,7 @@
|
||||
#ifndef InputData_h__
|
||||
#define InputData_h__
|
||||
|
||||
#include "nsIDOMWheelEvent.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsPoint.h"
|
||||
#include "nsTArray.h"
|
||||
@@ -234,7 +235,7 @@ public:
|
||||
// and rotation angle.
|
||||
explicit MultiTouchInput(const WidgetMouseEvent& aMouseEvent);
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
MultiTouchType mType;
|
||||
nsTArray<SingleTouchData> mTouches;
|
||||
@@ -302,11 +303,17 @@ public:
|
||||
: InputData(PANGESTURE_INPUT, aTime, aTimeStamp, aModifiers),
|
||||
mType(aType),
|
||||
mPanStartPoint(aPanStartPoint),
|
||||
mPanDisplacement(aPanDisplacement)
|
||||
mPanDisplacement(aPanDisplacement),
|
||||
mLineOrPageDeltaX(0),
|
||||
mLineOrPageDeltaY(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool IsMomentum() const;
|
||||
|
||||
WidgetWheelEvent ToWidgetWheelEvent(nsIWidget* aWidget) const;
|
||||
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
PanGestureType mType;
|
||||
ScreenPoint mPanStartPoint;
|
||||
@@ -318,6 +325,10 @@ public:
|
||||
// coordinates of the APZC receiving the pan. These are set and used by APZ.
|
||||
ParentLayerPoint mLocalPanStartPoint;
|
||||
ParentLayerPoint mLocalPanDisplacement;
|
||||
|
||||
// See lineOrPageDeltaX/Y on WidgetWheelEvent.
|
||||
int32_t mLineOrPageDeltaX;
|
||||
int32_t mLineOrPageDeltaY;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -369,7 +380,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
PinchGestureType mType;
|
||||
|
||||
@@ -439,7 +450,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
TapGestureType mType;
|
||||
|
||||
@@ -460,10 +471,25 @@ public:
|
||||
enum ScrollDeltaType
|
||||
{
|
||||
// There are three kinds of scroll delta modes in Gecko: "page", "line" and
|
||||
// "pixel". For apz, we currently only support "line" mode.
|
||||
SCROLLDELTA_LINE
|
||||
// "pixel". For apz, we currently only support the "line" and "pixel" modes.
|
||||
SCROLLDELTA_LINE,
|
||||
SCROLLDELTA_PIXEL
|
||||
};
|
||||
|
||||
static ScrollDeltaType
|
||||
DeltaTypeForDeltaMode(uint32_t aDeltaMode)
|
||||
{
|
||||
switch (aDeltaMode) {
|
||||
case nsIDOMWheelEvent::DOM_DELTA_LINE:
|
||||
return SCROLLDELTA_LINE;
|
||||
case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
|
||||
return SCROLLDELTA_PIXEL;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
return SCROLLDELTA_LINE;
|
||||
}
|
||||
|
||||
enum ScrollMode
|
||||
{
|
||||
SCROLLMODE_INSTANT,
|
||||
@@ -483,10 +509,14 @@ public:
|
||||
mScrollMode(aScrollMode),
|
||||
mOrigin(aOrigin),
|
||||
mDeltaX(aDeltaX),
|
||||
mDeltaY(aDeltaY)
|
||||
mDeltaY(aDeltaY),
|
||||
mLineOrPageDeltaX(0),
|
||||
mLineOrPageDeltaY(0),
|
||||
mIsMomentum(false)
|
||||
{}
|
||||
|
||||
void TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
WidgetWheelEvent ToWidgetWheelEvent(nsIWidget* aWidget) const;
|
||||
bool TransformToLocal(const gfx::Matrix4x4& aTransform);
|
||||
|
||||
ScrollDeltaType mDeltaType;
|
||||
ScrollMode mScrollMode;
|
||||
@@ -505,6 +535,12 @@ public:
|
||||
// The location of the scroll in local coordinates. This is set and used by
|
||||
// APZ.
|
||||
ParentLayerPoint mLocalOrigin;
|
||||
|
||||
// See lineOrPageDeltaX/Y on WidgetWheelEvent.
|
||||
int32_t mLineOrPageDeltaX;
|
||||
int32_t mLineOrPageDeltaY;
|
||||
|
||||
bool mIsMomentum;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -454,6 +454,7 @@ public:
|
||||
, overflowDeltaX(0.0)
|
||||
, overflowDeltaY(0.0)
|
||||
, mViewPortIsOverscrolled(false)
|
||||
, mCanTriggerSwipe(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -468,6 +469,16 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
// On OS X, scroll gestures that start at the edge of the scrollable range
|
||||
// can result in a swipe gesture. For the first wheel event of such a
|
||||
// gesture, call TriggersSwipe() after the event has been processed
|
||||
// in order to find out whether a swipe should be started.
|
||||
bool TriggersSwipe() const
|
||||
{
|
||||
return mCanTriggerSwipe && mViewPortIsOverscrolled &&
|
||||
this->overflowDeltaX != 0.0;
|
||||
}
|
||||
|
||||
// NOTE: deltaX, deltaY and deltaZ may be customized by
|
||||
// mousewheel.*.delta_multiplier_* prefs which are applied by
|
||||
// EventStateManager. So, after widget dispatches this event,
|
||||
@@ -551,6 +562,10 @@ public:
|
||||
// overscrolled.
|
||||
bool mViewPortIsOverscrolled;
|
||||
|
||||
// The wheel event can trigger a swipe to start if it's overscrolling the
|
||||
// viewport.
|
||||
bool mCanTriggerSwipe;
|
||||
|
||||
void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets)
|
||||
{
|
||||
AssignMouseEventBaseData(aEvent, aCopyTargets);
|
||||
@@ -568,6 +583,7 @@ public:
|
||||
overflowDeltaX = aEvent.overflowDeltaX;
|
||||
overflowDeltaY = aEvent.overflowDeltaY;
|
||||
mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
|
||||
mCanTriggerSwipe = aEvent.mCanTriggerSwipe;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1077,6 +1077,23 @@ PuppetWidget::GetNativeData(uint32_t aDataType)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
void
|
||||
PuppetWidget::SetNativeData(uint32_t aDataType, uintptr_t aVal)
|
||||
{
|
||||
switch (aDataType) {
|
||||
case NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW:
|
||||
MOZ_ASSERT(mTabChild, "Need TabChild to send the message.");
|
||||
if (mTabChild) {
|
||||
mTabChild->SendSetNativeChildOfShareableWindow(aVal);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("SetNativeData called with unsupported data type.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIntPoint
|
||||
PuppetWidget::GetChromeDimensions()
|
||||
{
|
||||
|
||||
@@ -119,6 +119,9 @@ public:
|
||||
|
||||
// PuppetWidgets don't have native data, as they're purely nonnative.
|
||||
virtual void* GetNativeData(uint32_t aDataType) override;
|
||||
#if defined(XP_WIN)
|
||||
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
|
||||
#endif
|
||||
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) override
|
||||
{ return NS_ERROR_UNEXPECTED; }
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 SwipeTracker_h
|
||||
#define SwipeTracker_h
|
||||
|
||||
#include "EventForwards.h"
|
||||
#include "mozilla/layers/AxisPhysicsMSDModel.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "Units.h"
|
||||
|
||||
class nsIPresShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class PanGestureInput;
|
||||
|
||||
/**
|
||||
* SwipeTracker turns PanGestureInput events into swipe events
|
||||
* (WidgetSimpleGestureEvent) and dispatches them into Gecko.
|
||||
* The swiping behavior mirrors the behavior of the Cocoa API
|
||||
* -[NSEvent trackSwipeEventWithOptions:dampenAmountThresholdMin:max:usingHandler:].
|
||||
* The advantage of using this class over the Cocoa API is that this class
|
||||
* properly supports submitting queued up events to it, and that it hopefully
|
||||
* doesn't intermittently break scrolling the way the Cocoa API does (bug 927702).
|
||||
*
|
||||
* The swipe direction is either left or right. It is determined before the
|
||||
* SwipeTracker is created and stays fixed during the swipe.
|
||||
* During the swipe, the swipe has a current "value" which is between 0 and the
|
||||
* target value. The target value is either 1 (swiping left) or -1 (swiping
|
||||
* right) - see SwipeSuccessTargetValue().
|
||||
* A swipe can either succeed or fail. If it succeeds, the swipe animation
|
||||
* animates towards the success target value; if it fails, it animates back to
|
||||
* a value of 0. A swipe can only succeed if the user is swiping in an allowed
|
||||
* direction. (Since both the allowed directions and the swipe direction are
|
||||
* known at swipe start time, it's clear from the beginning whether a swipe is
|
||||
* doomed to fail. In that case, the purpose of the SwipeTracker is to simulate
|
||||
* a bounce-back animation.)
|
||||
*/
|
||||
class SwipeTracker final : public nsARefreshObserver {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(SwipeTracker, override)
|
||||
|
||||
SwipeTracker(nsChildView& aWidget,
|
||||
const PanGestureInput& aSwipeStartEvent,
|
||||
uint32_t aAllowedDirections,
|
||||
uint32_t aSwipeDirection);
|
||||
|
||||
void Destroy();
|
||||
|
||||
nsEventStatus ProcessEvent(const PanGestureInput& aEvent);
|
||||
void CancelSwipe();
|
||||
|
||||
static WidgetSimpleGestureEvent
|
||||
CreateSwipeGestureEvent(EventMessage aMsg, nsIWidget* aWidget,
|
||||
const LayoutDeviceIntPoint& aPosition);
|
||||
|
||||
|
||||
// nsARefreshObserver
|
||||
void WillRefresh(mozilla::TimeStamp aTime) override;
|
||||
|
||||
protected:
|
||||
~SwipeTracker();
|
||||
|
||||
bool SwipingInAllowedDirection() const { return mAllowedDirections & mSwipeDirection; }
|
||||
double SwipeSuccessTargetValue() const;
|
||||
double ClampToAllowedRange(double aGestureAmount) const;
|
||||
bool ComputeSwipeSuccess() const;
|
||||
void StartAnimating(double aTargetValue);
|
||||
void SwipeFinished();
|
||||
void UnregisterFromRefreshDriver();
|
||||
bool SendSwipeEvent(EventMessage aMsg, uint32_t aDirection, double aDelta);
|
||||
|
||||
nsChildView& mWidget;
|
||||
nsRefPtr<nsRefreshDriver> mRefreshDriver;
|
||||
layers::AxisPhysicsMSDModel mAxis;
|
||||
const LayoutDeviceIntPoint mEventPosition;
|
||||
TimeStamp mLastEventTimeStamp;
|
||||
TimeStamp mLastAnimationFrameTime;
|
||||
const uint32_t mAllowedDirections;
|
||||
const uint32_t mSwipeDirection;
|
||||
double mGestureAmount;
|
||||
double mCurrentVelocity;
|
||||
bool mEventsAreControllingSwipe;
|
||||
bool mEventsHaveStartedNewGesture;
|
||||
bool mRegisteredWithRefreshDriver;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // SwipeTracker_h
|
||||
@@ -0,0 +1,219 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "SwipeTracker.h"
|
||||
|
||||
#include "InputData.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/TouchEvents.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsChildView.h"
|
||||
#include "UnitTransforms.h"
|
||||
|
||||
// These values were tweaked to make the physics feel similar to the native swipe.
|
||||
static const double kSpringForce = 250.0;
|
||||
static const double kVelocityTwitchTolerance = 0.0000001;
|
||||
static const double kWholePagePixelSize = 1000.0;
|
||||
static const double kRubberBandResistanceFactor = 4.0;
|
||||
static const double kSwipeSuccessThreshold = 0.25;
|
||||
static const double kSwipeSuccessVelocityContribution = 0.3;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static already_AddRefed<nsRefreshDriver>
|
||||
GetRefreshDriver(nsIWidget& aWidget)
|
||||
{
|
||||
nsIWidgetListener* widgetListener = aWidget.GetWidgetListener();
|
||||
nsIPresShell* presShell = widgetListener ? widgetListener->GetPresShell() : nullptr;
|
||||
nsPresContext* presContext = presShell ? presShell->GetPresContext() : nullptr;
|
||||
nsRefPtr<nsRefreshDriver> refreshDriver = presContext ? presContext->RefreshDriver() : nullptr;
|
||||
return refreshDriver.forget();
|
||||
}
|
||||
|
||||
SwipeTracker::SwipeTracker(nsChildView& aWidget,
|
||||
const PanGestureInput& aSwipeStartEvent,
|
||||
uint32_t aAllowedDirections,
|
||||
uint32_t aSwipeDirection)
|
||||
: mWidget(aWidget)
|
||||
, mRefreshDriver(GetRefreshDriver(mWidget))
|
||||
, mAxis(0.0, 0.0, 0.0, kSpringForce, 1.0)
|
||||
, mEventPosition(RoundedToInt(ViewAs<LayoutDevicePixel>(aSwipeStartEvent.mPanStartPoint,
|
||||
PixelCastJustification::LayoutDeviceToScreenForUntransformedEvent)))
|
||||
, mLastEventTimeStamp(aSwipeStartEvent.mTimeStamp)
|
||||
, mAllowedDirections(aAllowedDirections)
|
||||
, mSwipeDirection(aSwipeDirection)
|
||||
, mGestureAmount(0.0)
|
||||
, mCurrentVelocity(0.0)
|
||||
, mEventsAreControllingSwipe(true)
|
||||
, mEventsHaveStartedNewGesture(false)
|
||||
, mRegisteredWithRefreshDriver(false)
|
||||
{
|
||||
ProcessEvent(aSwipeStartEvent);
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::Destroy()
|
||||
{
|
||||
UnregisterFromRefreshDriver();
|
||||
}
|
||||
|
||||
SwipeTracker::~SwipeTracker()
|
||||
{
|
||||
MOZ_ASSERT(!mRegisteredWithRefreshDriver, "Destroy needs to be called before deallocating");
|
||||
}
|
||||
|
||||
double
|
||||
SwipeTracker::SwipeSuccessTargetValue() const
|
||||
{
|
||||
return (mSwipeDirection == nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
double
|
||||
SwipeTracker::ClampToAllowedRange(double aGestureAmount) const
|
||||
{
|
||||
// gestureAmount needs to stay between -1 and 0 when swiping right and
|
||||
// between 0 and 1 when swiping left.
|
||||
double min = (mSwipeDirection == nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1.0 : 0.0;
|
||||
double max = (mSwipeDirection == nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ? 1.0 : 0.0;
|
||||
return clamped(aGestureAmount, min, max);
|
||||
}
|
||||
|
||||
bool
|
||||
SwipeTracker::ComputeSwipeSuccess() const
|
||||
{
|
||||
double targetValue = SwipeSuccessTargetValue();
|
||||
|
||||
// If the fingers were moving away from the target direction when they were
|
||||
// lifted from the touchpad, abort the swipe.
|
||||
if (mCurrentVelocity * targetValue < -kVelocityTwitchTolerance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (mGestureAmount * targetValue +
|
||||
mCurrentVelocity * targetValue * kSwipeSuccessVelocityContribution) >= kSwipeSuccessThreshold;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
SwipeTracker::ProcessEvent(const PanGestureInput& aEvent)
|
||||
{
|
||||
// If the fingers have already been lifted, don't process this event for swiping.
|
||||
if (!mEventsAreControllingSwipe) {
|
||||
// Return nsEventStatus_eConsumeNoDefault for events from the swipe gesture
|
||||
// and nsEventStatus_eIgnore for events of subsequent scroll gestures.
|
||||
if (aEvent.mType == PanGestureInput::PANGESTURE_MAYSTART ||
|
||||
aEvent.mType == PanGestureInput::PANGESTURE_START) {
|
||||
mEventsHaveStartedNewGesture = true;
|
||||
}
|
||||
return mEventsHaveStartedNewGesture ? nsEventStatus_eIgnore : nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
double delta = -aEvent.mPanDisplacement.x / mWidget.BackingScaleFactor() / kWholePagePixelSize;
|
||||
if (!SwipingInAllowedDirection()) {
|
||||
delta /= kRubberBandResistanceFactor;
|
||||
}
|
||||
mGestureAmount = ClampToAllowedRange(mGestureAmount + delta);
|
||||
SendSwipeEvent(NS_SIMPLE_GESTURE_SWIPE_UPDATE, 0, mGestureAmount);
|
||||
|
||||
if (aEvent.mType != PanGestureInput::PANGESTURE_END) {
|
||||
double elapsedSeconds = std::max(0.008, (aEvent.mTimeStamp - mLastEventTimeStamp).ToSeconds());
|
||||
mCurrentVelocity = delta / elapsedSeconds;
|
||||
mLastEventTimeStamp = aEvent.mTimeStamp;
|
||||
} else {
|
||||
mEventsAreControllingSwipe = false;
|
||||
bool didSwipeSucceed = SwipingInAllowedDirection() && ComputeSwipeSuccess();
|
||||
double targetValue = 0.0;
|
||||
if (didSwipeSucceed) {
|
||||
SendSwipeEvent(NS_SIMPLE_GESTURE_SWIPE, mSwipeDirection, 0.0);
|
||||
targetValue = SwipeSuccessTargetValue();
|
||||
}
|
||||
StartAnimating(targetValue);
|
||||
}
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::StartAnimating(double aTargetValue)
|
||||
{
|
||||
mAxis.SetPosition(mGestureAmount);
|
||||
mAxis.SetDestination(aTargetValue);
|
||||
mAxis.SetVelocity(mCurrentVelocity);
|
||||
|
||||
mLastAnimationFrameTime = TimeStamp::Now();
|
||||
|
||||
// Add ourselves as a refresh driver observer. The refresh driver
|
||||
// will call WillRefresh for each animation frame until we
|
||||
// unregister ourselves.
|
||||
MOZ_ASSERT(!mRegisteredWithRefreshDriver);
|
||||
if (mRefreshDriver) {
|
||||
mRefreshDriver->AddRefreshObserver(this, Flush_Style);
|
||||
mRegisteredWithRefreshDriver = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
mAxis.Simulate(now - mLastAnimationFrameTime);
|
||||
mLastAnimationFrameTime = now;
|
||||
|
||||
bool isFinished = mAxis.IsFinished(1.0 / kWholePagePixelSize);
|
||||
mGestureAmount = (isFinished ? mAxis.GetDestination() : mAxis.GetPosition());
|
||||
SendSwipeEvent(NS_SIMPLE_GESTURE_SWIPE_UPDATE, 0, mGestureAmount);
|
||||
|
||||
if (isFinished) {
|
||||
UnregisterFromRefreshDriver();
|
||||
SwipeFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::CancelSwipe()
|
||||
{
|
||||
SendSwipeEvent(NS_SIMPLE_GESTURE_SWIPE_END, 0, 0.0);
|
||||
}
|
||||
|
||||
void SwipeTracker::SwipeFinished()
|
||||
{
|
||||
SendSwipeEvent(NS_SIMPLE_GESTURE_SWIPE_END, 0, 0.0);
|
||||
mWidget.SwipeFinished();
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::UnregisterFromRefreshDriver()
|
||||
{
|
||||
if (mRegisteredWithRefreshDriver) {
|
||||
MOZ_ASSERT(mRefreshDriver, "How were we able to register, then?");
|
||||
mRefreshDriver->RemoveRefreshObserver(this, Flush_Style);
|
||||
}
|
||||
mRegisteredWithRefreshDriver = false;
|
||||
}
|
||||
|
||||
/* static */ WidgetSimpleGestureEvent
|
||||
SwipeTracker::CreateSwipeGestureEvent(EventMessage aMsg, nsIWidget* aWidget,
|
||||
const LayoutDeviceIntPoint& aPosition)
|
||||
{
|
||||
WidgetSimpleGestureEvent geckoEvent(true, aMsg, aWidget);
|
||||
geckoEvent.modifiers = 0;
|
||||
geckoEvent.timeStamp = TimeStamp::Now();
|
||||
geckoEvent.refPoint = aPosition;
|
||||
geckoEvent.buttons = 0;
|
||||
return geckoEvent;
|
||||
}
|
||||
|
||||
bool
|
||||
SwipeTracker::SendSwipeEvent(EventMessage aMsg, uint32_t aDirection, double aDelta)
|
||||
{
|
||||
WidgetSimpleGestureEvent geckoEvent =
|
||||
CreateSwipeGestureEvent(aMsg, &mWidget, mEventPosition);
|
||||
geckoEvent.direction = aDirection;
|
||||
geckoEvent.delta = aDelta;
|
||||
geckoEvent.allowedDirections = mAllowedDirections;
|
||||
return mWidget.DispatchWindowEvent(geckoEvent);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -31,7 +31,6 @@ UNIFIED_SOURCES += [
|
||||
'nsColorPicker.mm',
|
||||
'nsCursorManager.mm',
|
||||
'nsDeviceContextSpecX.mm',
|
||||
'nsDragService.mm',
|
||||
'nsFilePicker.mm',
|
||||
'nsIdleServiceX.mm',
|
||||
'nsLookAndFeel.mm',
|
||||
@@ -44,7 +43,6 @@ UNIFIED_SOURCES += [
|
||||
'nsMenuItemX.mm',
|
||||
'nsMenuUtilsX.mm',
|
||||
'nsMenuX.mm',
|
||||
'nsNativeThemeCocoa.mm',
|
||||
'nsPrintDialogX.mm',
|
||||
'nsPrintOptionsX.mm',
|
||||
'nsPrintSettingsX.mm',
|
||||
@@ -57,6 +55,7 @@ UNIFIED_SOURCES += [
|
||||
'nsWidgetFactory.mm',
|
||||
'nsWindowMap.mm',
|
||||
'OSXNotificationCenter.mm',
|
||||
'SwipeTracker.mm',
|
||||
'TextInputHandler.mm',
|
||||
'VibrancyManager.mm',
|
||||
'WidgetTraceEvent.mm',
|
||||
@@ -67,9 +66,11 @@ SOURCES += [
|
||||
'nsChildView.mm',
|
||||
'nsClipboard.mm',
|
||||
'nsCocoaDebugUtils.mm',
|
||||
'nsDragService.mm',
|
||||
'nsNativeThemeCocoa.mm',
|
||||
]
|
||||
|
||||
if not CONFIG['RELEASE_BUILD'] or CONFIG['DEBUG']:
|
||||
if not CONFIG['RELEASE_BUILD'] or CONFIG['MOZ_DEBUG']:
|
||||
SOURCES += [
|
||||
'nsSandboxViolationSink.mm',
|
||||
]
|
||||
|
||||
+18
-11
@@ -42,8 +42,11 @@ class RectTextureImage;
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
class VibrancyManager;
|
||||
class InputData;
|
||||
class PanGestureInput;
|
||||
class SwipeTracker;
|
||||
struct SwipeEventQueue;
|
||||
class VibrancyManager;
|
||||
namespace layers {
|
||||
class GLManager;
|
||||
class APZCTreeManager;
|
||||
@@ -240,7 +243,6 @@ typedef NSInteger NSEventGestureAxis;
|
||||
#ifdef __LP64__
|
||||
// Support for fluid swipe tracking.
|
||||
BOOL* mCancelSwipeAnimation;
|
||||
uint32_t mCurrentSwipeDir;
|
||||
#endif
|
||||
|
||||
// Whether this uses off-main-thread compositing.
|
||||
@@ -306,14 +308,6 @@ typedef NSInteger NSEventGestureAxis;
|
||||
// Helper function for Lion smart magnify events
|
||||
+ (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent;
|
||||
|
||||
// Support for fluid swipe tracking.
|
||||
#ifdef __LP64__
|
||||
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
|
||||
scrollOverflowX:(double)anOverflowX
|
||||
scrollOverflowY:(double)anOverflowY
|
||||
viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled;
|
||||
#endif
|
||||
|
||||
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
|
||||
|
||||
- (NSEvent*)lastKeyDownEvent;
|
||||
@@ -554,7 +548,9 @@ public:
|
||||
|
||||
virtual nsIntPoint GetClientOffset() override;
|
||||
|
||||
mozilla::WidgetWheelEvent DispatchAPZWheelInputEvent(mozilla::InputData& aEvent);
|
||||
void DispatchAPZWheelInputEvent(mozilla::InputData& aEvent, bool aCanTriggerSwipe);
|
||||
|
||||
void SwipeFinished();
|
||||
|
||||
protected:
|
||||
virtual ~nsChildView();
|
||||
@@ -599,6 +595,15 @@ protected:
|
||||
virtual nsresult NotifyIMEInternal(
|
||||
const IMENotification& aIMENotification) override;
|
||||
|
||||
struct SwipeInfo {
|
||||
bool wantsSwipe;
|
||||
uint32_t allowedDirections;
|
||||
};
|
||||
|
||||
SwipeInfo SendMayStartSwipe(const mozilla::PanGestureInput& aSwipeStartEvent);
|
||||
void TrackScrollEventAsSwipe(const mozilla::PanGestureInput& aSwipeStartEvent,
|
||||
uint32_t aAllowedDirections);
|
||||
|
||||
protected:
|
||||
|
||||
NSView<mozView>* mView; // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG]
|
||||
@@ -664,6 +669,8 @@ protected:
|
||||
nsAutoPtr<GLPresenter> mGLPresenter;
|
||||
|
||||
mozilla::UniquePtr<mozilla::VibrancyManager> mVibrancyManager;
|
||||
nsRefPtr<mozilla::SwipeTracker> mSwipeTracker;
|
||||
mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
|
||||
|
||||
static uint32_t sLastInputEventCount;
|
||||
|
||||
|
||||
+137
-266
@@ -89,6 +89,7 @@
|
||||
#include "mozilla/layers/ChromeProcessController.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "InputData.h"
|
||||
#include "SwipeTracker.h"
|
||||
#include "VibrancyManager.h"
|
||||
#include "nsNativeThemeCocoa.h"
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
@@ -196,6 +197,8 @@ static uint32_t gNumberOfWidgetsNeedingEventThread = 0;
|
||||
- (BOOL)inactiveWindowAcceptsMouseEvent:(NSEvent*)aEvent;
|
||||
- (void)updateWindowDraggableState;
|
||||
|
||||
- (bool)shouldConsiderStartingSwipeFromEvent:(NSEvent*)aEvent;
|
||||
|
||||
@end
|
||||
|
||||
@interface EventThreadRunner : NSObject
|
||||
@@ -370,6 +373,21 @@ protected:
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct SwipeEventQueue {
|
||||
SwipeEventQueue(uint32_t aAllowedDirections, uint64_t aInputBlockId)
|
||||
: allowedDirections(aAllowedDirections)
|
||||
, inputBlockId(aInputBlockId)
|
||||
{}
|
||||
|
||||
nsTArray<PanGestureInput> queuedEvents;
|
||||
uint32_t allowedDirections;
|
||||
uint64_t inputBlockId;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#pragma mark -
|
||||
|
||||
nsChildView::nsChildView() : nsBaseWidget()
|
||||
@@ -395,6 +413,11 @@ nsChildView::~nsChildView()
|
||||
{
|
||||
ReleaseTitlebarCGContext();
|
||||
|
||||
if (mSwipeTracker) {
|
||||
mSwipeTracker->Destroy();
|
||||
mSwipeTracker = nullptr;
|
||||
}
|
||||
|
||||
// Notify the children that we're gone. childView->ResetParent() can change
|
||||
// our list of children while it's being iterated, so the way we iterate the
|
||||
// list must allow for this.
|
||||
@@ -948,6 +971,9 @@ nsChildView::BackingScaleFactorChanged()
|
||||
if (presShell) {
|
||||
presShell->BackingScaleFactorChanged();
|
||||
}
|
||||
// When the backing scale factor changes, so does our size in device pixels
|
||||
// (though not in display pixels).
|
||||
ReportSizeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2567,6 +2593,57 @@ nsChildView::EnsureVibrancyManager()
|
||||
return *mVibrancyManager;
|
||||
}
|
||||
|
||||
nsChildView::SwipeInfo
|
||||
nsChildView::SendMayStartSwipe(const mozilla::PanGestureInput& aSwipeStartEvent)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
|
||||
|
||||
uint32_t direction = (aSwipeStartEvent.mPanDisplacement.x > 0.0)
|
||||
? (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT
|
||||
: (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
|
||||
|
||||
// We're ready to start the animation. Tell Gecko about it, and at the same
|
||||
// time ask it if it really wants to start an animation for this event.
|
||||
// This event also reports back the directions that we can swipe in.
|
||||
LayoutDeviceIntPoint position =
|
||||
RoundedToInt(aSwipeStartEvent.mPanStartPoint * ScreenToLayoutDeviceScale(1));
|
||||
WidgetSimpleGestureEvent geckoEvent =
|
||||
SwipeTracker::CreateSwipeGestureEvent(NS_SIMPLE_GESTURE_SWIPE_START, this, position);
|
||||
geckoEvent.direction = direction;
|
||||
geckoEvent.delta = 0.0;
|
||||
geckoEvent.allowedDirections = 0;
|
||||
bool shouldStartSwipe = DispatchWindowEvent(geckoEvent); // event cancelled == swipe should start
|
||||
|
||||
SwipeInfo result = { shouldStartSwipe, geckoEvent.allowedDirections };
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsChildView::TrackScrollEventAsSwipe(const mozilla::PanGestureInput& aSwipeStartEvent,
|
||||
uint32_t aAllowedDirections)
|
||||
{
|
||||
// If a swipe is currently being tracked kill it -- it's been interrupted
|
||||
// by another gesture event.
|
||||
if (mSwipeTracker) {
|
||||
mSwipeTracker->CancelSwipe();
|
||||
mSwipeTracker->Destroy();
|
||||
mSwipeTracker = nullptr;
|
||||
}
|
||||
|
||||
uint32_t direction = (aSwipeStartEvent.mPanDisplacement.x > 0.0)
|
||||
? (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT
|
||||
: (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
|
||||
|
||||
mSwipeTracker = new SwipeTracker(*this, aSwipeStartEvent,
|
||||
aAllowedDirections, direction);
|
||||
}
|
||||
|
||||
void
|
||||
nsChildView::SwipeFinished()
|
||||
{
|
||||
mSwipeTracker = nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
nsChildView::StartRemoteDrawing()
|
||||
{
|
||||
@@ -2658,22 +2735,47 @@ nsChildView::UpdateWindowDraggingRegion(const nsIntRegion& aRegion)
|
||||
}
|
||||
}
|
||||
|
||||
WidgetWheelEvent
|
||||
nsChildView::DispatchAPZWheelInputEvent(InputData& aEvent)
|
||||
void
|
||||
nsChildView::DispatchAPZWheelInputEvent(InputData& aEvent, bool aCanTriggerSwipe)
|
||||
{
|
||||
if (mSwipeTracker && aEvent.mInputType == PANGESTURE_INPUT) {
|
||||
// Give the swipe tracker a first pass at the event. If a new pan gesture
|
||||
// has been started since the beginning of the swipe, the swipe tracker
|
||||
// will know to ignore the event.
|
||||
nsEventStatus status = mSwipeTracker->ProcessEvent(aEvent.AsPanGestureInput());
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WidgetWheelEvent event(true, NS_WHEEL_WHEEL, this);
|
||||
|
||||
if (mAPZC) {
|
||||
uint64_t inputBlockId = 0;
|
||||
ScrollableLayerGuid guid;
|
||||
|
||||
nsEventStatus result = mAPZC->ReceiveInputEvent(aEvent, &guid, &inputBlockId);
|
||||
if (result == nsEventStatus_eConsumeNoDefault) {
|
||||
return event;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(aEvent.mInputType) {
|
||||
case PANGESTURE_INPUT: {
|
||||
event = aEvent.AsPanGestureInput().ToWidgetWheelEvent(this);
|
||||
PanGestureInput& panInput = aEvent.AsPanGestureInput();
|
||||
|
||||
event = panInput.ToWidgetWheelEvent(this);
|
||||
if (aCanTriggerSwipe) {
|
||||
SwipeInfo swipeInfo = SendMayStartSwipe(panInput);
|
||||
event.mCanTriggerSwipe = swipeInfo.wantsSwipe;
|
||||
if (swipeInfo.wantsSwipe) {
|
||||
mSwipeEventQueue = MakeUnique<SwipeEventQueue>(swipeInfo.allowedDirections,
|
||||
inputBlockId);
|
||||
}
|
||||
}
|
||||
|
||||
if (mSwipeEventQueue && mSwipeEventQueue->inputBlockId == inputBlockId) {
|
||||
mSwipeEventQueue->queuedEvents.AppendElement(panInput);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCROLLWHEEL_INPUT: {
|
||||
@@ -2682,19 +2784,29 @@ nsChildView::DispatchAPZWheelInputEvent(InputData& aEvent)
|
||||
};
|
||||
default:
|
||||
MOZ_CRASH("unsupported event type");
|
||||
return event;
|
||||
return;
|
||||
}
|
||||
if (event.mMessage == NS_WHEEL_WHEEL &&
|
||||
(event.deltaX != 0 || event.deltaY != 0)) {
|
||||
ProcessUntransformedAPZEvent(&event, guid, inputBlockId, result);
|
||||
}
|
||||
return event;
|
||||
return;
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
switch(aEvent.mInputType) {
|
||||
case PANGESTURE_INPUT: {
|
||||
event = aEvent.AsPanGestureInput().ToWidgetWheelEvent(this);
|
||||
PanGestureInput panInput = aEvent.AsPanGestureInput();
|
||||
event = panInput.ToWidgetWheelEvent(this);
|
||||
if (aCanTriggerSwipe) {
|
||||
SwipeInfo swipeInfo = SendMayStartSwipe(panInput);
|
||||
event.mCanTriggerSwipe = swipeInfo.wantsSwipe;
|
||||
DispatchEvent(&event, status);
|
||||
if (event.TriggersSwipe()) {
|
||||
TrackScrollEventAsSwipe(panInput, swipeInfo.allowedDirections);
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCROLLWHEEL_INPUT: {
|
||||
@@ -2703,13 +2815,12 @@ nsChildView::DispatchAPZWheelInputEvent(InputData& aEvent)
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("unexpected event type");
|
||||
return event;
|
||||
return;
|
||||
}
|
||||
if (event.mMessage == NS_WHEEL_WHEEL &&
|
||||
(event.deltaX != 0 || event.deltaY != 0)) {
|
||||
DispatchEvent(&event, status);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
@@ -3068,7 +3179,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
||||
|
||||
#ifdef __LP64__
|
||||
mCancelSwipeAnimation = nil;
|
||||
mCurrentSwipeDir = 0;
|
||||
#endif
|
||||
|
||||
mTopLeftCornerMask = NULL;
|
||||
@@ -4236,55 +4346,10 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
||||
[anEvent subtype] == 0x16;
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
- (bool)sendSwipeEvent:(NSEvent*)aEvent
|
||||
withKind:(EventMessage)aMsg
|
||||
allowedDirections:(uint32_t*)aAllowedDirections
|
||||
direction:(uint32_t)aDirection
|
||||
delta:(double)aDelta
|
||||
{
|
||||
if (!mGeckoChild)
|
||||
return false;
|
||||
|
||||
WidgetSimpleGestureEvent geckoEvent(true, aMsg, mGeckoChild);
|
||||
geckoEvent.direction = aDirection;
|
||||
geckoEvent.delta = aDelta;
|
||||
geckoEvent.allowedDirections = *aAllowedDirections;
|
||||
[self convertCocoaMouseEvent:aEvent toGeckoEvent:&geckoEvent];
|
||||
bool eventCancelled = mGeckoChild->DispatchWindowEvent(geckoEvent);
|
||||
*aAllowedDirections = geckoEvent.allowedDirections;
|
||||
return eventCancelled; // event cancelled == swipe should start
|
||||
}
|
||||
|
||||
- (void)sendSwipeEndEvent:(NSEvent *)anEvent
|
||||
allowedDirections:(uint32_t)aAllowedDirections
|
||||
{
|
||||
// Tear down animation overlay by sending a swipe end event.
|
||||
uint32_t allowedDirectionsCopy = aAllowedDirections;
|
||||
[self sendSwipeEvent:anEvent
|
||||
withKind:NS_SIMPLE_GESTURE_SWIPE_END
|
||||
allowedDirections:&allowedDirectionsCopy
|
||||
direction:0
|
||||
delta:0.0];
|
||||
}
|
||||
|
||||
// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful
|
||||
// to only invoke this support on a two-finger gesture that really
|
||||
// is a swipe (and not a scroll) -- in other words, the app is responsible
|
||||
// for deciding which is which. But once the decision is made, the OS tracks
|
||||
// the swipe until it has finished, and decides whether or not it succeeded.
|
||||
// A horizontal swipe has the same functionality as the Back and Forward
|
||||
// buttons.
|
||||
// This method is partly based on Apple sample code available at
|
||||
// developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html
|
||||
// (under Fluid Swipe Tracking API).
|
||||
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
|
||||
scrollOverflowX:(double)anOverflowX
|
||||
scrollOverflowY:(double)anOverflowY
|
||||
viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled
|
||||
- (bool)shouldConsiderStartingSwipeFromEvent:(NSEvent*)anEvent
|
||||
{
|
||||
if (!nsCocoaFeatures::OnLionOrLater()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This method checks whether the AppleEnableSwipeNavigateWithScrolls global
|
||||
@@ -4293,207 +4358,29 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
||||
// preference can't (currently) be set from the Preferences UI -- only using
|
||||
// 'defaults write'.
|
||||
if (![NSEvent isSwipeTrackingFromScrollEventsEnabled]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should only track scroll events as swipe if the viewport is being
|
||||
// overscrolled.
|
||||
if (!aViewPortIsOverscrolled) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only initiate horizontal tracking for gestures that have just begun --
|
||||
// otherwise a scroll to one side of the page can have a swipe tacked on
|
||||
// to it.
|
||||
NSEventPhase eventPhase = nsCocoaUtils::EventPhase(anEvent);
|
||||
// Verify that this is a scroll wheel event with proper phase to be tracked
|
||||
// by the OS.
|
||||
if ([anEvent type] != NSScrollWheel || eventPhase == NSEventPhaseNone) {
|
||||
return;
|
||||
if ([anEvent type] != NSScrollWheel ||
|
||||
eventPhase != NSEventPhaseBegan ||
|
||||
![anEvent hasPreciseScrollingDeltas]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only initiate tracking if the user has tried to scroll past the edge of
|
||||
// the current page (as indicated by 'anOverflowX' or 'anOverflowY' being
|
||||
// non-zero). Gecko only sets WidgetMouseScrollEvent.scrollOverflow when it's
|
||||
// processing NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
|
||||
if (anOverflowX == 0.0 && anOverflowY == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat deltaX, deltaY;
|
||||
if ([anEvent hasPreciseScrollingDeltas]) {
|
||||
deltaX = [anEvent scrollingDeltaX];
|
||||
deltaY = [anEvent scrollingDeltaY];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t vDirs = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN |
|
||||
(uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
|
||||
uint32_t direction = 0;
|
||||
|
||||
// Only initiate horizontal tracking for events whose horizontal element is
|
||||
// at least eight times larger than its vertical element. This minimizes
|
||||
// performance problems with vertical scrolls (by minimizing the possibility
|
||||
// that they'll be misinterpreted as horizontal swipes), while still
|
||||
// tolerating a small vertical element to a true horizontal swipe. The number
|
||||
// '8' was arrived at by trial and error.
|
||||
if (anOverflowX != 0.0 && deltaX != 0.0 &&
|
||||
std::abs(deltaX) > std::abs(deltaY) * 8) {
|
||||
// Only initiate horizontal tracking for gestures that have just begun --
|
||||
// otherwise a scroll to one side of the page can have a swipe tacked on
|
||||
// to it.
|
||||
if (eventPhase != NSEventPhaseBegan) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (deltaX < 0.0) {
|
||||
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
|
||||
} else {
|
||||
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
|
||||
}
|
||||
}
|
||||
// Only initiate vertical tracking for events whose vertical element is
|
||||
// at least two times larger than its horizontal element. This minimizes
|
||||
// performance problems. The number '2' was arrived at by trial and error.
|
||||
else if (anOverflowY != 0.0 && deltaY != 0.0 &&
|
||||
std::abs(deltaY) > std::abs(deltaX) * 2) {
|
||||
if (deltaY < 0.0) {
|
||||
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
|
||||
} else {
|
||||
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
|
||||
}
|
||||
|
||||
if ((mCurrentSwipeDir & vDirs) && (mCurrentSwipeDir != direction)) {
|
||||
// If a swipe is currently being tracked kill it -- it's been interrupted
|
||||
// by another gesture event.
|
||||
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
|
||||
*mCancelSwipeAnimation = YES;
|
||||
mCancelSwipeAnimation = nil;
|
||||
[self sendSwipeEndEvent:anEvent allowedDirections:0];
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Track the direction we're going in.
|
||||
mCurrentSwipeDir = direction;
|
||||
|
||||
uint32_t allowedDirections = 0;
|
||||
// We're ready to start the animation. Tell Gecko about it, and at the same
|
||||
// time ask it if it really wants to start an animation for this event.
|
||||
// This event also reports back the directions that we can swipe in.
|
||||
bool shouldStartSwipe = [self sendSwipeEvent:anEvent
|
||||
withKind:NS_SIMPLE_GESTURE_SWIPE_START
|
||||
allowedDirections:&allowedDirections
|
||||
direction:direction
|
||||
delta:0.0];
|
||||
|
||||
if (!shouldStartSwipe) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a swipe is currently being tracked kill it -- it's been interrupted
|
||||
// by another gesture event.
|
||||
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
|
||||
*mCancelSwipeAnimation = YES;
|
||||
mCancelSwipeAnimation = nil;
|
||||
}
|
||||
|
||||
CGFloat min = 0.0;
|
||||
CGFloat max = 0.0;
|
||||
if (!(direction & vDirs)) {
|
||||
min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ?
|
||||
-1.0 : 0.0;
|
||||
max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ?
|
||||
1.0 : 0.0;
|
||||
}
|
||||
|
||||
__block BOOL animationCanceled = NO;
|
||||
__block BOOL geckoSwipeEventSent = NO;
|
||||
// At this point, anEvent is the first scroll wheel event in a two-finger
|
||||
// horizontal gesture that we've decided to treat as a swipe. When we call
|
||||
// [NSEvent trackSwipeEventWithOptions:...], the OS interprets all
|
||||
// subsequent scroll wheel events that are part of this gesture as a swipe,
|
||||
// and stops sending them to us. The OS calls the trackingHandler "block"
|
||||
// multiple times, asynchronously (sometimes after [NSEvent
|
||||
// maybeTrackScrollEventAsSwipe:...] has returned). The OS determines when
|
||||
// the gesture has finished, and whether or not it was "successful" -- this
|
||||
// information is passed to trackingHandler. We must be careful to only
|
||||
// call [NSEvent maybeTrackScrollEventAsSwipe:...] on a "real" swipe --
|
||||
// otherwise two-finger scrolling performance will suffer significantly.
|
||||
// Note that we use anEvent inside the block. This extends the lifetime of
|
||||
// the anEvent object because it's retained by the block, see bug 682445.
|
||||
// The block will release it when the block goes away at the end of the
|
||||
// animation, or when the animation is canceled.
|
||||
[anEvent trackSwipeEventWithOptions:NSEventSwipeTrackingLockDirection |
|
||||
NSEventSwipeTrackingClampGestureAmount
|
||||
dampenAmountThresholdMin:min
|
||||
max:max
|
||||
usingHandler:^(CGFloat gestureAmount,
|
||||
NSEventPhase phase,
|
||||
BOOL isComplete,
|
||||
BOOL *stop) {
|
||||
uint32_t allowedDirectionsCopy = allowedDirections;
|
||||
// Since this tracking handler can be called asynchronously, mGeckoChild
|
||||
// might have become NULL here (our child widget might have been
|
||||
// destroyed).
|
||||
// Checking for gestureAmount == 0.0 also works around bug 770626, which
|
||||
// happens when DispatchWindowEvent() triggers a modal dialog, which spins
|
||||
// the event loop and confuses the OS. This results in several re-entrant
|
||||
// calls to this handler.
|
||||
if (animationCanceled || !mGeckoChild || gestureAmount == 0.0) {
|
||||
*stop = YES;
|
||||
animationCanceled = YES;
|
||||
if (gestureAmount == 0.0 ||
|
||||
((direction & vDirs) && (direction != mCurrentSwipeDir))) {
|
||||
if (mCancelSwipeAnimation)
|
||||
*mCancelSwipeAnimation = YES;
|
||||
mCancelSwipeAnimation = nil;
|
||||
[self sendSwipeEndEvent:anEvent
|
||||
allowedDirections:allowedDirectionsCopy];
|
||||
}
|
||||
mCurrentSwipeDir = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Update animation overlay to match gestureAmount.
|
||||
[self sendSwipeEvent:anEvent
|
||||
withKind:NS_SIMPLE_GESTURE_SWIPE_UPDATE
|
||||
allowedDirections:&allowedDirectionsCopy
|
||||
direction:0.0
|
||||
delta:gestureAmount];
|
||||
|
||||
if (phase == NSEventPhaseEnded && !geckoSwipeEventSent) {
|
||||
// The result of the swipe is now known, so the main event can be sent.
|
||||
// The animation might continue even after this event was sent, so
|
||||
// don't tear down the animation overlay yet.
|
||||
|
||||
uint32_t directionCopy = direction;
|
||||
|
||||
// gestureAmount is documented to be '-1', '0' or '1' when isComplete
|
||||
// is TRUE, but the docs don't say anything about its value at other
|
||||
// times. However, tests show that, when phase == NSEventPhaseEnded,
|
||||
// gestureAmount is negative when it will be '-1' at isComplete, and
|
||||
// positive when it will be '1'. And phase is never equal to
|
||||
// NSEventPhaseEnded when gestureAmount will be '0' at isComplete.
|
||||
geckoSwipeEventSent = YES;
|
||||
[self sendSwipeEvent:anEvent
|
||||
withKind:NS_SIMPLE_GESTURE_SWIPE
|
||||
allowedDirections:&allowedDirectionsCopy
|
||||
direction:directionCopy
|
||||
delta:0.0];
|
||||
}
|
||||
|
||||
if (isComplete) {
|
||||
[self sendSwipeEndEvent:anEvent allowedDirections:allowedDirectionsCopy];
|
||||
mCurrentSwipeDir = 0;
|
||||
mCancelSwipeAnimation = nil;
|
||||
}
|
||||
}];
|
||||
|
||||
mCancelSwipeAnimation = &animationCanceled;
|
||||
CGFloat deltaX = [anEvent scrollingDeltaX];
|
||||
CGFloat deltaY = [anEvent scrollingDeltaY];
|
||||
return std::abs(deltaX) > std::abs(deltaY) * 8;
|
||||
}
|
||||
#endif // #ifdef __LP64__
|
||||
|
||||
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC
|
||||
{
|
||||
@@ -4978,8 +4865,6 @@ PanGestureTypeForEvent(NSEvent* aEvent)
|
||||
|
||||
Modifiers modifiers = nsCocoaUtils::ModifiersForEvent(theEvent);
|
||||
|
||||
WidgetWheelEvent widgetWheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
|
||||
|
||||
NSTimeInterval beforeNow = [[NSProcessInfo processInfo] systemUptime] - [theEvent timestamp];
|
||||
PRIntervalTime eventIntervalTime = PR_IntervalNow() - PR_MillisecondsToInterval(beforeNow * 1000);
|
||||
TimeStamp eventTimeStamp = TimeStamp::Now() - TimeDuration::FromSeconds(beforeNow);
|
||||
@@ -4998,23 +4883,9 @@ PanGestureTypeForEvent(NSEvent* aEvent)
|
||||
position, preciseDelta, modifiers);
|
||||
panEvent.mLineOrPageDeltaX = lineOrPageDeltaX;
|
||||
panEvent.mLineOrPageDeltaY = lineOrPageDeltaY;
|
||||
widgetWheelEvent = mGeckoChild->DispatchAPZWheelInputEvent(panEvent);
|
||||
|
||||
if (!mGeckoChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
if ((widgetWheelEvent.deltaX != 0.0 || widgetWheelEvent.deltaY != 0.0)) {
|
||||
// overflowDeltaX and overflowDeltaY tell us when the user has tried to
|
||||
// scroll past the edge of a page (in those cases it's non-zero).
|
||||
[self maybeTrackScrollEventAsSwipe:theEvent
|
||||
scrollOverflowX:widgetWheelEvent.overflowDeltaX
|
||||
scrollOverflowY:widgetWheelEvent.overflowDeltaY
|
||||
viewPortIsOverscrolled:widgetWheelEvent.mViewPortIsOverscrolled];
|
||||
}
|
||||
#endif // #ifdef __LP64__
|
||||
|
||||
bool canTriggerSwipe = [self shouldConsiderStartingSwipeFromEvent:theEvent];
|
||||
mGeckoChild->DispatchAPZWheelInputEvent(panEvent, canTriggerSwipe);
|
||||
} else if (usePreciseDeltas) {
|
||||
// This is on 10.6 or old touchpads that don't have any phase information.
|
||||
ScrollWheelInput wheelEvent(eventIntervalTime, eventTimeStamp, modifiers,
|
||||
@@ -5026,7 +4897,7 @@ PanGestureTypeForEvent(NSEvent* aEvent)
|
||||
wheelEvent.mLineOrPageDeltaX = lineOrPageDeltaX;
|
||||
wheelEvent.mLineOrPageDeltaY = lineOrPageDeltaY;
|
||||
wheelEvent.mIsMomentum = nsCocoaUtils::IsMomentumScrollEvent(theEvent);
|
||||
widgetWheelEvent = mGeckoChild->DispatchAPZWheelInputEvent(wheelEvent);
|
||||
mGeckoChild->DispatchAPZWheelInputEvent(wheelEvent, false);
|
||||
} else {
|
||||
ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT;
|
||||
if (gfxPrefs::SmoothScrollEnabled() && gfxPrefs::WheelSmoothScrollEnabled()) {
|
||||
@@ -5040,7 +4911,7 @@ PanGestureTypeForEvent(NSEvent* aEvent)
|
||||
lineOrPageDeltaY);
|
||||
wheelEvent.mLineOrPageDeltaX = lineOrPageDeltaX;
|
||||
wheelEvent.mLineOrPageDeltaY = lineOrPageDeltaY;
|
||||
widgetWheelEvent = mGeckoChild->DispatchAPZWheelInputEvent(wheelEvent);
|
||||
mGeckoChild->DispatchAPZWheelInputEvent(wheelEvent, false);
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
|
||||
@@ -328,8 +328,12 @@ public:
|
||||
*/
|
||||
static void InitInputEvent(mozilla::WidgetInputEvent &aInputEvent,
|
||||
NSEvent* aNativeEvent);
|
||||
static void InitInputEvent(mozilla::WidgetInputEvent &aInputEvent,
|
||||
NSUInteger aModifiers);
|
||||
|
||||
/**
|
||||
* Converts the native modifiers from aNativeEvent into WidgetMouseEvent
|
||||
* Modifiers. aNativeEvent can be null.
|
||||
*/
|
||||
static mozilla::Modifiers ModifiersForEvent(NSEvent* aNativeEvent);
|
||||
|
||||
/**
|
||||
* ConvertToCarbonModifier() returns carbon modifier flags for the cocoa
|
||||
|
||||
@@ -617,40 +617,38 @@ nsCocoaUtils::InitInputEvent(WidgetInputEvent& aInputEvent,
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
NSUInteger modifiers =
|
||||
aNativeEvent ? [aNativeEvent modifierFlags] : [NSEvent modifierFlags];
|
||||
InitInputEvent(aInputEvent, modifiers);
|
||||
|
||||
aInputEvent.modifiers = ModifiersForEvent(aNativeEvent);
|
||||
aInputEvent.time = PR_IntervalNow();
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsCocoaUtils::InitInputEvent(WidgetInputEvent& aInputEvent,
|
||||
NSUInteger aModifiers)
|
||||
Modifiers
|
||||
nsCocoaUtils::ModifiersForEvent(NSEvent* aNativeEvent)
|
||||
{
|
||||
aInputEvent.modifiers = 0;
|
||||
if (aModifiers & NSShiftKeyMask) {
|
||||
aInputEvent.modifiers |= MODIFIER_SHIFT;
|
||||
NSUInteger modifiers =
|
||||
aNativeEvent ? [aNativeEvent modifierFlags] : [NSEvent modifierFlags];
|
||||
Modifiers result = 0;
|
||||
if (modifiers & NSShiftKeyMask) {
|
||||
result |= MODIFIER_SHIFT;
|
||||
}
|
||||
if (aModifiers & NSControlKeyMask) {
|
||||
aInputEvent.modifiers |= MODIFIER_CONTROL;
|
||||
if (modifiers & NSControlKeyMask) {
|
||||
result |= MODIFIER_CONTROL;
|
||||
}
|
||||
if (aModifiers & NSAlternateKeyMask) {
|
||||
aInputEvent.modifiers |= MODIFIER_ALT;
|
||||
if (modifiers & NSAlternateKeyMask) {
|
||||
result |= MODIFIER_ALT;
|
||||
// Mac's option key is similar to other platforms' AltGr key.
|
||||
// Let's set AltGr flag when option key is pressed for consistency with
|
||||
// other platforms.
|
||||
aInputEvent.modifiers |= MODIFIER_ALTGRAPH;
|
||||
result |= MODIFIER_ALTGRAPH;
|
||||
}
|
||||
if (aModifiers & NSCommandKeyMask) {
|
||||
aInputEvent.modifiers |= MODIFIER_META;
|
||||
if (modifiers & NSCommandKeyMask) {
|
||||
result |= MODIFIER_META;
|
||||
}
|
||||
|
||||
if (aModifiers & NSAlphaShiftKeyMask) {
|
||||
aInputEvent.modifiers |= MODIFIER_CAPSLOCK;
|
||||
if (modifiers & NSAlphaShiftKeyMask) {
|
||||
result |= MODIFIER_CAPSLOCK;
|
||||
}
|
||||
// Mac doesn't have NumLock key. We can assume that NumLock is always locked
|
||||
// if user is using a keyboard which has numpad. Otherwise, if user is using
|
||||
@@ -660,14 +658,15 @@ nsCocoaUtils::InitInputEvent(WidgetInputEvent& aInputEvent,
|
||||
// We should notify locked state only when keys in numpad are pressed.
|
||||
// By this, web applications may not be confused by unexpected numpad key's
|
||||
// key event with unlocked state.
|
||||
if (aModifiers & NSNumericPadKeyMask) {
|
||||
aInputEvent.modifiers |= MODIFIER_NUMLOCK;
|
||||
if (modifiers & NSNumericPadKeyMask) {
|
||||
result |= MODIFIER_NUMLOCK;
|
||||
}
|
||||
|
||||
// Be aware, NSFunctionKeyMask is included when arrow keys, home key or some
|
||||
// other keys are pressed. We cannot check whether 'fn' key is pressed or
|
||||
// not by the flag.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -1591,6 +1591,9 @@ nsCocoaWindow::BackingScaleFactorChanged()
|
||||
if (presShell) {
|
||||
presShell->BackingScaleFactorChanged();
|
||||
}
|
||||
// When the backing scale factor changes, so does our size in device pixels
|
||||
// (though not in display pixels).
|
||||
ReportSizeEvent();
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
||||
@@ -136,6 +136,7 @@ struct ParamTraits<mozilla::WidgetMouseEventBase>
|
||||
WriteParam(aMsg, aParam.button);
|
||||
WriteParam(aMsg, aParam.buttons);
|
||||
WriteParam(aMsg, aParam.pressure);
|
||||
WriteParam(aMsg, aParam.hitCluster);
|
||||
WriteParam(aMsg, aParam.inputSource);
|
||||
}
|
||||
|
||||
@@ -146,6 +147,7 @@ struct ParamTraits<mozilla::WidgetMouseEventBase>
|
||||
ReadParam(aMsg, aIter, &aResult->button) &&
|
||||
ReadParam(aMsg, aIter, &aResult->buttons) &&
|
||||
ReadParam(aMsg, aIter, &aResult->pressure) &&
|
||||
ReadParam(aMsg, aIter, &aResult->hitCluster) &&
|
||||
ReadParam(aMsg, aIter, &aResult->inputSource);
|
||||
}
|
||||
};
|
||||
@@ -170,6 +172,8 @@ struct ParamTraits<mozilla::WidgetWheelEvent>
|
||||
WriteParam(aMsg, static_cast<int32_t>(aParam.scrollType));
|
||||
WriteParam(aMsg, aParam.overflowDeltaX);
|
||||
WriteParam(aMsg, aParam.overflowDeltaY);
|
||||
WriteParam(aMsg, aParam.mViewPortIsOverscrolled);
|
||||
WriteParam(aMsg, aParam.mCanTriggerSwipe);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
@@ -189,7 +193,9 @@ struct ParamTraits<mozilla::WidgetWheelEvent>
|
||||
ReadParam(aMsg, aIter, &aResult->lineOrPageDeltaY) &&
|
||||
ReadParam(aMsg, aIter, &scrollType) &&
|
||||
ReadParam(aMsg, aIter, &aResult->overflowDeltaX) &&
|
||||
ReadParam(aMsg, aIter, &aResult->overflowDeltaY);
|
||||
ReadParam(aMsg, aIter, &aResult->overflowDeltaY) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mViewPortIsOverscrolled) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mCanTriggerSwipe);
|
||||
aResult->scrollType =
|
||||
static_cast<mozilla::WidgetWheelEvent::ScrollType>(scrollType);
|
||||
return rv;
|
||||
|
||||
+3
-2
@@ -101,6 +101,8 @@ typedef void* nsNativeWidget;
|
||||
// HWND on Windows and XID on X11
|
||||
#define NS_NATIVE_SHAREABLE_WINDOW 11
|
||||
#define NS_NATIVE_OPENGL_CONTEXT 12
|
||||
// See RegisterPluginWindowForRemoteUpdates
|
||||
#define NS_NATIVE_PLUGIN_ID 13
|
||||
#ifdef XP_MACOSX
|
||||
#define NS_NATIVE_PLUGIN_PORT_QD 100
|
||||
#define NS_NATIVE_PLUGIN_PORT_CG 101
|
||||
@@ -111,13 +113,12 @@ typedef void* nsNativeWidget;
|
||||
#define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
|
||||
#define NS_NATIVE_ICOREWINDOW 103 // winrt specific
|
||||
#define NS_NATIVE_CHILD_WINDOW 104
|
||||
#define NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW 105
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
// set/get nsPluginNativeWindowGtk, e10s specific
|
||||
#define NS_NATIVE_PLUGIN_OBJECT_PTR 104
|
||||
#endif
|
||||
// See RegisterPluginWindowForRemoteUpdates
|
||||
#define NS_NATIVE_PLUGIN_ID 105
|
||||
|
||||
#define NS_IWIDGET_IID \
|
||||
{ 0x483BF75C, 0xF909, 0x45C3, \
|
||||
|
||||
+20
-13
@@ -2938,24 +2938,31 @@ void* nsWindow::GetNativeData(uint32_t aDataType)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
SetChildStyleAndParent(HWND aChildWindow, HWND aParentWindow)
|
||||
{
|
||||
// Make sure the window is styled to be a child window.
|
||||
LONG_PTR style = GetWindowLongPtr(aChildWindow, GWL_STYLE);
|
||||
style |= WS_CHILD;
|
||||
style &= ~WS_POPUP;
|
||||
SetWindowLongPtr(aChildWindow, GWL_STYLE, style);
|
||||
|
||||
// Do the reparenting. Note that this call will probably cause a sync native
|
||||
// message to the process that owns the child window.
|
||||
::SetParent(aChildWindow, aParentWindow);
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
|
||||
{
|
||||
switch (aDataType) {
|
||||
case NS_NATIVE_CHILD_WINDOW:
|
||||
{
|
||||
HWND childWindow = reinterpret_cast<HWND>(aVal);
|
||||
|
||||
// Make sure the window is styled to be a child window.
|
||||
LONG_PTR style = GetWindowLongPtr(childWindow, GWL_STYLE);
|
||||
style |= WS_CHILD;
|
||||
style &= ~WS_POPUP;
|
||||
SetWindowLongPtr(childWindow, GWL_STYLE, style);
|
||||
|
||||
// Do the reparenting.
|
||||
::SetParent(childWindow, mWnd);
|
||||
break;
|
||||
}
|
||||
SetChildStyleAndParent(reinterpret_cast<HWND>(aVal), mWnd);
|
||||
break;
|
||||
case NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW:
|
||||
SetChildStyleAndParent(reinterpret_cast<HWND>(aVal),
|
||||
WinUtils::GetTopLevelHWND(mWnd));
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("SetNativeData called with unsupported data type.");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ SOURCES += [
|
||||
]
|
||||
|
||||
DEFINES['XULRUNNER_PROGNAME'] = '"xulrunner"'
|
||||
if CONFIG['DEBUG']:
|
||||
if CONFIG['MOZ_DEBUG']:
|
||||
DEFINES['DEBUG'] = True
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
||||
Reference in New Issue
Block a user