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:
2022-02-02 12:04:50 +08:00
parent abb8daa3fe
commit e9ba40cf6b
76 changed files with 3506 additions and 2359 deletions
+8 -1
View File
@@ -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);
+2 -2
View File
@@ -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
+18 -8
View File
@@ -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);
}
}
}
}
}
+6
View File
@@ -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();
}
+21 -2
View File
@@ -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;
+13
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-13
View File
@@ -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;
}
+90 -18
View File
@@ -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
+9
View File
@@ -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;
+13 -4
View File
@@ -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();
+79 -74
View File
@@ -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
+8 -2
View File
@@ -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;
+99 -24
View File
@@ -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
+10
View File
@@ -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;
+2 -47
View File
@@ -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
+1 -55
View File
@@ -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; }
+15 -1
View File
@@ -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.
+9
View File
@@ -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;
+69
View File
@@ -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 */
+69
View File
@@ -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
+4 -1
View File
@@ -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
+2
View File
@@ -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',
+9 -16
View File
@@ -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
+1 -1
View File
@@ -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);
-5
View File
@@ -120,11 +120,6 @@ public:
return (def == *this);
}
bool IsRootScrollable() const
{
return mIsRootContent;
}
bool IsScrollable() const
{
return mScrollId != NULL_SCROLL_ID;
+119 -51
View File
@@ -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
+1 -1
View File
@@ -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,
+52 -21
View File
@@ -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);
+7 -6
View File
@@ -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);
+1 -3
View File
@@ -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);
}
+1 -4
View File
@@ -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
+46 -25
View File
@@ -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;
+3
View File
@@ -166,6 +166,9 @@ public:
/* Notify content that the repaint flush is complete. */
static void NotifyFlushComplete();
private:
static uint64_t sLastTargetAPZCNotificationInputBlock;
};
} // namespace layers
+5 -1
View File
@@ -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);
}
+1
View File
@@ -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
View File
@@ -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 {
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -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));
+2 -1
View File
@@ -291,7 +291,8 @@ function isRootedGCPointerTypeName(name)
name == "WrappableJSErrorResult" ||
name == "frontend::TokenStream" ||
name == "frontend::TokenStream::Position" ||
name == "ModuleCompiler")
name == "ModuleCompiler" ||
name == "ModuleValidator")
{
return true;
}
+1 -1
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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,
+2 -2
View File
@@ -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);
+284
View File
@@ -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));
}
+62
View File
@@ -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
+12 -2
View File
@@ -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 =
+39
View File
@@ -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
+2 -2
View File
@@ -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;
+1
View File
@@ -112,6 +112,7 @@ UNIFIED_SOURCES += [
'GeometryUtils.cpp',
'LayoutLogging.cpp',
'MaskLayerImageCache.cpp',
'MobileViewportManager.cpp',
'nsBidi.cpp',
'nsBidiPresUtils.cpp',
'nsCaret.cpp',
+8 -3
View File
@@ -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.
+32
View File
@@ -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);
}
+6 -4
View File
@@ -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;
+7 -3
View File
@@ -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.
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+16
View File
@@ -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;
}
};
+17
View File
@@ -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()
{
+3
View File
@@ -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; }
+96
View File
@@ -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
+219
View File
@@ -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
+4 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+6 -2
View File
@@ -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
+20 -21
View File
@@ -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
+3
View File
@@ -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
+7 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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.");
}
+1 -1
View File
@@ -13,7 +13,7 @@ SOURCES += [
]
DEFINES['XULRUNNER_PROGNAME'] = '"xulrunner"'
if CONFIG['DEBUG']:
if CONFIG['MOZ_DEBUG']:
DEFINES['DEBUG'] = True
LOCAL_INCLUDES += [