Merge b2g28 to v1.3t. a=merge
B2G_1_3T_20140317_MERGEDAY
Merge b2g28 to v1.3t. a=merge
--- a/.hgtags
+++ b/.hgtags
@@ -93,8 +93,9 @@ 5bb309998e7050c9ee80b0147de1e473f008e221
cc37417e2c284aed960f98ffa479de4ccdd5c7c3 FIREFOX_AURORA_21_BASE
1c070ab0f9db59f13423b9c1db60419f7a9098f9 FIREFOX_AURORA_22_BASE
d7ce9089999719d5186595d160f25123a4e63e39 FIREFOX_AURORA_23_BASE
8d3810543edccf4fbe458178b88dd4a6e420b010 FIREFOX_AURORA_24_BASE
ad0ae007aa9e03cd74e9005cd6652e544139b3b5 FIREFOX_AURORA_25_BASE
2520866d58740851d862c7c59246a4e3f8b4a176 FIREFOX_AURORA_26_BASE
05025f4889a0bf4dc99ce0c244c750adc002f015 FIREFOX_AURORA_27_BASE
d3997dda8ddc87fe632a7836982098584d5634b7 B2G_1_3_20140203_MERGEDAY
+e2c448e8e3b4a78fec0b37e9a078aaa254bac27b B2G_1_3_20140317_MERGEDAY
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="15d69a6789c638709911507f74d25c0425963636">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
<project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
"remote": "",
"branch": "",
"revision": ""
},
- "revision": "947ff99ea34ba2478cbd9a99aa503bae0f03f375",
+ "revision": "55b99ce9f94b47238f3fc6e5352f549dc462e918",
"repo_path": "/integration/gaia-1_3"
}
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="9c4d35857e6a2843aa240e1465aa51780eaf99f6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="9c4d35857e6a2843aa240e1465aa51780eaf99f6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="9c4d35857e6a2843aa240e1465aa51780eaf99f6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="9c4d35857e6a2843aa240e1465aa51780eaf99f6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="15d69a6789c638709911507f74d25c0425963636">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
<project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0ab8a9cbcef5f23cec904a3d7f7675e44de29951"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2ea2aab306bd1c941719160cdcb49ee9d755dc17"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7e006b3f770f7ca77d4b007e568ccd050bd1a89e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="9c4d35857e6a2843aa240e1465aa51780eaf99f6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="685f70050cb340e33811efe962b24d324c8f6f2f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -66,16 +66,17 @@
#include "PCOMContentPermissionRequestChild.h"
#include "PuppetWidget.h"
#include "StructuredCloneUtils.h"
#include "nsViewportInfo.h"
#include "JavaScriptChild.h"
#include "APZCCallbackHelper.h"
#include "nsILoadContext.h"
#include "ipc/nsGUIEventIPC.h"
+#include "UnitTransforms.h"
#ifdef DEBUG
#include "PCOMContentPermissionRequestChild.h"
#endif /* DEBUG */
#define BROWSER_ELEMENT_CHILD_SCRIPT \
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
@@ -339,17 +340,19 @@ TabChild::Observe(nsISupports *aSubject,
// calculate them properly using the actual metadata from the
// page.
SetCSSViewport(kDefaultViewportSize);
// 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.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
- mLastRootMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
+ mLastRootMetrics.mCompositionBounds = ParentLayerIntRect(
+ ParentLayerIntPoint(),
+ ViewAs<ParentLayerPixel>(mInnerSize, PixelCastJustification::ScreenToParentLayerForRoot));
mLastRootMetrics.mZoom = mLastRootMetrics.CalculateIntrinsicScale();
mLastRootMetrics.mDevPixelsPerCSSPixel = mWidget->GetDefaultScale();
// We use ScreenToLayerScale(1) below in order to turn the
// async zoom amount into the gecko zoom amount.
mLastRootMetrics.mCumulativeResolution =
mLastRootMetrics.mZoom / mLastRootMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
@@ -561,17 +564,19 @@ TabChild::HandlePossibleViewportChange()
float oldScreenWidth = mLastRootMetrics.mCompositionBounds.width;
if (!oldScreenWidth) {
oldScreenWidth = mInnerSize.width;
}
FrameMetrics metrics(mLastRootMetrics);
metrics.mViewport = CSSRect(CSSPoint(), viewport);
- metrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
+ metrics.mCompositionBounds = ParentLayerIntRect(
+ ParentLayerIntPoint(),
+ ViewAs<ParentLayerPixel>(mInnerSize, PixelCastJustification::ScreenToParentLayerForRoot));
// 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)
@@ -610,17 +615,17 @@ TabChild::HandlePossibleViewportChange()
// we have no idea how long painting will take.
metrics, ScreenPoint(0.0f, 0.0f), 0.0);
metrics.mCumulativeResolution = metrics.mZoom / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
metrics.mResolution = metrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
utils->SetResolution(metrics.mResolution.scale, metrics.mResolution.scale);
- CSSSize scrollPort = metrics.CalculateCompositedRectInCssPixels().Size();
+ CSSSize scrollPort = CSSSize(metrics.CalculateCompositedRectInCssPixels().Size());
utils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
// 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) {
@@ -1533,45 +1538,29 @@ TabChild::ProcessUpdateFrame(const Frame
return aFrameMetrics;
}
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
FrameMetrics newMetrics = aFrameMetrics;
APZCCallbackHelper::UpdateRootFrame(utils, newMetrics);
- CSSRect cssCompositedRect = newMetrics.CalculateCompositedRectInCssPixels();
+ CSSRect cssCompositedRect = CSSRect(newMetrics.CalculateCompositedRectInCssPixels());
// The BrowserElementScrolling helper must know about these updated metrics
// for other functions it performs, such as double tap handling.
// Note, %f must not be used because it is locale specific!
nsCString data;
data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.mScrollOffset.x));
data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.mScrollOffset.y));
data.AppendLiteral(", \"viewport\" : ");
data.AppendLiteral("{ \"width\" : ");
data.AppendFloat(newMetrics.mViewport.width);
data.AppendLiteral(", \"height\" : ");
data.AppendFloat(newMetrics.mViewport.height);
data.AppendLiteral(" }");
- data.AppendLiteral(", \"displayPort\" : ");
- data.AppendLiteral("{ \"x\" : ");
- data.AppendFloat(newMetrics.mDisplayPort.x);
- data.AppendLiteral(", \"y\" : ");
- data.AppendFloat(newMetrics.mDisplayPort.y);
- data.AppendLiteral(", \"width\" : ");
- data.AppendFloat(newMetrics.mDisplayPort.width);
- data.AppendLiteral(", \"height\" : ");
- data.AppendFloat(newMetrics.mDisplayPort.height);
- data.AppendLiteral(" }");
- data.AppendLiteral(", \"compositionBounds\" : ");
- data.AppendPrintf("{ \"x\" : %d", newMetrics.mCompositionBounds.x);
- data.AppendPrintf(", \"y\" : %d", newMetrics.mCompositionBounds.y);
- data.AppendPrintf(", \"width\" : %d", newMetrics.mCompositionBounds.width);
- data.AppendPrintf(", \"height\" : %d", newMetrics.mCompositionBounds.height);
- data.AppendLiteral(" }");
data.AppendLiteral(", \"cssPageRect\" : ");
data.AppendLiteral("{ \"x\" : ");
data.AppendFloat(newMetrics.mScrollableRect.x);
data.AppendLiteral(", \"y\" : ");
data.AppendFloat(newMetrics.mScrollableRect.y);
data.AppendLiteral(", \"width\" : ");
data.AppendFloat(newMetrics.mScrollableRect.width);
data.AppendLiteral(", \"height\" : ");
--- a/dom/network/src/NetworkStatsService.jsm
+++ b/dom/network/src/NetworkStatsService.jsm
@@ -36,16 +36,20 @@ const NETWORK_STATUS_READY = 0;
// enabled 3G since boot).
const NETWORK_STATUS_STANDBY = 1;
// Network is not present, but stored in database by the previous connections.
const NETWORK_STATUS_AWAY = 2;
// The maximum traffic amount can be saved in the |cachedStats|.
const MAX_CACHED_TRAFFIC = 500 * 1000 * 1000; // 500 MB
+const QUEUE_TYPE_UPDATE_STATS = 0;
+const QUEUE_TYPE_UPDATE_CACHE = 1;
+const QUEUE_TYPE_WRITE_CACHE = 2;
+
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
XPCOMUtils.defineLazyServiceGetter(this, "gRil",
"@mozilla.org/ril;1",
"nsIRadioInterfaceLayer");
@@ -393,17 +397,16 @@ this.NetworkStatsService = {
* Function called from manager to get stats from database.
* In order to return updated stats, first is performed a call to
* updateAllStats function, which will get last stats from netd
* and update the database.
* Then, depending on the request (stats per appId or total stats)
* it retrieve them from database and return to the manager.
*/
getSamples: function getSamples(mm, msg) {
- let self = this;
let network = msg.network;
let netId = this.getNetworkId(network.id, network.type);
let appId = 0;
let appManifestURL = msg.appManifestURL;
if (appManifestURL) {
appId = appsService.getAppLocalIdByManifestURL(appManifestURL);
@@ -415,46 +418,54 @@ this.NetworkStatsService = {
}
}
let serviceType = msg.serviceType || "";
let start = new Date(msg.start);
let end = new Date(msg.end);
+ let callback = (function (aError, aResult) {
+ this._db.find(function onStatsFound(aError, aResult) {
+ mm.sendAsyncMessage("NetworkStats:Get:Return",
+ { id: msg.id, error: aError, result: aResult });
+ }, appId, serviceType, network, start, end, appManifestURL);
+ }).bind(this);
+
this.validateNetwork(network, function onValidateNetwork(aNetId) {
if (!aNetId) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: "Invalid connectionType", result: null });
return;
}
// If network is currently active we need to update the cached stats first before
// retrieving stats from the DB.
- if (self._networks[aNetId].status == NETWORK_STATUS_READY) {
- self.updateStats(aNetId, function onStatsUpdated(aResult, aMessage) {
- debug("getstats for network " + network.id + " of type " + network.type);
- debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
+ if (this._networks[aNetId].status == NETWORK_STATUS_READY) {
+ debug("getstats for network " + network.id + " of type " + network.type);
+ debug("appId: " + appId + " from appManifestURL: " + appManifestURL);
+ debug("serviceType: " + serviceType);
- self.updateCachedStats(function onStatsUpdated(aResult, aMessage) {
- self._db.find(function onStatsFound(aError, aResult) {
- mm.sendAsyncMessage("NetworkStats:Get:Return",
- { id: msg.id, error: aError, result: aResult });
- }, appId, serviceType, network, start, end, appManifestURL);
- });
- });
+ if (appId || serviceType) {
+ this.updateCachedStats(callback);
+ return;
+ }
+
+ this.updateStats(aNetId, function onStatsUpdated(aResult, aMessage) {
+ this.updateCachedStats(callback);
+ }.bind(this));
return;
}
// Network not active, so no need to update
- self._db.find(function onStatsFound(aError, aResult) {
+ this._db.find(function onStatsFound(aError, aResult) {
mm.sendAsyncMessage("NetworkStats:Get:Return",
{ id: msg.id, error: aError, result: aResult });
}, appId, serviceType, network, start, end, appManifestURL);
- });
+ }.bind(this));
},
clearInterfaceStats: function clearInterfaceStats(mm, msg) {
let self = this;
let network = msg.network;
debug("clear stats for network " + network.id + " of type " + network.type);
@@ -510,85 +521,89 @@ this.NetworkStatsService = {
mm.sendAsyncMessage("NetworkStats:ClearAll:Return",
{ id: msg.id, error: aError, result: aResult });
});
});
});
},
updateAllStats: function updateAllStats(aCallback) {
- // Update |cachedStats|.
- this.updateCachedStats();
-
let elements = [];
let lastElement = null;
+ let callback = (function (success, message) {
+ this.updateCachedStats(aCallback);
+ }).bind(this);
// For each connectionType create an object containning the type
// and the 'queueIndex', the 'queueIndex' is an integer representing
// the index of a connection type in the global queue array. So, if
// the connection type is already in the queue it is not appended again,
// else it is pushed in 'elements' array, which later will be pushed to
// the queue array.
for (let netId in this._networks) {
if (this._networks[netId].status != NETWORK_STATUS_READY) {
continue;
}
lastElement = { netId: netId,
- queueIndex: this.updateQueueIndex(netId)};
+ queueIndex: this.updateQueueIndex(netId) };
if (lastElement.queueIndex == -1) {
- elements.push({ netId: lastElement.netId, callbacks: [] });
+ elements.push({ netId: lastElement.netId,
+ callbacks: [],
+ queueType: QUEUE_TYPE_UPDATE_STATS });
}
}
if (!lastElement) {
// No elements need to be updated, probably because status is different than
// NETWORK_STATUS_READY.
if (aCallback) {
aCallback(true, "OK");
}
return;
}
if (elements.length > 0) {
// If length of elements is greater than 0, callback is set to
// the last element.
- elements[elements.length - 1].callbacks.push(aCallback);
+ elements[elements.length - 1].callbacks.push(callback);
this.updateQueue = this.updateQueue.concat(elements);
} else {
// Else, it means that all connection types are already in the queue to
// be updated, so callback for this request is added to
// the element in the main queue with the index of the last 'lastElement'.
// But before is checked that element is still in the queue because it can
// be processed while generating 'elements' array.
let element = this.updateQueue[lastElement.queueIndex];
if (aCallback &&
(!element || element.netId != lastElement.netId)) {
aCallback();
return;
}
- this.updateQueue[lastElement.queueIndex].callbacks.push(aCallback);
+ this.updateQueue[lastElement.queueIndex].callbacks.push(callback);
}
// Call the function that process the elements of the queue.
this.processQueue();
if (DEBUG) {
this.logAllRecords();
}
},
updateStats: function updateStats(aNetId, aCallback) {
// Check if the connection is in the main queue, push a new element
// if it is not being processed or add a callback if it is.
let index = this.updateQueueIndex(aNetId);
if (index == -1) {
- this.updateQueue.push({netId: aNetId, callbacks: [aCallback]});
+ this.updateQueue.push({ netId: aNetId,
+ callbacks: [aCallback],
+ queueType: QUEUE_TYPE_UPDATE_STATS });
} else {
this.updateQueue[index].callbacks.push(aCallback);
return;
}
// Call the function that process the elements of the queue.
this.processQueue();
},
@@ -606,41 +621,49 @@ this.NetworkStatsService = {
*/
processQueue: function processQueue(aResult, aMessage) {
// If aResult is not undefined, the caller of the function is the result
// of processing an element, so remove that element and call the callbacks
// it has.
if (aResult != undefined) {
let item = this.updateQueue.shift();
for (let callback of item.callbacks) {
- if(callback) {
+ if (callback) {
callback(aResult, aMessage);
}
}
} else {
// The caller is a function that has pushed new elements to the queue,
// if isQueueRunning is false it means there is no processing currently
// being done, so start.
if (this.isQueueRunning) {
- if(this.updateQueue.length > 1) {
- return;
- }
+ return;
} else {
this.isQueueRunning = true;
}
}
// Check length to determine if queue is empty and stop processing.
if (this.updateQueue.length < 1) {
this.isQueueRunning = false;
return;
}
// Call the update function for the next element.
- this.update(this.updateQueue[0].netId, this.processQueue.bind(this));
+ switch (this.updateQueue[0].queueType) {
+ case QUEUE_TYPE_UPDATE_STATS:
+ this.update(this.updateQueue[0].netId, this.processQueue.bind(this));
+ break;
+ case QUEUE_TYPE_UPDATE_CACHE:
+ this.updateCache(this.processQueue.bind(this));
+ break;
+ case QUEUE_TYPE_WRITE_CACHE:
+ this.writeCache(this.updateQueue[0].stats, this.processQueue.bind(this));
+ break;
+ }
},
update: function update(aNetId, aCallback) {
// Check if connection type is valid.
if (!this._networks[aNetId]) {
if (aCallback) {
aCallback(false, "Invalid network " + aNetId);
}
@@ -703,24 +726,21 @@ this.NetworkStatsService = {
* Function responsible for receiving stats which are not from netd.
*/
saveStats: function saveStats(aAppId, aServiceType, aNetwork, aTimeStamp,
aRxBytes, aTxBytes, aIsAccumulative,
aCallback) {
let netId = this.convertNetworkInterface(aNetwork);
if (!netId) {
if (aCallback) {
- aCallback.notify(false, "Invalid network type");
+ aCallback(false, "Invalid network type");
}
return;
}
- debug("saveStats: " + aAppId + " " + aServiceType + " " + netId + " " +
- aTimeStamp + " " + aRxBytes + " " + aTxBytes);
-
// Check if |aConnectionType|, |aAppId| and |aServiceType| are valid.
// There are two invalid cases for the combination of |aAppId| and
// |aServiceType|:
// a. Both |aAppId| is non-zero and |aServiceType| is non-empty.
// b. Both |aAppId| is zero and |aServiceType| is empty.
if (!this._networks[netId] || (aAppId && aServiceType) ||
(!aAppId && !aServiceType)) {
debug("Invalid network interface, appId or serviceType");
@@ -731,114 +751,128 @@ this.NetworkStatsService = {
serviceType: aServiceType,
networkId: this._networks[netId].network.id,
networkType: this._networks[netId].network.type,
date: new Date(aTimeStamp),
rxBytes: aRxBytes,
txBytes: aTxBytes,
isAccumulative: aIsAccumulative };
+ this.updateQueue.push({ stats: stats,
+ callbacks: [aCallback],
+ queueType: QUEUE_TYPE_WRITE_CACHE });
+
+ this.processQueue();
+ },
+
+ /*
+ *
+ */
+ writeCache: function writeCache(aStats, aCallback) {
+ debug("saveStats: " + aStats.appId + " " + aStats.serviceType + " " +
+ aStats.networkId + " " + aStats.networkType + " " + aStats.date + " "
+ + aStats.date + " " + aStats.rxBytes + " " + aStats.txBytes);
+
// Generate an unique key from |appId|, |serviceType| and |netId|,
// which is used to retrieve data in |cachedStats|.
- let key = stats.appId + "" + stats.serviceType + "" + netId;
+ let netId = this.getNetworkId(aStats.networkId, aStats.networkType);
+ let key = aStats.appId + "" + aStats.serviceType + "" + netId;
// |cachedStats| only keeps the data with the same date.
// If the incoming date is different from |cachedStatsDate|,
// both |cachedStats| and |cachedStatsDate| will get updated.
- let diff = (this._db.normalizeDate(stats.date) -
+ let diff = (this._db.normalizeDate(aStats.date) -
this._db.normalizeDate(this.cachedStatsDate)) /
this._db.sampleRate;
if (diff != 0) {
- this.updateCachedStats(function onUpdated(success, message) {
- this.cachedStatsDate = stats.date;
- this.cachedStats[key] = stats;
-
- if (!aCallback) {
- return;
- }
+ this.updateCache(function onUpdated(success, message) {
+ this.cachedStatsDate = aStats.date;
+ this.cachedStats[key] = aStats;
- if (!success) {
- aCallback.notify(false, message);
- return;
+ if (aCallback) {
+ aCallback(true, "ok");
}
-
- aCallback.notify(true, "ok");
}.bind(this));
-
return;
}
// Try to find the matched row in the cached by |appId| and |connectionType|.
// If not found, save the incoming data into the cached.
let cachedStats = this.cachedStats[key];
if (!cachedStats) {
- this.cachedStats[key] = stats;
+ this.cachedStats[key] = aStats;
+ if (aCallback) {
+ aCallback(true, "ok");
+ }
return;
}
// Find matched row, accumulate the traffic amount.
- cachedStats.rxBytes += stats.rxBytes;
- cachedStats.txBytes += stats.txBytes;
+ cachedStats.rxBytes += aStats.rxBytes;
+ cachedStats.txBytes += aStats.txBytes;
// If new rxBytes or txBytes exceeds MAX_CACHED_TRAFFIC
// the corresponding row will be saved to indexedDB.
// Then, the row will be removed from the cached.
if (cachedStats.rxBytes > MAX_CACHED_TRAFFIC ||
cachedStats.txBytes > MAX_CACHED_TRAFFIC) {
- this._db.saveStats(cachedStats,
- function (error, result) {
- debug("Application stats inserted in indexedDB");
+ this._db.saveStats(cachedStats, function (error, result) {
+ debug("Application stats inserted in indexedDB");
+ if (aCallback) {
+ aCallback(true, "ok");
}
- );
+ });
delete this.cachedStats[key];
+ return;
+ }
+
+ if (aCallback) {
+ aCallback(true, "ok");
}
},
updateCachedStats: function updateCachedStats(aCallback) {
- debug("updateCachedStats: " + this.cachedStatsDate);
+ this.updateQueue.push({ callbacks: [aCallback],
+ queueType: QUEUE_TYPE_UPDATE_CACHE });
+
+ this.processQueue();
+ },
+
+ updateCache: function updateCache(aCallback) {
+ debug("updateCache: " + this.cachedStatsDate);
let stats = Object.keys(this.cachedStats);
if (stats.length == 0) {
// |cachedStats| is empty, no need to update.
if (aCallback) {
aCallback(true, "no need to update");
}
-
return;
}
let index = 0;
this._db.saveStats(this.cachedStats[stats[index]],
- function onSavedStats(error, result) {
- if (DEBUG) {
- debug("Application stats inserted in indexedDB");
- }
+ function onSavedStats(error, result) {
+ debug("Application stats inserted in indexedDB");
- // Clean up the |cachedStats| after updating.
- if (index == stats.length - 1) {
- this.cachedStats = Object.create(null);
-
- if (!aCallback) {
- return;
- }
+ // Clean up the |cachedStats| after updating.
+ if (index == stats.length - 1) {
+ this.cachedStats = Object.create(null);
- if (error) {
- aCallback(false, error);
- return;
- }
-
+ if (aCallback) {
aCallback(true, "ok");
- return;
}
+ return;
+ }
- // Update is not finished, keep updating.
- index += 1;
- this._db.saveStats(this.cachedStats[stats[index]],
- onSavedStats.bind(this, error, result));
- }.bind(this));
+ // Update is not finished, keep updating.
+ index += 1;
+ this._db.saveStats(this.cachedStats[stats[index]],
+ onSavedStats.bind(this, error, result));
+ }.bind(this));
},
get maxCachedTraffic () {
return MAX_CACHED_TRAFFIC;
},
logAllRecords: function logAllRecords() {
this._db.logAllRecords(function onResult(aError, aResult) {
--- a/dom/network/src/NetworkStatsServiceProxy.js
+++ b/dom/network/src/NetworkStatsServiceProxy.js
@@ -39,16 +39,20 @@ NetworkStatsServiceProxy.prototype = {
return;
}
if (DEBUG) {
debug("saveAppStats: " + aAppId + " " + aNetwork.type + " " + aTimeStamp +
" " + aRxBytes + " " + aTxBytes + " " + aIsAccumulative);
}
+ if (aCallback) {
+ aCallback = aCallback.notify;
+ }
+
NetworkStatsService.saveStats(aAppId, "", aNetwork, aTimeStamp,
aRxBytes, aTxBytes, aIsAccumulative,
aCallback);
},
/*
* Function called in the points of different system services
* to pass the per-serive stats to NetworkStatsService.
@@ -64,16 +68,20 @@ NetworkStatsServiceProxy.prototype = {
}
if (DEBUG) {
debug("saveServiceStats: " + aServiceType + " " + aNetwork.type + " " +
aTimeStamp + " " + aRxBytes + " " + aTxBytes + " " +
aIsAccumulative);
}
+ if (aCallback) {
+ aCallback = aCallback.notify;
+ }
+
NetworkStatsService.saveStats(0, aServiceType ,aNetwork, aTimeStamp,
aRxBytes, aTxBytes, aIsAccumulative,
aCallback);
},
classID : NETWORKSTATSSERVICEPROXY_CID,
QueryInterface : XPCOMUtils.generateQI([nsINetworkStatsServiceProxy]),
}
--- a/dom/network/tests/unit_stats/test_networkstats_db.js
+++ b/dom/network/tests/unit_stats/test_networkstats_db.js
@@ -180,21 +180,18 @@ add_test(function test_internalSaveStats
do_check_eq(result[0].rxTotalBytes, stats.rxTotalBytes);
do_check_eq(result[0].txTotalBytes, stats.txTotalBytes);
run_next_test();
});
});
});
add_test(function test_internalSaveStats_arraySamples() {
- var networks = getNetworks();
-
- netStatsDb.clearStats(networks, function (error, result) {
- do_check_eq(error, null);
-
+ clearStore('net_stats_store', function() {
+ var networks = getNetworks();
var network = [networks[0].id, networks[0].type];
var samples = 2;
var stats = [];
for (var i = 0; i < samples; i++) {
stats.push({ appId: 0,
serviceType: "",
network: network,
@@ -210,22 +207,19 @@ add_test(function test_internalSaveStats
netStatsDb.dbNewTxn("net_stats_store", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, stats);
}, function(error, result) {
do_check_eq(error, null);
netStatsDb.logAllRecords(function(error, result) {
do_check_eq(error, null);
- // Result has one sample more than samples because clear inserts
- // an empty sample to keep totalBytes synchronized with netd counters
- result.shift();
do_check_eq(result.length, samples);
var success = true;
- for (var i = 1; i < samples; i++) {
+ for (var i = 0; i < samples; i++) {
if (result[i].appId != stats[i].appId ||
result[i].serviceType != stats[i].serviceType ||
!compareNetworks(result[i].network, stats[i].network) ||
result[i].timestamp != stats[i].timestamp ||
result[i].rxBytes != stats[i].rxBytes ||
result[i].txBytes != stats[i].txBytes ||
result[i].rxSystemBytes != stats[i].rxSystemBytes ||
result[i].txSystemBytes != stats[i].txSystemBytes ||
@@ -238,21 +232,18 @@ add_test(function test_internalSaveStats
do_check_true(success);
run_next_test();
});
});
});
});
add_test(function test_internalRemoveOldStats() {
- var networks = getNetworks();
-
- netStatsDb.clearStats(networks, function (error, result) {
- do_check_eq(error, null);
-
+ clearStore('net_stats_store', function() {
+ var networks = getNetworks();
var network = [networks[0].id, networks[0].type];
var samples = 10;
var stats = [];
for (var i = 0; i < samples - 1; i++) {
stats.push({ appId: 0, serviceType: "",
network: network, timestamp: Date.now() + (10 * i),
rxBytes: 0, txBytes: 0,
rxSystemBytes: 1234, txSystemBytes: 1234,
@@ -279,18 +270,17 @@ add_test(function test_internalRemoveOld
run_next_test();
});
});
});
});
function processSamplesDiff(networks, lastStat, newStat, callback) {
- netStatsDb.clearStats(networks, function (error, result){
- do_check_eq(error, null);
+ clearStore('net_stats_store', function() {
netStatsDb.dbNewTxn("net_stats_store", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, lastStat);
}, function(error, result) {
netStatsDb.dbNewTxn("net_stats_store", "readwrite", function(txn, store) {
let request = store.index("network").openCursor(newStat.network, "prev");
request.onsuccess = function onsuccess(event) {
let cursor = event.target.result;
do_check_neq(cursor, null);
@@ -455,39 +445,33 @@ add_test(function test_saveAppStats() {
serviceType: "",
networkId: networks[0].id,
networkType: networks[0].type,
date: new Date(),
rxBytes: 2234,
txBytes: 2234,
isAccumulative: false };
- netStatsDb.clearStats(networks, function (error, result) {
- do_check_eq(error, null);
+ clearStore('net_stats_store', function() {
netStatsDb.saveStats(stats, function(error, result) {
do_check_eq(error, null);
netStatsDb.logAllRecords(function(error, result) {
do_check_eq(error, null);
- // The clear function clears all records of the datbase but
- // inserts a new element for each [appId, connectionId, connectionType]
- // record to keep the track of rxTotalBytes / txTotalBytes.
- // So at this point, we have two records, one for the appId 0 used in
- // past tests and the new one for appId 1
- do_check_eq(result.length, 2);
- do_check_eq(result[1].appId, stats.appId);
- do_check_eq(result[1].serviceType, stats.serviceType);
- do_check_true(compareNetworks(result[1].network, network));
+ do_check_eq(result.length, 1);
+ do_check_eq(result[0].appId, stats.appId);
+ do_check_eq(result[0].serviceType, stats.serviceType);
+ do_check_true(compareNetworks(result[0].network, network));
let timestamp = filterTimestamp(stats.date);
- do_check_eq(result[1].timestamp, timestamp);
- do_check_eq(result[1].rxBytes, stats.rxBytes);
- do_check_eq(result[1].txBytes, stats.txBytes);
- do_check_eq(result[1].rxSystemBytes, 0);
- do_check_eq(result[1].txSystemBytes, 0);
- do_check_eq(result[1].rxTotalBytes, 0);
- do_check_eq(result[1].txTotalBytes, 0);
+ do_check_eq(result[0].timestamp, timestamp);
+ do_check_eq(result[0].rxBytes, stats.rxBytes);
+ do_check_eq(result[0].txBytes, stats.txBytes);
+ do_check_eq(result[0].rxSystemBytes, 0);
+ do_check_eq(result[0].txSystemBytes, 0);
+ do_check_eq(result[0].rxTotalBytes, 0);
+ do_check_eq(result[0].txTotalBytes, 0);
run_next_test();
});
});
});
});
add_test(function test_saveServiceStats() {
var networks = getNetworks();
@@ -497,46 +481,41 @@ add_test(function test_saveServiceStats(
serviceType: "FakeType",
networkId: networks[0].id,
networkType: networks[0].type,
date: new Date(),
rxBytes: 2234,
txBytes: 2234,
isAccumulative: false };
- netStatsDb.clearStats(networks, function (error, result) {
- do_check_eq(error, null);
+ clearStore('net_stats_store', function() {
netStatsDb.saveStats(stats, function(error, result) {
do_check_eq(error, null);
netStatsDb.logAllRecords(function(error, result) {
do_check_eq(error, null);
- // Again, at this point, we have two records, one for the appId 0 and
- // empty serviceType used in past tests and the new one for appId 0 and
- // non-empty serviceType.
- do_check_eq(result.length, 2);
- do_check_eq(result[1].appId, stats.appId);
- do_check_eq(result[1].serviceType, stats.serviceType);
- do_check_true(compareNetworks(result[1].network, network));
+ do_check_eq(result.length, 1);
+ do_check_eq(result[0].appId, stats.appId);
+ do_check_eq(result[0].serviceType, stats.serviceType);
+ do_check_true(compareNetworks(result[0].network, network));
let timestamp = filterTimestamp(stats.date);
- do_check_eq(result[1].timestamp, timestamp);
- do_check_eq(result[1].rxBytes, stats.rxBytes);
- do_check_eq(result[1].txBytes, stats.txBytes);
- do_check_eq(result[1].rxSystemBytes, 0);
- do_check_eq(result[1].txSystemBytes, 0);
- do_check_eq(result[1].rxTotalBytes, 0);
- do_check_eq(result[1].txTotalBytes, 0);
+ do_check_eq(result[0].timestamp, timestamp);
+ do_check_eq(result[0].rxBytes, stats.rxBytes);
+ do_check_eq(result[0].txBytes, stats.txBytes);
+ do_check_eq(result[0].rxSystemBytes, 0);
+ do_check_eq(result[0].txSystemBytes, 0);
+ do_check_eq(result[0].rxTotalBytes, 0);
+ do_check_eq(result[0].txTotalBytes, 0);
run_next_test();
});
});
});
});
-function prepareFind(network, stats, callback) {
- netStatsDb.clearStats(network, function (error, result) {
- do_check_eq(error, null);
+function prepareFind(stats, callback) {
+ clearStore('net_stats_store', function() {
netStatsDb.dbNewTxn("net_stats_store", "readwrite", function(txn, store) {
netStatsDb._saveStats(txn, store, stats);
}, function(error, result) {
callback(error, result);
});
});
}
@@ -564,17 +543,17 @@ add_test(function test_find () {
stats.push({ appId: appId, serviceType: serviceType,
network: networkMobile, timestamp: saveDate + (sampleRate * i),
rxBytes: 0, txBytes: 10,
rxSystemBytes: 0, txSystemBytes: 0,
rxTotalBytes: 0, txTotalBytes: 0 });
}
- prepareFind(networks[0], stats, function(error, result) {
+ prepareFind(stats, function(error, result) {
do_check_eq(error, null);
netStatsDb.find(function (error, result) {
do_check_eq(error, null);
do_check_eq(result.serviceType, serviceType);
do_check_eq(result.network.id, networks[0].id);
do_check_eq(result.network.type, networks[0].type);
do_check_eq(result.start.getTime(), start.getTime());
do_check_eq(result.end.getTime(), end.getTime());
@@ -608,17 +587,17 @@ add_test(function test_findAppStats () {
rxTotalBytes: 0, txTotalBytes: 0 });
stats.push({ appId: appId, serviceType: serviceType,
network: networkMobile, timestamp: saveDate + (sampleRate * i),
rxBytes: 0, txBytes: 10,
rxTotalBytes: 0, txTotalBytes: 0 });
}
- prepareFind(networks[0], stats, function(error, result) {
+ prepareFind(stats, function(error, result) {
do_check_eq(error, null);
netStatsDb.find(function (error, result) {
do_check_eq(error, null);
do_check_eq(result.serviceType, serviceType);
do_check_eq(result.network.id, networks[0].id);
do_check_eq(result.network.type, networks[0].type);
do_check_eq(result.start.getTime(), start.getTime());
do_check_eq(result.end.getTime(), end.getTime());
@@ -652,17 +631,17 @@ add_test(function test_findServiceStats
rxTotalBytes: 0, txTotalBytes: 0 });
stats.push({ appId: appId, serviceType: serviceType,
network: networkMobile, timestamp: saveDate + (sampleRate * i),
rxBytes: 0, txBytes: 10,
rxTotalBytes: 0, txTotalBytes: 0 });
}
- prepareFind(networks[0], stats, function(error, result) {
+ prepareFind(stats, function(error, result) {
do_check_eq(error, null);
netStatsDb.find(function (error, result) {
do_check_eq(error, null);
do_check_eq(result.serviceType, serviceType);
do_check_eq(result.network.id, networks[0].id);
do_check_eq(result.network.type, networks[0].type);
do_check_eq(result.start.getTime(), start.getTime());
do_check_eq(result.end.getTime(), end.getTime());
@@ -727,31 +706,24 @@ add_test(function test_saveMultipleAppSt
rxBytes: 0, txBytes: 10,
serviceType: "", isAccumulative: false
};
let keys = Object.keys(cached);
let index = 0;
networks.push(networkMobile);
- netStatsDb.clearStats(networks, function (error, result) {
- do_check_eq(error, null);
+
+ clearStore('net_stats_store', function() {
netStatsDb.saveStats(cached[keys[index]],
function callback(error, result) {
do_check_eq(error, null);
if (index == keys.length - 1) {
netStatsDb.logAllRecords(function(error, result) {
- // Again, result has two samples more than expected samples because
- // clear inserts one empty sample for each network to keep totalBytes
- // synchronized with netd counters. so the first two samples have to
- // be discarted.
- result.shift();
- result.shift();
-
do_check_eq(error, null);
do_check_eq(result.length, 6);
do_check_eq(result[0].serviceType, serviceType);
do_check_eq(result[3].appId, 1);
do_check_true(compareNetworks(result[0].network, [networkWifi.id, networkWifi.type]));
do_check_eq(result[0].rxBytes, 0);
do_check_eq(result[0].txBytes, 10);
run_next_test();
--- a/dom/network/tests/unit_stats/test_networkstats_service.js
+++ b/dom/network/tests/unit_stats/test_networkstats_service.js
@@ -2,16 +2,18 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const NETWORK_STATUS_READY = 0;
const NETWORK_STATUS_STANDBY = 1;
const NETWORK_STATUS_AWAY = 2;
+const QUEUE_TYPE_UPDATE_STATS = 0;
+
var wifiId = '00';
function getNetworks(callback) {
NetworkStatsService._db.getAvailableNetworks(function onGetNetworks(aError, aResult) {
callback(aError, aResult);
});
}
@@ -75,21 +77,21 @@ add_test(function test_update() {
NetworkStatsService.update(netId, function (success, msg) {
do_check_eq(success, true);
run_next_test();
});
});
});
add_test(function test_updateQueueIndex() {
- NetworkStatsService.updateQueue = [{netId: 0, callbacks: null},
- {netId: 1, callbacks: null},
- {netId: 2, callbacks: null},
- {netId: 3, callbacks: null},
- {netId: 4, callbacks: null}];
+ NetworkStatsService.updateQueue = [{netId: 0, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
+ {netId: 1, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
+ {netId: 2, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
+ {netId: 3, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS},
+ {netId: 4, callbacks: null, queueType: QUEUE_TYPE_UPDATE_STATS}];
var index = NetworkStatsService.updateQueueIndex(3);
do_check_eq(index, 3);
index = NetworkStatsService.updateQueueIndex(10);
do_check_eq(index, -1);
NetworkStatsService.updateQueue = [];
run_next_test();
});
--- a/dom/network/tests/unit_stats/test_networkstats_service_proxy.js
+++ b/dom/network/tests/unit_stats/test_networkstats_service_proxy.js
@@ -31,181 +31,170 @@ function mokConvertNetworkInterface() {
return netId;
};
}
add_test(function test_saveAppStats() {
var cachedStats = NetworkStatsService.cachedStats;
var timestamp = NetworkStatsService.cachedStatsDate.getTime();
- var samples = 5;
// Create to fake nsINetworkInterfaces. As nsINetworkInterface can not
// be instantiated, these two vars will emulate it by filling the properties
// that will be used.
var wifi = {type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, id: "0"};
var mobile = {type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, id: "1234"};
// Insert fake mobile network interface in NetworkStatsService
var mobileNetId = NetworkStatsService.getNetworkId(mobile.id, mobile.type);
do_check_eq(Object.keys(cachedStats).length, 0);
- for (var i = 0; i < samples; i++) {
- nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false);
-
- nssProxy.saveAppStats(1, mobile, timestamp, 10, 20, false);
- }
-
- var key1 = 1 + "" + NetworkStatsService.getNetworkId(wifi.id, wifi.type);
- var key2 = 1 + "" + mobileNetId + "";
+ nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false,
+ function (success, message) {
+ do_check_eq(success, true);
+ nssProxy.saveAppStats(1, mobile, timestamp, 10, 20, false,
+ function (success, message) {
+ var key1 = 1 + "" + NetworkStatsService.getNetworkId(wifi.id, wifi.type);
+ var key2 = 1 + "" + mobileNetId + "";
- do_check_eq(Object.keys(cachedStats).length, 2);
- do_check_eq(cachedStats[key1].appId, 1);
- do_check_eq(cachedStats[key1].serviceType.length, 0);
- do_check_eq(cachedStats[key1].networkId, wifi.id);
- do_check_eq(cachedStats[key1].networkType, wifi.type);
- do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
- Math.floor(timestamp / 1000));
- do_check_eq(cachedStats[key1].rxBytes, 50);
- do_check_eq(cachedStats[key1].txBytes, 100);
- do_check_eq(cachedStats[key2].appId, 1);
- do_check_eq(cachedStats[key1].serviceType.length, 0);
- do_check_eq(cachedStats[key2].networkId, mobile.id);
- do_check_eq(cachedStats[key2].networkType, mobile.type);
- do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
- Math.floor(timestamp / 1000));
- do_check_eq(cachedStats[key2].rxBytes, 50);
- do_check_eq(cachedStats[key2].txBytes, 100);
+ do_check_eq(Object.keys(cachedStats).length, 2);
+ do_check_eq(cachedStats[key1].appId, 1);
+ do_check_eq(cachedStats[key1].serviceType.length, 0);
+ do_check_eq(cachedStats[key1].networkId, wifi.id);
+ do_check_eq(cachedStats[key1].networkType, wifi.type);
+ do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
+ Math.floor(timestamp / 1000));
+ do_check_eq(cachedStats[key1].rxBytes, 10);
+ do_check_eq(cachedStats[key1].txBytes, 20);
+ do_check_eq(cachedStats[key2].appId, 1);
+ do_check_eq(cachedStats[key1].serviceType.length, 0);
+ do_check_eq(cachedStats[key2].networkId, mobile.id);
+ do_check_eq(cachedStats[key2].networkType, mobile.type);
+ do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
+ Math.floor(timestamp / 1000));
+ do_check_eq(cachedStats[key2].rxBytes, 10);
+ do_check_eq(cachedStats[key2].txBytes, 20);
- run_next_test();
+ run_next_test();
+ });
+ });
});
add_test(function test_saveServiceStats() {
var timestamp = NetworkStatsService.cachedStatsDate.getTime();
- var samples = 5;
// Create to fake nsINetworkInterfaces. As nsINetworkInterface can not
// be instantiated, these two vars will emulate it by filling the properties
// that will be used.
var wifi = {type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, id: "0"};
var mobile = {type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, id: "1234"};
// Insert fake mobile network interface in NetworkStatsService
var mobileNetId = NetworkStatsService.getNetworkId(mobile.id, mobile.type);
- NetworkStatsService.updateCachedStats(
- function (success, msg) {
- do_check_eq(success, true);
+ NetworkStatsService.updateCachedStats(function (success, msg) {
+ do_check_eq(success, true);
- var cachedStats = NetworkStatsService.cachedStats;
- do_check_eq(Object.keys(cachedStats).length, 0);
+ var cachedStats = NetworkStatsService.cachedStats;
+ do_check_eq(Object.keys(cachedStats).length, 0);
- var serviceType = 'FakeType';
- for (var i = 0; i < samples; i++) {
- nssProxy.saveServiceStats(serviceType, wifi, timestamp, 10, 20, false);
-
- nssProxy.saveServiceStats(serviceType, mobile, timestamp, 10, 20, false);
- }
-
- var key1 = 0 + "" + serviceType +
- NetworkStatsService.getNetworkId(wifi.id, wifi.type);
- var key2 = 0 + "" + serviceType + mobileNetId + "";
+ var serviceType = 'FakeType';
+ nssProxy.saveServiceStats(serviceType, wifi, timestamp, 10, 20, false,
+ function (success, message) {
+ do_check_eq(success, true);
+ nssProxy.saveServiceStats(serviceType, mobile, timestamp, 10, 20, false,
+ function (success, message) {
+ do_check_eq(success, true);
+ var key1 = 0 + "" + serviceType +
+ NetworkStatsService.getNetworkId(wifi.id, wifi.type);
+ var key2 = 0 + "" + serviceType + mobileNetId + "";
- do_check_eq(Object.keys(cachedStats).length, 2);
- do_check_eq(cachedStats[key1].appId, 0);
- do_check_eq(cachedStats[key1].serviceType, serviceType);
- do_check_eq(cachedStats[key1].networkId, wifi.id);
- do_check_eq(cachedStats[key1].networkType, wifi.type);
- do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
- Math.floor(timestamp / 1000));
- do_check_eq(cachedStats[key1].rxBytes, 50);
- do_check_eq(cachedStats[key1].txBytes, 100);
- do_check_eq(cachedStats[key2].appId, 0);
- do_check_eq(cachedStats[key1].serviceType, serviceType);
- do_check_eq(cachedStats[key2].networkId, mobile.id);
- do_check_eq(cachedStats[key2].networkType, mobile.type);
- do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
- Math.floor(timestamp / 1000));
- do_check_eq(cachedStats[key2].rxBytes, 50);
- do_check_eq(cachedStats[key2].txBytes, 100);
- }
- );
+ do_check_eq(Object.keys(cachedStats).length, 2);
+ do_check_eq(cachedStats[key1].appId, 0);
+ do_check_eq(cachedStats[key1].serviceType, serviceType);
+ do_check_eq(cachedStats[key1].networkId, wifi.id);
+ do_check_eq(cachedStats[key1].networkType, wifi.type);
+ do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
+ Math.floor(timestamp / 1000));
+ do_check_eq(cachedStats[key1].rxBytes, 10);
+ do_check_eq(cachedStats[key1].txBytes, 20);
+ do_check_eq(cachedStats[key2].appId, 0);
+ do_check_eq(cachedStats[key1].serviceType, serviceType);
+ do_check_eq(cachedStats[key2].networkId, mobile.id);
+ do_check_eq(cachedStats[key2].networkType, mobile.type);
+ do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
+ Math.floor(timestamp / 1000));
+ do_check_eq(cachedStats[key2].rxBytes, 10);
+ do_check_eq(cachedStats[key2].txBytes, 20);
- run_next_test();
+ run_next_test();
+ });
+ });
+ });
});
add_test(function test_saveStatsWithDifferentDates() {
var today = NetworkStatsService.cachedStatsDate;
var tomorrow = new Date(today.getTime() + (24 * 60 * 60 * 1000));
- var wifi = {type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, id: "0"};
var mobile = {type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, id: "1234"};
- var key = 1 + "" + NetworkStatsService.getNetworkId(wifi.id, wifi.type);
-
- NetworkStatsService.updateCachedStats(
- function (success, msg) {
- do_check_eq(success, true);
-
- do_check_eq(Object.keys(NetworkStatsService.cachedStats).length, 0);
+ NetworkStatsService.updateCachedStats(function (success, message) {
+ do_check_eq(success, true);
- nssProxy.saveAppStats(1, wifi, today.getTime(), 10, 20, false);
-
- nssProxy.saveAppStats(1, mobile, today.getTime(), 10, 20, false);
-
- var saveStatsCb = {
- notify: function notify(success, message) {
- do_check_eq(success, true);
+ do_check_eq(Object.keys(NetworkStatsService.cachedStats).length, 0);
+ nssProxy.saveAppStats(1, mobile, today.getTime(), 10, 20, false,
+ function (success, message) {
+ do_check_eq(success, true);
+ nssProxy.saveAppStats(2, mobile, tomorrow.getTime(), 30, 40, false,
+ function (success, message) {
+ do_check_eq(success, true);
- var cachedStats = NetworkStatsService.cachedStats;
- var key = 2 + "" +
- NetworkStatsService.getNetworkId(mobile.id, mobile.type);
- do_check_eq(Object.keys(cachedStats).length, 1);
- do_check_eq(cachedStats[key].appId, 2);
- do_check_eq(cachedStats[key].networkId, mobile.id);
- do_check_eq(cachedStats[key].networkType, mobile.type);
- do_check_eq(new Date(cachedStats[key].date).getTime() / 1000,
- Math.floor(tomorrow.getTime() / 1000));
- do_check_eq(cachedStats[key].rxBytes, 30);
- do_check_eq(cachedStats[key].txBytes, 40);
+ var cachedStats = NetworkStatsService.cachedStats;
+ var key = 2 + "" +
+ NetworkStatsService.getNetworkId(mobile.id, mobile.type);
+ do_check_eq(Object.keys(cachedStats).length, 1);
+ do_check_eq(cachedStats[key].appId, 2);
+ do_check_eq(cachedStats[key].networkId, mobile.id);
+ do_check_eq(cachedStats[key].networkType, mobile.type);
+ do_check_eq(new Date(cachedStats[key].date).getTime() / 1000,
+ Math.floor(tomorrow.getTime() / 1000));
+ do_check_eq(cachedStats[key].rxBytes, 30);
+ do_check_eq(cachedStats[key].txBytes, 40);
- run_next_test();
- }
- };
-
- nssProxy.saveAppStats(2, mobile, tomorrow.getTime(), 30, 40, false,
- saveStatsCb);
- }
- );
+ run_next_test();
+ });
+ });
+ });
});
add_test(function test_saveStatsWithMaxCachedTraffic() {
var timestamp = NetworkStatsService.cachedStatsDate.getTime();
var maxtraffic = NetworkStatsService.maxCachedTraffic;
var wifi = {type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, id: "0"};
- NetworkStatsService.updateCachedStats(
- function (success, msg) {
- do_check_eq(success, true);
-
- var cachedStats = NetworkStatsService.cachedStats;
- do_check_eq(Object.keys(cachedStats).length, 0);
-
- nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false);
+ NetworkStatsService.updateCachedStats(function (success, message) {
+ do_check_eq(success, true);
+ var cachedStats = NetworkStatsService.cachedStats;
+ do_check_eq(Object.keys(cachedStats).length, 0);
+ nssProxy.saveAppStats(1, wifi, timestamp, 10, 20, false,
+ function (success, message) {
+ do_check_eq(success, true);
do_check_eq(Object.keys(cachedStats).length, 1);
-
- nssProxy.saveAppStats(1, wifi, timestamp, maxtraffic, 20, false);
+ nssProxy.saveAppStats(1, wifi, timestamp, maxtraffic, 20, false,
+ function (success, message) {
+ do_check_eq(success, true);
+ do_check_eq(Object.keys(cachedStats).length, 0);
- do_check_eq(Object.keys(cachedStats).length, 0);
-
- run_next_test();
- }
- );
+ run_next_test();
+ });
+ });
+ });
});
function run_test() {
do_get_profile();
Cu.import("resource://gre/modules/NetworkStatsService.jsm");
// Function convertNetworkInterface of NetworkStatsService causes errors when dealing
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -582,16 +582,17 @@ struct ParamTraits<mozilla::layers::Fram
WriteParam(aMsg, aParam.mZoom);
WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
WriteParam(aMsg, aParam.mPresShellId);
WriteParam(aMsg, aParam.mIsRoot);
WriteParam(aMsg, aParam.mHasScrollgrab);
WriteParam(aMsg, aParam.mUpdateScrollOffset);
WriteParam(aMsg, aParam.mScrollGeneration);
+ WriteParam(aMsg, aParam.mTransformScale);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
ReadParam(aMsg, aIter, &aResult->mViewport) &&
ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
@@ -602,17 +603,18 @@ struct ParamTraits<mozilla::layers::Fram
ReadParam(aMsg, aIter, &aResult->mCumulativeResolution) &&
ReadParam(aMsg, aIter, &aResult->mZoom) &&
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&
ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
ReadParam(aMsg, aIter, &aResult->mHasScrollgrab) &&
ReadParam(aMsg, aIter, &aResult->mUpdateScrollOffset) &&
- ReadParam(aMsg, aIter, &aResult->mScrollGeneration));
+ ReadParam(aMsg, aIter, &aResult->mScrollGeneration) &&
+ ReadParam(aMsg, aIter, &aResult->mTransformScale));
}
};
template<>
struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
{
typedef mozilla::layers::TextureFactoryIdentifier paramType;
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -12,27 +12,47 @@
#include "mozilla/gfx/Rect.h" // for RoundedIn
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
namespace IPC {
template <typename T> struct ParamTraits;
} // namespace IPC
namespace mozilla {
-namespace layers {
-// The layer coordinates of the parent layer. Like the layer coordinates
-// of the current layer (LayerPixel) but doesn't include the current layer's
-// resolution.
+// The layer coordinates of the parent layer.
+// This can be arrived at in two ways:
+// - Start with the CSS coordinates of the parent layer (note: NOT the
+// CSS coordinates of the current layer, that will give you the wrong
+// answer), multiply by the device scale and the resolutions of all
+// layers from the root down to and including the parent.
+// - Start with global screen coordinates and unapply all CSS and async
+// transforms from the root down to and including the parent.
+// It's helpful to look at https://wiki.mozilla.org/Platform/GFX/APZ#Coordinate_systems
+// to get a picture of how the various coordinate systems relate to each other.
struct ParentLayerPixel {};
+typedef gfx::PointTyped<ParentLayerPixel> ParentLayerPoint;
+typedef gfx::RectTyped<ParentLayerPixel> ParentLayerRect;
+typedef gfx::SizeTyped<ParentLayerPixel> ParentLayerSize;
+
+typedef gfx::IntMarginTyped<ParentLayerPixel> ParentLayerIntMargin;
+typedef gfx::IntPointTyped<ParentLayerPixel> ParentLayerIntPoint;
+typedef gfx::IntRectTyped<ParentLayerPixel> ParentLayerIntRect;
+typedef gfx::IntSizeTyped<ParentLayerPixel> ParentLayerIntSize;
+
+typedef gfx::ScaleFactor<CSSPixel, ParentLayerPixel> CSSToParentLayerScale;
typedef gfx::ScaleFactor<LayoutDevicePixel, ParentLayerPixel> LayoutDeviceToParentLayerScale;
+typedef gfx::ScaleFactor<ScreenPixel, ParentLayerPixel> ScreenToParentLayerScale;
+
typedef gfx::ScaleFactor<ParentLayerPixel, LayerPixel> ParentLayerToLayerScale;
+typedef gfx::ScaleFactor<ParentLayerPixel, ScreenPixel> ParentLayerToScreenScale;
-typedef gfx::ScaleFactor<ParentLayerPixel, ScreenPixel> ParentLayerToScreenScale;
+
+namespace layers {
/**
* The viewport and displayport metrics for the painted frame at the
* time of a layer-tree transaction. These metrics are especially
* useful for shadow layers, because the metrics values are updated
* atomically with new pixels.
*/
struct FrameMetrics {
@@ -50,16 +70,17 @@ public:
, mCriticalDisplayPort(0, 0, 0, 0)
, mViewport(0, 0, 0, 0)
, mScrollOffset(0, 0)
, mScrollId(NULL_SCROLL_ID)
, mScrollableRect(0, 0, 0, 0)
, mResolution(1)
, mCumulativeResolution(1)
, mZoom(1)
+ , mTransformScale(1)
, mDevPixelsPerCSSPixel(1)
, mPresShellId(-1)
, mMayHaveTouchListeners(false)
, mIsRoot(false)
, mHasScrollgrab(false)
, mUpdateScrollOffset(false)
, mScrollGeneration(0)
{}
@@ -126,44 +147,52 @@ public:
// because the scrollableRect can be smaller if the content is not large
// and the scrollableRect hasn't been updated yet.
// We move the scrollableRect up because we don't know if we can move it
// down. i.e. we know that scrollableRect can go back as far as zero.
// but we don't know how much further ahead it can go.
CSSRect GetExpandedScrollableRect() const
{
CSSRect scrollableRect = mScrollableRect;
- CSSRect compBounds = CalculateCompositedRectInCssPixels();
+ CSSRect compBounds = CSSRect(CalculateCompositedRectInCssPixels());
if (scrollableRect.width < compBounds.width) {
scrollableRect.x = std::max(0.f,
scrollableRect.x - (compBounds.width - scrollableRect.width));
scrollableRect.width = compBounds.width;
}
if (scrollableRect.height < compBounds.height) {
scrollableRect.y = std::max(0.f,
scrollableRect.y - (compBounds.height - scrollableRect.height));
scrollableRect.height = compBounds.height;
}
return scrollableRect;
}
- /**
- * Return the scale factor needed to fit the viewport
- * into its composition bounds.
- */
+ // Return the scale factor needed to fit the viewport
+ // into its composition bounds.
CSSToScreenScale CalculateIntrinsicScale() const
{
return CSSToScreenScale(float(mCompositionBounds.width) / float(mViewport.width));
}
- CSSRect CalculateCompositedRectInCssPixels() const
+ // Return the scale factor for converting from CSS pixels (for this layer)
+ // to layer pixels of our parent layer. Much as mZoom is used to interface
+ // between inputs we get in screen pixels and quantities in CSS pixels,
+ // this is used to interface between mCompositionBounds and quantities
+ // in CSS pixels.
+ CSSToParentLayerScale GetZoomToParent() const
{
- return CSSRect(gfx::RoundedIn(mCompositionBounds / mZoom));
+ return mZoom * mTransformScale;
+ }
+
+ CSSIntRect CalculateCompositedRectInCssPixels() const
+ {
+ return gfx::RoundedIn(mCompositionBounds / GetZoomToParent());
}
// ---------------------------------------------------------------------------
// The following metrics are all in widget space/device pixels.
//
// This is the area within the widget that we're compositing to. It is relative
// to the layer tree origin.
@@ -175,17 +204,17 @@ public:
// where we're prerendering the wrong regions and the content may be clipped,
// or too much of it prerendered. If the composition dimensions are the same as the
// viewport dimensions, there is no need for this and we can just use the viewport
// instead.
//
// This value is valid for nested scrollable layers as well, and is still
// relative to the layer tree origin. This value is provided by Gecko at
// layout/paint time.
- ScreenIntRect mCompositionBounds;
+ ParentLayerIntRect mCompositionBounds;
// ---------------------------------------------------------------------------
// The following metrics are all in CSS pixels. They are not in any uniform
// space, so each is explained separately.
//
// The area of a frame's contents that has been painted, relative to the
// viewport. It is in the same coordinate space as |mViewport|. For example,
@@ -273,16 +302,27 @@ public:
LayoutDeviceToLayerScale mCumulativeResolution;
// The "user zoom". Content is painted by gecko at mResolution * mDevPixelsPerCSSPixel,
// but will be drawn to the screen at mZoom. In the steady state, the
// two will be the same, but during an async zoom action the two may
// diverge. This information is initialized in Gecko but updated in the APZC.
CSSToScreenScale mZoom;
+ // The conversion factor between local screen pixels (the coordinate
+ // system in which APZCs receive input events) and our parent layer's
+ // layer pixels (the coordinate system of mCompositionBounds).
+ // This consists of the scale of the local CSS transform and the
+ // nontransient async transform.
+ // TODO: APZ does not currently work well if there is a CSS transform
+ // on the layer being scrolled that's not just a scale that's
+ // the same in both directions. When we fix this, mTransformScale
+ // will probably need to turn into a matrix.
+ ScreenToParentLayerScale mTransformScale;
+
// The conversion factor between CSS pixels and device pixels for this frame.
// This can vary based on a variety of things, such as reflowing-zoom. The
// conversion factor for device pixels to layers pixels is just the
// resolution.
CSSToLayoutDeviceScale mDevPixelsPerCSSPixel;
uint32_t mPresShellId;
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -470,18 +470,18 @@ ClientLayerManager::GetBackendName(nsASt
case LAYERS_D3D10: aName.AssignLiteral("Direct3D 10"); return;
case LAYERS_D3D11: aName.AssignLiteral("Direct3D 11"); return;
default: NS_RUNTIMEABORT("Invalid backend");
}
}
bool
ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
- ScreenRect& aCompositionBounds,
- CSSToScreenScale& aZoom,
+ ParentLayerRect& aCompositionBounds,
+ CSSToParentLayerScale& aZoom,
bool aDrawingCritical)
{
aZoom.scale = 1.0;
#ifdef MOZ_WIDGET_ANDROID
Layer* primaryScrollable = GetPrimaryScrollableLayer();
if (primaryScrollable) {
const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -130,18 +130,18 @@ public:
* aDrawingCritical will be true if the current drawing operation is using
* the critical displayport.
* Returns true if the update should continue, or false if it should be
* cancelled.
* This is only called if gfxPlatform::UseProgressiveTilePainting() returns
* true.
*/
bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
- ScreenRect& aCompositionBounds,
- CSSToScreenScale& aZoom,
+ ParentLayerRect& aCompositionBounds,
+ CSSToParentLayerScale& aZoom,
bool aDrawingCritical);
#ifdef DEBUG
bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
bool InDrawing() { return mPhase == PHASE_DRAWING; }
bool InForward() { return mPhase == PHASE_FORWARD; }
#endif
bool InTransaction() { return mPhase != PHASE_NONE; }
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -1,15 +1,16 @@
/* 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 "ClientTiledThebesLayer.h"
#include "FrameMetrics.h" // for FrameMetrics
#include "Units.h" // for ScreenIntRect, CSSPoint, etc
+#include "UnitTransforms.h" // for TransformTo
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "gfx3DMatrix.h" // for gfx3DMatrix
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxPoint.h" // for gfxSize
#include "gfxRect.h" // for gfxRect
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Rect.h" // for Rect, RectTyped
@@ -39,21 +40,19 @@ ClientTiledThebesLayer::~ClientTiledTheb
void
ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{
aAttrs = ThebesLayerAttributes(GetValidRegion());
}
static LayoutDeviceRect
-ApplyScreenToLayoutTransform(const gfx3DMatrix& aTransform, const ScreenRect& aScreenRect)
+ApplyParentLayerToLayoutTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect)
{
- gfxRect input(aScreenRect.x, aScreenRect.y, aScreenRect.width, aScreenRect.height);
- gfxRect output = aTransform.TransformBounds(input);
- return LayoutDeviceRect(output.x, output.y, output.width, output.height);
+ return TransformTo<LayoutDevicePixel>(aTransform, aParentLayerRect);
}
void
ClientTiledThebesLayer::BeginPaint()
{
if (ClientManager()->IsRepeatTransaction()) {
return;
}
@@ -76,38 +75,40 @@ ClientTiledThebesLayer::BeginPaint()
// composition bounds to empty so that progressive updates are disabled.
NS_WARNING("Tiled Thebes layer with no scrollable container parent");
mPaintData.mCompositionBounds.SetEmpty();
return;
}
const FrameMetrics& metrics = scrollParent->GetFrameMetrics();
- // Calculate the transform required to convert screen space into transformed
- // layout device space.
- gfx3DMatrix layoutToScreen = GetEffectiveTransform();
+ // Calculate the transform required to convert parent layer space into
+ // transformed layout device space.
+ gfx3DMatrix layoutToParentLayer = GetEffectiveTransform();
for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
if (parent->UseIntermediateSurface()) {
- layoutToScreen *= parent->GetEffectiveTransform();
+ layoutToParentLayer *= parent->GetEffectiveTransform();
}
}
- layoutToScreen.ScalePost(metrics.mCumulativeResolution.scale,
- metrics.mCumulativeResolution.scale,
- 1.f);
+ layoutToParentLayer.ScalePost(metrics.GetParentResolution().scale,
+ metrics.GetParentResolution().scale,
+ 1.f);
- mPaintData.mTransformScreenToLayout = layoutToScreen.Inverse();
+ mPaintData.mTransformParentLayerToLayout = layoutToParentLayer.Inverse();
// Compute the critical display port in layer space.
mPaintData.mLayoutCriticalDisplayPort.SetEmpty();
if (!metrics.mCriticalDisplayPort.IsEmpty()) {
// Convert the display port to screen space first so that we can transform
// it into layout device space.
- const ScreenRect& criticalDisplayPort = metrics.mCriticalDisplayPort * metrics.mZoom;
+ const ParentLayerRect& criticalDisplayPort = metrics.mCriticalDisplayPort
+ * metrics.mDevPixelsPerCSSPixel
+ * metrics.GetParentResolution();
LayoutDeviceRect transformedCriticalDisplayPort =
- ApplyScreenToLayoutTransform(mPaintData.mTransformScreenToLayout, criticalDisplayPort);
+ ApplyParentLayerToLayoutTransform(mPaintData.mTransformParentLayerToLayout, criticalDisplayPort);
mPaintData.mLayoutCriticalDisplayPort =
LayoutDeviceIntRect::ToUntyped(RoundedOut(transformedCriticalDisplayPort));
}
// Calculate the frame resolution. Because this is Gecko-side, before any
// async transforms have occurred, we can use mZoom for this.
mPaintData.mResolution = metrics.mZoom;
@@ -115,18 +116,18 @@ ClientTiledThebesLayer::BeginPaint()
// composition bounds.
mPaintData.mCompositionBounds.SetEmpty();
mPaintData.mScrollOffset.MoveTo(0, 0);
Layer* primaryScrollable = ClientManager()->GetPrimaryScrollableLayer();
if (primaryScrollable) {
const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
mPaintData.mScrollOffset = metrics.mScrollOffset * metrics.mZoom;
mPaintData.mCompositionBounds =
- ApplyScreenToLayoutTransform(mPaintData.mTransformScreenToLayout,
- ScreenRect(metrics.mCompositionBounds));
+ ApplyParentLayerToLayoutTransform(mPaintData.mTransformParentLayerToLayout,
+ ParentLayerRect(metrics.mCompositionBounds));
}
}
void
ClientTiledThebesLayer::EndPaint(bool aFinish)
{
if (!aFinish && !mPaintData.mPaintFinished) {
return;
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -415,18 +415,18 @@ BasicTiledLayerBuffer::ValidateTile(Basi
#endif
aTile = ValidateTileInternal(aTile, aTileOrigin, *rect);
}
return aTile;
}
static LayoutDeviceRect
-TransformCompositionBounds(const ScreenRect& aCompositionBounds,
- const CSSToScreenScale& aZoom,
+TransformCompositionBounds(const ParentLayerRect& aCompositionBounds,
+ const CSSToParentLayerScale& aZoom,
const ScreenPoint& aScrollOffset,
const CSSToScreenScale& aResolution,
const gfx3DMatrix& aTransformScreenToLayout)
{
// Transform the current composition bounds into transformed layout device
// space by compensating for the difference in resolution and subtracting the
// old composition bounds origin.
ScreenRect offsetViewportRect = (aCompositionBounds / aZoom) * aResolution;
@@ -467,35 +467,35 @@ BasicTiledLayerBuffer::ComputeProgressiv
// Find out if we have any non-stale content to update.
nsIntRegion staleRegion;
staleRegion.And(aInvalidRegion, aOldValidRegion);
// Find out the current view transform to determine which tiles to draw
// first, and see if we should just abort this paint. Aborting is usually
// caused by there being an incoming, more relevant paint.
- ScreenRect compositionBounds;
- CSSToScreenScale zoom;
+ ParentLayerRect compositionBounds;
+ CSSToParentLayerScale zoom;
if (mManager->ProgressiveUpdateCallback(!staleRegion.Contains(aInvalidRegion),
compositionBounds, zoom,
!drawingLowPrecision)) {
// We ignore if front-end wants to abort if this is the first,
// non-low-precision paint, as in that situation, we're about to override
// front-end's page/viewport metrics.
if (!aPaintData->mFirstPaint || drawingLowPrecision) {
PROFILER_LABEL("ContentClient", "Abort painting");
aRegionToPaint.SetEmpty();
return aIsRepeated;
}
}
// Transform the screen coordinates into transformed layout device coordinates.
LayoutDeviceRect transformedCompositionBounds =
TransformCompositionBounds(compositionBounds, zoom, aPaintData->mScrollOffset,
- aPaintData->mResolution, aPaintData->mTransformScreenToLayout);
+ aPaintData->mResolution, aPaintData->mTransformParentLayerToLayout);
// Paint tiles that have stale content or that intersected with the screen
// at the time of issuing the draw command in a single transaction first.
// This is to avoid rendering glitches on animated page content, and when
// layers change size/shape.
LayoutDeviceRect coherentUpdateRect =
transformedCompositionBounds.Intersect(aPaintData->mCompositionBounds);
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -113,20 +113,20 @@ struct BasicTiledLayerPaintData {
/*
* The scroll offset of the content from the nearest ancestor layer that
* represents scrollable content with a display port set, for the last
* layer update transaction.
*/
ScreenPoint mLastScrollOffset;
/*
- * The transform matrix to go from Screen units to transformed LayoutDevice
- * units.
+ * The transform matrix to go from ParentLayer units to transformed
+ * LayoutDevice units.
*/
- gfx3DMatrix mTransformScreenToLayout;
+ gfx3DMatrix mTransformParentLayerToLayout;
/*
* The critical displayport of the content from the nearest ancestor layer
* that represents scrollable content with a display port set. Empty if a
* critical displayport is not set.
*
* This is in transformed LayoutDevice coordinates, but is stored as an
* nsIntRect for convenience when intersecting with the layer's mValidRegion.
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -15,16 +15,17 @@
#include "mozilla/layers/AsyncPanZoomController.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/mozalloc.h" // for operator new
#include "mozilla/TouchEvents.h"
#include "nsDebug.h" // for NS_WARNING
#include "nsPoint.h" // for nsIntPoint
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
#include "nsThreadUtils.h" // for NS_IsMainThread
+#include "UnitTransforms.h" // for ViewAs
#include <algorithm> // for std::stable_sort
#define APZC_LOG(...)
// #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
namespace mozilla {
namespace layers {
@@ -109,30 +110,32 @@ APZCTreeManager::UpdatePanZoomController
bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
{
mTreeLock.AssertCurrentThreadOwns();
ContainerLayer* container = aLayer->AsContainerLayer();
AsyncPanZoomController* apzc = nullptr;
if (container) {
- if (container->GetFrameMetrics().IsScrollable()) {
+ const FrameMetrics& metrics = container->GetFrameMetrics();
+ if (metrics.IsScrollable()) {
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
if (state && state->mController.get()) {
// If we get here, aLayer is a scrollable container layer and somebody
// has registered a GeckoContentController for it, so we need to ensure
// it has an APZC instance to manage its scrolling.
apzc = container->GetAsyncPanZoomController();
// If the content represented by the container layer has changed (which may
// be possible because of DLBI heuristics) then we don't want to keep using
// the same old APZC for the new content. Null it out so we run through the
// code to find another one or create one.
- if (apzc && !apzc->Matches(ScrollableLayerGuid(aLayersId, container->GetFrameMetrics()))) {
+ ScrollableLayerGuid guid(aLayersId, metrics);
+ if (apzc && !apzc->Matches(guid)) {
apzc = nullptr;
}
// If the container doesn't have an APZC already, try to find one of our
// pre-existing ones that matches. In particular, if we find an APZC whose
// ScrollableLayerGuid is the same, then we know what happened is that the
// layout of the page changed causing the layer tree to be rebuilt, but the
// underlying content for which the APZC was originally created is still
@@ -163,29 +166,32 @@ APZCTreeManager::UpdatePanZoomController
// building the tree. Also remove it from the set of APZCs that are going
// to be destroyed, because it's going to remain active.
aApzcsToDestroy->RemoveElement(apzc);
apzc->SetPrevSibling(nullptr);
apzc->SetLastChild(nullptr);
}
APZC_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer, aLayersId, container->GetFrameMetrics().mScrollId);
- apzc->NotifyLayersUpdated(container->GetFrameMetrics(),
+ apzc->NotifyLayersUpdated(metrics,
aIsFirstPaint && (aLayersId == aFirstPaintLayersId));
// Use the composition bounds as the hit test region.
// Optionally, the GeckoContentController can provide a touch-sensitive
// region that constrains all frames associated with the controller.
// In this case we intersect the composition bounds with that region.
- ScreenRect visible(container->GetFrameMetrics().mCompositionBounds);
+ ParentLayerRect visible(metrics.mCompositionBounds);
CSSRect touchSensitiveRegion;
if (state->mController->GetTouchSensitiveRegion(&touchSensitiveRegion)) {
+ // Note: we assume here that touchSensitiveRegion is in the CSS pixels
+ // of our parent layer, which makes this coordinate conversion
+ // correct.
visible = visible.Intersect(touchSensitiveRegion
- * container->GetFrameMetrics().LayersPixelsPerCSSPixel()
- * LayerToScreenScale(1.0));
+ * metrics.mDevPixelsPerCSSPixel
+ * metrics.GetParentResolution());
}
apzc->SetLayerHitTestData(visible, aTransform, aLayer->GetTransform());
APZC_LOG("Setting rect(%f %f %f %f) as visible region for APZC %p\n", visible.x, visible.y,
visible.width, visible.height,
apzc);
// Bind the APZC instance into the tree of APZCs
if (aNextSibling) {
@@ -811,35 +817,31 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPan
mTreeLock.AssertCurrentThreadOwns();
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
// explained in the comment on GetInputTransforms. This function will recurse with aApzc at L and P, and the
// comments explain what values are stored in the variables at these two levels. All the comments
// use standard matrix notation where the leftmost matrix in a multiplication is applied first.
// ancestorUntransform takes points from aApzc's parent APZC's layer coordinates
- // to aApzc's screen coordinates.
+ // to aApzc's parent layer's layer coordinates.
// It is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L,
// and RC.Inverse() * QC.Inverse() at recursion level for P.
gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
- // hitTestTransform takes points from aApzc's parent APZC's layer coordinates to
- // the hit test space (which is aApzc's transient coordinates).
- // It is OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LN.Inverse() at L,
- // and RC.Inverse() * QC.Inverse() * PC.Inverse() * PN.Inverse() at P.
- gfx3DMatrix hitTestTransform = ancestorUntransform
- * aApzc->GetCSSTransform().Inverse()
- * aApzc->GetNontransientAsyncTransform().Inverse();
- gfxPoint hitTestPointForThisLayer = hitTestTransform.ProjectPoint(aHitTestPoint);
+ // Hit testing for this layer takes place in our parent layer coordinates,
+ // since the composition bounds (used to initialize the visible rect against
+ // which we hit test are in those coordinates).
+ gfxPoint hitTestPointForThisLayer = ancestorUntransform.ProjectPoint(aHitTestPoint);
APZC_LOG("Untransformed %f %f to transient coordinates %f %f for hit-testing APZC %p\n",
aHitTestPoint.x, aHitTestPoint.y,
hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc);
// childUntransform takes points from aApzc's parent APZC's layer coordinates
- // to aApzc's layer coordinates (which are aApzc's children's screen coordinates).
+ // to aApzc's layer coordinates (which are aApzc's children's ParentLayer coordinates).
// It is OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LA.Inverse() at L
// and RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse() at P.
gfx3DMatrix childUntransform = ancestorUntransform
* aApzc->GetCSSTransform().Inverse()
* gfx3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
gfxPoint hitTestPointForChildLayers = childUntransform.ProjectPoint(aHitTestPoint);
APZC_LOG("Untransformed %f %f to layer coordinates %f %f for APZC %p\n",
aHitTestPoint.x, aHitTestPoint.y,
@@ -848,17 +850,17 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPan
// This walks the tree in depth-first, reverse order, so that it encounters
// APZCs front-to-back on the screen.
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
AsyncPanZoomController* match = GetAPZCAtPoint(child, hitTestPointForChildLayers);
if (match) {
return match;
}
}
- if (aApzc->VisibleRegionContains(ScreenPoint(hitTestPointForThisLayer.x, hitTestPointForThisLayer.y))) {
+ if (aApzc->VisibleRegionContains(ViewAs<ParentLayerPixel>(hitTestPointForThisLayer))) {
APZC_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n",
hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc);
return aApzc;
}
return nullptr;
}
/* This function sets the aTransformToApzcOut and aTransformToGeckoOut out-parameters
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -361,17 +361,17 @@ ContainerRender(ContainerT* aContainer,
transform);
}
if (aContainer->GetFrameMetrics().IsScrollable()) {
gfx::Matrix4x4 transform;
ToMatrix4x4(aContainer->GetEffectiveTransform(), transform);
const FrameMetrics& frame = aContainer->GetFrameMetrics();
- LayerRect layerBounds = ScreenRect(frame.mCompositionBounds) * ScreenToLayerScale(1.0);
+ LayerRect layerBounds = ParentLayerRect(frame.mCompositionBounds) * ParentLayerToLayerScale(1.0);
gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height);
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
aManager->GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTAINER,
rect, clipRect,
transform);
}
}
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -10,16 +10,17 @@
#include <algorithm> // for max, min
#include "AnimationCommon.h" // for ComputedTimingFunction
#include "AsyncPanZoomController.h" // for AsyncPanZoomController, etc
#include "CompositorParent.h" // for CompositorParent
#include "FrameMetrics.h" // for FrameMetrics, etc
#include "GestureEventListener.h" // for GestureEventListener
#include "InputData.h" // for MultiTouchInput, etc
#include "Units.h" // for CSSRect, CSSPoint, etc
+#include "UnitTransforms.h" // for TransformTo
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include "base/tracked.h" // for FROM_HERE
#include "gfxTypes.h" // for gfxFloat
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/BasicEvents.h" // for Modifiers, MODIFIER_*
#include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
#include "mozilla/Constants.h" // for M_PI
@@ -708,17 +709,17 @@ nsEventStatus AsyncPanZoomController::On
nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
if (!mZoomConstraints.mAllowZoom) {
return nsEventStatus_eConsumeNoDefault;
}
SetState(PINCHING);
- mLastZoomFocus = aEvent.mFocusPoint - mFrameMetrics.mCompositionBounds.TopLeft();
+ mLastZoomFocus = ToParentLayerCoords(aEvent.mFocusPoint) - mFrameMetrics.mCompositionBounds.TopLeft();
return nsEventStatus_eConsumeNoDefault;
}
nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
APZC_LOG("%p got a scale in state %d\n", this, mState);
if (mState != PINCHING) {
return nsEventStatus_eConsumeNoDefault;
@@ -730,18 +731,18 @@ nsEventStatus AsyncPanZoomController::On
return nsEventStatus_eConsumeNoDefault;
}
float spanRatio = aEvent.mCurrentSpan / aEvent.mPreviousSpan;
{
ReentrantMonitorAutoEnter lock(mMonitor);
- CSSToScreenScale userZoom = mFrameMetrics.mZoom;
- ScreenPoint focusPoint = aEvent.mFocusPoint - mFrameMetrics.mCompositionBounds.TopLeft();
+ CSSToParentLayerScale userZoom = mFrameMetrics.GetZoomToParent();
+ ParentLayerPoint focusPoint = ToParentLayerCoords(aEvent.mFocusPoint) - mFrameMetrics.mCompositionBounds.TopLeft();
CSSPoint cssFocusPoint = focusPoint / userZoom;
CSSPoint focusChange = (mLastZoomFocus - focusPoint) / userZoom;
// If displacing by the change in focus point will take us off page bounds,
// then reduce the displacement such that it doesn't.
if (mX.DisplacementWillOverscroll(focusChange.x) != Axis::OVERSCROLL_NONE) {
focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
}
@@ -750,18 +751,18 @@ nsEventStatus AsyncPanZoomController::On
}
ScrollBy(focusChange);
// When we zoom in with focus, we can zoom too much towards the boundaries
// that we actually go over them. These are the needed displacements along
// either axis such that we don't overscroll the boundaries when zooming.
CSSPoint neededDisplacement;
- CSSToScreenScale realMinZoom = mZoomConstraints.mMinZoom;
- CSSToScreenScale realMaxZoom = mZoomConstraints.mMaxZoom;
+ CSSToParentLayerScale realMinZoom = mZoomConstraints.mMinZoom * mFrameMetrics.mTransformScale;
+ CSSToParentLayerScale realMaxZoom = mZoomConstraints.mMaxZoom * mFrameMetrics.mTransformScale;
realMinZoom.scale = std::max(realMinZoom.scale,
mFrameMetrics.mCompositionBounds.width / mFrameMetrics.mScrollableRect.width);
realMinZoom.scale = std::max(realMinZoom.scale,
mFrameMetrics.mCompositionBounds.height / mFrameMetrics.mScrollableRect.height);
if (realMaxZoom < realMinZoom) {
realMaxZoom = realMinZoom;
}
@@ -1202,18 +1203,17 @@ EnlargeDisplayPortAlongAxis(float* aOutO
/* static */
const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
const FrameMetrics& aFrameMetrics,
const ScreenPoint& aVelocity,
double aEstimatedPaintDuration)
{
// convert to milliseconds
double estimatedPaintDurationMillis = aEstimatedPaintDuration * 1000;
-
- CSSRect compositionBounds = aFrameMetrics.CalculateCompositedRectInCssPixels();
+ CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels());
CSSPoint scrollOffset = aFrameMetrics.mScrollOffset;
CSSRect displayPort(scrollOffset, compositionBounds.Size());
CSSPoint velocity = aVelocity / aFrameMetrics.mZoom;
CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect();
float xSkateSizeMultiplier = gXSkateSizeMultiplier,
ySkateSizeMultiplier = gYSkateSizeMultiplier;
@@ -1397,17 +1397,17 @@ bool AsyncPanZoomController::SampleConte
requestAnimationFrame = UpdateAnimation(aSampleTime);
aScrollOffset = mFrameMetrics.mScrollOffset * mFrameMetrics.mZoom;
*aNewTransform = GetCurrentAsyncTransform();
LogRendertraceRect("viewport", "red",
CSSRect(mFrameMetrics.mScrollOffset,
- ScreenSize(mFrameMetrics.mCompositionBounds.Size()) / mFrameMetrics.mZoom));
+ ParentLayerSize(mFrameMetrics.mCompositionBounds.Size()) / mFrameMetrics.GetZoomToParent()));
mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset;
}
// Cancel the mAsyncScrollTimeoutTask because we will fire a
// mozbrowserasyncscroll event or renew the mAsyncScrollTimeoutTask again.
if (mAsyncScrollTimeoutTask) {
mAsyncScrollTimeoutTask->Cancel();
@@ -1446,17 +1446,17 @@ ViewTransform AsyncPanZoomController::Ge
}
CSSPoint currentScrollOffset = mFrameMetrics.mScrollOffset;
// If checkerboarding has been disallowed, clamp the scroll position to stay
// within rendered content.
if (!gAllowCheckerboarding &&
!mLastContentPaintMetrics.mDisplayPort.IsEmpty()) {
- CSSRect compositedRect = mLastContentPaintMetrics.CalculateCompositedRectInCssPixels();
+ CSSRect compositedRect(mLastContentPaintMetrics.CalculateCompositedRectInCssPixels());
CSSPoint maxScrollOffset = lastPaintScrollOffset +
CSSPoint(mLastContentPaintMetrics.mDisplayPort.XMost() - compositedRect.width,
mLastContentPaintMetrics.mDisplayPort.YMost() - compositedRect.height);
CSSPoint minScrollOffset = lastPaintScrollOffset + mLastContentPaintMetrics.mDisplayPort.TopLeft();
if (minScrollOffset.x < maxScrollOffset.x) {
currentScrollOffset.x = clamped(currentScrollOffset.x, minScrollOffset.x, maxScrollOffset.x);
}
@@ -1489,16 +1489,17 @@ gfx3DMatrix AsyncPanZoomController::GetT
return gfx3DMatrix::Translation(scrollChange.x, scrollChange.y, 0) *
gfx3DMatrix::ScalingMatrix(zoomChange, zoomChange, 1);
}
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
ReentrantMonitorAutoEnter lock(mMonitor);
mLastContentPaintMetrics = aLayerMetrics;
+ UpdateTransformScale();
bool isDefault = mFrameMetrics.IsDefault();
mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint);
LogRendertraceRect("page", "brown", aLayerMetrics.mScrollableRect);
LogRendertraceRect("painted displayport", "green",
aLayerMetrics.mDisplayPort + aLayerMetrics.mScrollOffset);
@@ -1578,66 +1579,66 @@ const FrameMetrics& AsyncPanZoomControll
}
void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
SetState(ANIMATING_ZOOM);
{
ReentrantMonitorAutoEnter lock(mMonitor);
- ScreenIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
+ ParentLayerIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
CSSRect cssPageRect = mFrameMetrics.mScrollableRect;
CSSPoint scrollOffset = mFrameMetrics.mScrollOffset;
- CSSToScreenScale currentZoom = mFrameMetrics.mZoom;
- CSSToScreenScale targetZoom;
+ CSSToParentLayerScale currentZoom = mFrameMetrics.GetZoomToParent();
+ CSSToParentLayerScale targetZoom;
// The minimum zoom to prevent over-zoom-out.
// If the zoom factor is lower than this (i.e. we are zoomed more into the page),
// then the CSS content rect, in layers pixels, will be smaller than the
// composition bounds. If this happens, we can't fill the target composited
// area with this frame.
- CSSToScreenScale localMinZoom(std::max(mZoomConstraints.mMinZoom.scale,
- std::max(compositionBounds.width / cssPageRect.width,
- compositionBounds.height / cssPageRect.height)));
- CSSToScreenScale localMaxZoom = mZoomConstraints.mMaxZoom;
+ CSSToParentLayerScale localMinZoom(std::max((mZoomConstraints.mMinZoom * mFrameMetrics.mTransformScale).scale,
+ std::max(compositionBounds.width / cssPageRect.width,
+ compositionBounds.height / cssPageRect.height)));
+ CSSToParentLayerScale localMaxZoom = mZoomConstraints.mMaxZoom * mFrameMetrics.mTransformScale;
if (!aRect.IsEmpty()) {
// Intersect the zoom-to-rect to the CSS rect to make sure it fits.
aRect = aRect.Intersect(cssPageRect);
- targetZoom = CSSToScreenScale(std::min(compositionBounds.width / aRect.width,
- compositionBounds.height / aRect.height));
+ targetZoom = CSSToParentLayerScale(std::min(compositionBounds.width / aRect.width,
+ compositionBounds.height / aRect.height));
}
// 1. If the rect is empty, request received from browserElementScrolling.js
// 2. currentZoom is equal to mZoomConstraints.mMaxZoom and user still double-tapping it
// 3. currentZoom is equal to localMinZoom and user still double-tapping it
// Treat these three cases as a request to zoom out as much as possible.
if (aRect.IsEmpty() ||
(currentZoom == localMaxZoom && targetZoom >= localMaxZoom) ||
(currentZoom == localMinZoom && targetZoom <= localMinZoom)) {
- CSSRect compositedRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
+ CSSRect compositedRect = CSSRect(mFrameMetrics.CalculateCompositedRectInCssPixels());
float y = scrollOffset.y;
float newHeight =
cssPageRect.width * (compositedRect.height / compositedRect.width);
float dh = compositedRect.height - newHeight;
aRect = CSSRect(0.0f,
- y + dh/2,
- cssPageRect.width,
- newHeight);
+ y + dh/2,
+ cssPageRect.width,
+ newHeight);
aRect = aRect.Intersect(cssPageRect);
- targetZoom = CSSToScreenScale(std::min(compositionBounds.width / aRect.width,
- compositionBounds.height / aRect.height));
+ targetZoom = CSSToParentLayerScale(std::min(compositionBounds.width / aRect.width,
+ compositionBounds.height / aRect.height));
}
targetZoom.scale = clamped(targetZoom.scale, localMinZoom.scale, localMaxZoom.scale);
FrameMetrics endZoomToMetrics = mFrameMetrics;
- endZoomToMetrics.mZoom = targetZoom;
+ endZoomToMetrics.mZoom = targetZoom / mFrameMetrics.mTransformScale;
// Adjust the zoomToRect to a sensible position to prevent overscrolling.
- CSSRect rectAfterZoom = endZoomToMetrics.CalculateCompositedRectInCssPixels();
+ CSSRect rectAfterZoom = CSSRect(endZoomToMetrics.CalculateCompositedRectInCssPixels());
// If either of these conditions are met, the page will be
// overscrolled after zoomed
if (aRect.y + rectAfterZoom.height > cssPageRect.height) {
aRect.y = cssPageRect.height - rectAfterZoom.height;
aRect.y = aRect.y > 0 ? aRect.y : 0;
}
if (aRect.x + rectAfterZoom.width > cssPageRect.width) {
@@ -1774,17 +1775,17 @@ void AsyncPanZoomController::SendAsyncSc
bool isRoot;
CSSRect contentRect;
CSSSize scrollableSize;
{
ReentrantMonitorAutoEnter lock(mMonitor);
isRoot = mFrameMetrics.mIsRoot;
scrollableSize = mFrameMetrics.mScrollableRect.Size();
- contentRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
+ contentRect = CSSRect(mFrameMetrics.CalculateCompositedRectInCssPixels());
contentRect.MoveTo(mCurrentAsyncScrollOffset);
}
controller->SendAsyncScrollDOMEvent(isRoot, contentRect, scrollableSize);
}
bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid)
{
@@ -1796,10 +1797,24 @@ void AsyncPanZoomController::GetGuid(Scr
if (!aGuidOut) {
return;
}
aGuidOut->mLayersId = mLayersId;
aGuidOut->mScrollId = mFrameMetrics.mScrollId;
aGuidOut->mPresShellId = mFrameMetrics.mPresShellId;
}
+ParentLayerPoint AsyncPanZoomController::ToParentLayerCoords(const ScreenPoint& aPoint)
+{
+ return TransformTo<ParentLayerPixel>(GetNontransientAsyncTransform() * GetCSSTransform(), aPoint);
+}
+
+void AsyncPanZoomController::UpdateTransformScale()
+{
+ gfx3DMatrix nontransientTransforms = GetNontransientAsyncTransform() * GetCSSTransform();
+ if (fabsf(nontransientTransforms.GetXScale() - nontransientTransforms.GetYScale()) > EPSILON) {
+ NS_WARNING("The x- and y-scales of the nontransient transforms should be equal");
+ }
+ mFrameMetrics.mTransformScale.scale = nontransientTransforms.GetXScale();
+}
+
}
}
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -529,16 +529,26 @@ private:
enum AxisLockMode {
FREE, /* No locking at all */
STANDARD, /* Default axis locking mode that remains locked until pan ends*/
STICKY, /* Allow lock to be broken, with hysteresis */
};
static AxisLockMode GetAxisLockMode();
+ // Convert a point from local screen coordinates to parent layer coordinates.
+ // This is a common operation as inputs from the tree manager are in screen
+ // coordinates but the composition bounds is in parent layer coordinates.
+ ParentLayerPoint ToParentLayerCoords(const ScreenPoint& aPoint);
+
+ // Update mFrameMetrics.mTransformScale. This should be called whenever
+ // our CSS transform or the non-transient part of our async transform
+ // changes, as it corresponds to the scale portion of those transforms.
+ void UpdateTransformScale();
+
uint64_t mLayersId;
nsRefPtr<CompositorParent> mCompositorParent;
TaskThrottler mPaintThrottler;
/* Access to the following two fields is protected by the mRefPtrMonitor,
since they are accessed on the UI thread but can be cleared on the
compositor thread. */
nsRefPtr<GeckoContentController> mGeckoContentController;
@@ -593,17 +603,17 @@ private:
// The last time the compositor has sampled the content transform for this
// frame.
TimeStamp mLastSampleTime;
// The last time a touch event came through on the UI thread.
uint32_t mLastEventTime;
// Stores the previous focus point if there is a pinch gesture happening. Used
// to allow panning by moving multiple fingers (thus moving the focus point).
- ScreenPoint mLastZoomFocus;
+ ParentLayerPoint mLastZoomFocus;
// Stores the state of panning and zooming this frame. This is protected by
// |mMonitor|; that is, it should be held whenever this is updated.
PanZoomState mState;
// The last time and offset we fire the mozbrowserasyncscroll event when
// compositor has sampled the content transform for this frame.
TimeStamp mLastAsyncScrollTime;
@@ -674,40 +684,41 @@ private:
nsRefPtr<AsyncPanZoomController> mPrevSibling;
nsRefPtr<AsyncPanZoomController> mParent;
/* The functions and members in this section are used to maintain the
* area that this APZC instance is responsible for. This is used when
* hit-testing to see which APZC instance should handle touch events.
*/
public:
- void SetLayerHitTestData(const ScreenRect& aRect, const gfx3DMatrix& aTransformToLayer,
+ void SetLayerHitTestData(const ParentLayerRect& aRect, const gfx3DMatrix& aTransformToLayer,
const gfx3DMatrix& aTransformForLayer) {
mVisibleRect = aRect;
mAncestorTransform = aTransformToLayer;
mCSSTransform = aTransformForLayer;
+ UpdateTransformScale();
}
gfx3DMatrix GetAncestorTransform() const {
return mAncestorTransform;
}
gfx3DMatrix GetCSSTransform() const {
return mCSSTransform;
}
- bool VisibleRegionContains(const ScreenPoint& aPoint) const {
+ bool VisibleRegionContains(const ParentLayerPoint& aPoint) const {
return mVisibleRect.Contains(aPoint);
}
private:
/* This is the visible region of the layer that this APZC corresponds to, in
* that layer's screen pixels (the same coordinate system in which this APZC
* receives events in ReceiveInputEvent()). */
- ScreenRect mVisibleRect;
+ ParentLayerRect mVisibleRect;
/* This is the cumulative CSS transform for all the layers between the parent
* APZC and this one (not inclusive) */
gfx3DMatrix mAncestorTransform;
/* This is the CSS transform for this APZC's layer. */
gfx3DMatrix mCSSTransform;
};
class AsyncPanZoomAnimation {
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -268,34 +268,34 @@ float Axis::GetPageEnd() {
float Axis::GetOrigin() {
CSSPoint origin = mAsyncPanZoomController->GetFrameMetrics().mScrollOffset;
return GetPointOffset(origin);
}
float Axis::GetCompositionLength() {
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
- CSSRect cssCompositedRect = metrics.CalculateCompositedRectInCssPixels();
+ CSSRect cssCompositedRect = CSSRect(metrics.CalculateCompositedRectInCssPixels());
return GetRectLength(cssCompositedRect);
}
float Axis::GetPageStart() {
CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
return GetRectOffset(pageRect);
}
float Axis::GetPageLength() {
CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
return GetRectLength(pageRect);
}
bool Axis::ScaleWillOverscrollBothSides(float aScale) {
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
- CSSToScreenScale scale(metrics.mZoom.scale * aScale);
+ CSSToParentLayerScale scale(metrics.GetZoomToParent().scale * aScale);
CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale;
return GetRectLength(metrics.mScrollableRect) < GetRectLength(cssCompositionBounds);
}
AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
: Axis(aAsyncPanZoomController)
{
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -118,17 +118,17 @@ public:
}
};
static
FrameMetrics TestFrameMetrics() {
FrameMetrics fm;
fm.mDisplayPort = CSSRect(0, 0, 10, 10);
- fm.mCompositionBounds = ScreenIntRect(0, 0, 10, 10);
+ fm.mCompositionBounds = ParentLayerIntRect(0, 0, 10, 10);
fm.mCriticalDisplayPort = CSSRect(0, 0, 10, 10);
fm.mScrollableRect = CSSRect(0, 0, 100, 100);
fm.mViewport = CSSRect(0, 0, 10, 10);
return fm;
}
static
@@ -231,17 +231,17 @@ TEST(AsyncPanZoomController, Constructor
}
TEST(AsyncPanZoomController, Pinch) {
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
FrameMetrics fm;
fm.mViewport = CSSRect(0, 0, 980, 480);
- fm.mCompositionBounds = ScreenIntRect(200, 200, 100, 200);
+ fm.mCompositionBounds = ParentLayerIntRect(200, 200, 100, 200);
fm.mScrollableRect = CSSRect(0, 0, 980, 1000);
fm.mScrollOffset = CSSPoint(300, 300);
fm.mZoom = CSSToScreenScale(2.0);
apzc->SetFrameMetrics(fm);
apzc->UpdateZoomConstraints(ZoomConstraints(true, CSSToScreenScale(0.25), CSSToScreenScale(4.0)));
// the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
@@ -274,17 +274,17 @@ TEST(AsyncPanZoomController, Pinch) {
}
TEST(AsyncPanZoomController, Overzoom) {
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
FrameMetrics fm;
fm.mViewport = CSSRect(0, 0, 100, 100);
- fm.mCompositionBounds = ScreenIntRect(0, 0, 100, 100);
+ fm.mCompositionBounds = ParentLayerIntRect(0, 0, 100, 100);
fm.mScrollableRect = CSSRect(0, 0, 125, 150);
fm.mScrollOffset = CSSPoint(10, 0);
fm.mZoom = CSSToScreenScale(1.0);
apzc->SetFrameMetrics(fm);
apzc->UpdateZoomConstraints(ZoomConstraints(true, CSSToScreenScale(0.25), CSSToScreenScale(4.0)));
// the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
@@ -352,17 +352,17 @@ TEST(AsyncPanZoomController, ComplexTran
transforms[0].ScalePost(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer
transforms[1].ScalePost(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer
nsTArray<nsRefPtr<Layer> > layers;
nsRefPtr<LayerManager> lm;
nsRefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
FrameMetrics metrics;
- metrics.mCompositionBounds = ScreenIntRect(0, 0, 24, 24);
+ metrics.mCompositionBounds = ParentLayerIntRect(0, 0, 24, 24);
metrics.mDisplayPort = CSSRect(-1, -1, 6, 6);
metrics.mViewport = CSSRect(0, 0, 4, 4);
metrics.mScrollOffset = CSSPoint(10, 10);
metrics.mScrollableRect = CSSRect(0, 0, 50, 50);
metrics.mCumulativeResolution = LayoutDeviceToLayerScale(2);
metrics.mResolution = ParentLayerToLayerScale(2);
metrics.mZoom = CSSToScreenScale(6);
metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(3);
@@ -650,18 +650,18 @@ SetScrollableFrameMetrics(Layer* aLayer,
// The scrollable rect is only used in HitTesting2,
// HitTesting1 doesn't care about it.
CSSRect aScrollableRect = CSSRect(-1, -1, -1, -1))
{
ContainerLayer* container = aLayer->AsContainerLayer();
FrameMetrics metrics;
metrics.mScrollId = aScrollId;
nsIntRect layerBound = aLayer->GetVisibleRegion().GetBounds();
- metrics.mCompositionBounds = ScreenIntRect(layerBound.x, layerBound.y,
- layerBound.width, layerBound.height);
+ metrics.mCompositionBounds = ParentLayerIntRect(layerBound.x, layerBound.y,
+ layerBound.width, layerBound.height);
metrics.mScrollableRect = aScrollableRect;
metrics.mScrollOffset = CSSPoint(0, 0);
container->SetFrameMetrics(metrics);
}
static already_AddRefed<AsyncPanZoomController>
GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToGeckoOut)
new file mode 100644
--- /dev/null
+++ b/layout/base/UnitTransforms.h
@@ -0,0 +1,77 @@
+/* -*- 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 MOZ_UNIT_TRANSFORMS_H_
+#define MOZ_UNIT_TRANSFORMS_H_
+
+#include "Units.h"
+
+namespace mozilla {
+
+// Convenience functions for converting an entity from one strongly-typed
+// coordinate system to another without changing the values it stores (this
+// can be thought of as a cast).
+// To use these functions, you must provide a justification for each use!
+// Feel free to add more justifications to PixelCastJustification, along with
+// a comment that explains under what circumstances it is appropriate to use.
+
+MOZ_BEGIN_ENUM_CLASS(PixelCastJustification, uint8_t)
+ // For the root layer, Screen Pixel = Parent Layer Pixel.
+ ScreenToParentLayerForRoot
+MOZ_END_ENUM_CLASS(PixelCastJustification)
+
+template <class TargetUnits, class SourceUnits>
+gfx::SizeTyped<TargetUnits> ViewAs(const gfx::SizeTyped<SourceUnits>& aSize, PixelCastJustification) {
+ return gfx::SizeTyped<TargetUnits>(aSize.width, aSize.height);
+}
+template <class TargetUnits, class SourceUnits>
+gfx::IntSizeTyped<TargetUnits> ViewAs(const gfx::IntSizeTyped<SourceUnits>& aSize, PixelCastJustification) {
+ return gfx::IntSizeTyped<TargetUnits>(aSize.width, aSize.height);
+}
+
+// Convenience functions for casting untyped entities to typed entities.
+// Using these functions does not require a justification, but once we convert
+// all code to use strongly typed units they should not be needed any longer.
+template <class TargetUnits>
+gfx::PointTyped<TargetUnits> ViewAs(const gfxPoint& aPoint) {
+ return gfx::PointTyped<TargetUnits>(aPoint.x, aPoint.y);
+}
+template <class TargetUnits>
+gfx::RectTyped<TargetUnits> ViewAs(const gfxRect& aRect) {
+ return gfx::RectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
+}
+
+// Convenience functions for casting typed entities to untyped entities.
+// Using these functions does not require a justification, but once we convert
+// all code to use strongly typed units they should not be needed any longer.
+template <class SourceUnits>
+gfxPoint ViewAsUntyped(const gfx::PointTyped<SourceUnits>& aPoint) {
+ return gfxPoint(aPoint.x, aPoint.y);
+}
+template <class SourceUnits>
+gfxRect ViewAsUntyped(const gfx::RectTyped<SourceUnits>& aRect) {
+ return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
+}
+
+// Convenience functions for transforming an entity from one strongly-typed
+// coordinate system to another using the provided transformation matrix.
+template <typename TargetUnits, typename SourceUnits>
+static gfx::PointTyped<TargetUnits> TransformTo(const gfx3DMatrix& aTransform,
+ const gfx::PointTyped<SourceUnits>& aPoint)
+{
+ return ViewAs<TargetUnits>(aTransform.Transform(ViewAsUntyped(aPoint)));
+}
+template <typename TargetUnits, typename SourceUnits>
+static gfx::RectTyped<TargetUnits> TransformTo(const gfx3DMatrix& aTransform,
+ const gfx::RectTyped<SourceUnits>& aRect)
+{
+ return ViewAs<TargetUnits>(aTransform.TransformBounds(ViewAsUntyped(aRect)));
+}
+
+
+}
+
+#endif
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -272,11 +272,11 @@ gfx::MarginTyped<dst> operator*(const gf
template<class src, class dst>
gfx::MarginTyped<dst> operator/(const gfx::MarginTyped<src>& aMargin, const gfx::ScaleFactor<dst, src>& aScale) {
return gfx::MarginTyped<dst>(aMargin.top / aScale.scale,
aMargin.right / aScale.scale,
aMargin.bottom / aScale.scale,
aMargin.left / aScale.scale);
}
-};
+}
#endif
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -51,16 +51,17 @@ EXPORTS += [
'nsPresArena.h',
'nsPresContext.h',
'nsPresState.h',
'nsRefreshDriver.h',
'nsStyleChangeList.h',
'ScrollbarStyles.h',
'StackArena.h',
'Units.h',
+ 'UnitTransforms.h',
]
EXPORTS.mozilla += [
'PaintTracker.h',
]
UNIFIED_SOURCES += [
'ActiveLayerTracker.cpp',
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -615,25 +615,16 @@ static void UnmarkFrameForDisplay(nsIFra
for (nsIFrame* f = aFrame; f;
f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
return;
f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
}
}
-static void AdjustForScrollBars(ScreenIntRect& aToAdjust, nsIScrollableFrame* aScrollableFrame) {
- if (aScrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
- nsMargin sizes = aScrollableFrame->GetActualScrollbarSizes();
- // Scrollbars are not subject to scaling, so CSS pixels = screen pixels for them.
- ScreenIntMargin boundMargins = RoundedToInt(CSSMargin::FromAppUnits(sizes) * CSSToScreenScale(1.0f));
- aToAdjust.Deflate(boundMargins);
- }
-}
-
static void RecordFrameMetrics(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
const nsIFrame* aReferenceFrame,
ContainerLayer* aRoot,
const nsRect& aVisibleRect,
const nsRect& aViewport,
nsRect* aDisplayPort,
nsRect* aCriticalDisplayPort,
@@ -738,43 +729,51 @@ static void RecordFrameMetrics(nsIFrame*
// Calculate the composition bounds as the size of the scroll frame and
// its origin relative to the reference frame.
// If aScrollFrame is null, we are in a document without a root scroll frame,
// so it's a xul document. In this case, use the size of the viewport frame.
nsIFrame* frameForCompositionBoundsCalculation = aScrollFrame ? aScrollFrame : aForFrame;
nsRect compositionBounds(frameForCompositionBoundsCalculation->GetOffsetToCrossDoc(aReferenceFrame),
frameForCompositionBoundsCalculation->GetSize());
metrics.mCompositionBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(compositionBounds, auPerDevPixel)
- * metrics.mCumulativeResolution
- * layerToScreenScale);
-
- // For the root scroll frame of the root content document, clamp the
- // composition bounds to the widget bounds. This is necessary because, if
- // the page is zoomed in, the frame's size might be larger than the widget
- // bounds, but we don't want the composition bounds to be.
- bool useWidgetBounds = false;
+ * metrics.GetParentResolution());
+
+ // For the root scroll frame of the root content document, the above calculation
+ // will yield the size of the viewport frame as the composition bounds, which
+ // doesn't actually correspond to what is visible when
+ // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
+ // the prescontext that the viewport frame is reflowed into. In that case if our
+ // document has a widget then the widget's bounds will correspond to what is
+ // visible. If we don't have a widget the root view's bounds correspond to what
+ // would be visible because they don't get modified by setCSSViewport.
bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument()
&& aScrollFrame == presShell->GetRootScrollFrame();
if (isRootContentDocRootScrollFrame) {
- if (nsIWidget* widget = aForFrame->GetNearestWidget()) {
- nsIntRect bounds;
- widget->GetBounds(bounds);
- ScreenIntRect screenBounds = ScreenIntRect::FromUnknownRect(mozilla::gfx::IntRect(
- bounds.x, bounds.y, bounds.width, bounds.height));
- AdjustForScrollBars(screenBounds, scrollableFrame);
- metrics.mCompositionBounds = metrics.mCompositionBounds.ForceInside(screenBounds);
- useWidgetBounds = true;
+ if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
+ if (nsView* view = rootFrame->GetView()) {
+ nsIWidget* widget = view->GetWidget();
+ if (widget) {
+ nsIntRect bounds;
+ widget->GetBounds(bounds);
+ metrics.mCompositionBounds = ParentLayerIntRect::FromUnknownRect(mozilla::gfx::IntRect(
+ bounds.x, bounds.y, bounds.width, bounds.height));
+ } else {
+ metrics.mCompositionBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(view->GetBounds(), auPerDevPixel)
+ * metrics.GetParentResolution());
+ }
+ }
}
}
// Adjust composition bounds for the size of scroll bars.
- // If the widget bounds were used to clamp the composition bounds,
- // this adjustment was already made to the widget bounds.
- if (!useWidgetBounds) {
- AdjustForScrollBars(metrics.mCompositionBounds, scrollableFrame);
+ if (scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
+ nsMargin sizes = scrollableFrame->GetActualScrollbarSizes();
+ // Scrollbars are not subject to scaling, so CSS pixels = layer pixels for them.
+ ParentLayerIntMargin boundMargins = RoundedToInt(CSSMargin::FromAppUnits(sizes) * CSSToParentLayerScale(1.0f));
+ metrics.mCompositionBounds.Deflate(boundMargins);
}
metrics.mPresShellId = presShell->GetPresShellId();
// If the scroll frame's content is marked 'scrollgrab', record this
// in the FrameMetrics so APZ knows to provide the scroll grabbing
// behaviour.
if (aScrollFrame && nsContentUtils::HasScrollgrab(aScrollFrame->GetContent())) {
--- a/security/manager/boot/src/nsSTSPreloadList.errors
+++ b/security/manager/boot/src/nsSTSPreloadList.errors
@@ -28,17 +28,16 @@ crypto.is: did not receive HSTS header
csawctf.poly.edu: did not receive HSTS header
dl.google.com: did not receive HSTS header
docs.google.com: did not receive HSTS header
drive.google.com: did not receive HSTS header
dropcam.com: did not receive HSTS header
email.lookout.com: could not connect to host
emailprivacytester.com: did not receive HSTS header
encrypted.google.com: did not receive HSTS header
-errors.zenpayroll.com: could not connect to host
espra.com: could not connect to host
fatzebra.com.au: did not receive HSTS header
fj.simple.com: did not receive HSTS header
get.zenpayroll.com: did not receive HSTS header
glass.google.com: did not receive HSTS header
gmail.com: did not receive HSTS header
gocardless.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-b28_v1_3-l64-hsts-0000000000/getHSTSPreloadList.js :: processStsHeader :: line 124" data: no]
googlemail.com: did not receive HSTS header
@@ -73,18 +72,16 @@ passport.yandex.com: did not receive HST
passport.yandex.com.tr: did not receive HSTS header
passport.yandex.kz: did not receive HSTS header
passport.yandex.ru: did not receive HSTS header
passport.yandex.ua: did not receive HSTS header
paypal.com: max-age too low: 14400
payroll.xero.com: max-age too low: 3600
platform.lookout.com: could not connect to host
play.google.com: did not receive HSTS header
-plus.google.com: did not receive HSTS header
-plus.sandbox.google.com: did not receive HSTS header
prodpad.com: did not receive HSTS header
profiles.google.com: did not receive HSTS header
rapidresearch.me: did not receive HSTS header
sah3.net: could not connect to host
saturngames.co.uk: did not receive HSTS header
script.google.com: did not receive HSTS header
security.google.com: did not receive HSTS header
serverdensity.io: did not receive HSTS header
--- a/security/manager/boot/src/nsSTSPreloadList.inc
+++ b/security/manager/boot/src/nsSTSPreloadList.inc
@@ -3,17 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*****************************************************************************/
/* This is an automatically generated file. If you're not */
/* nsSiteSecurityService.cpp, you shouldn't be #including it. */
/*****************************************************************************/
#include <stdint.h>
-const PRTime gPreloadListExpirationTime = INT64_C(1405163271028000);
+const PRTime gPreloadListExpirationTime = INT64_C(1405764347410000);
class nsSTSPreload
{
public:
const char *mHost;
const bool mIncludeSubdomains;
};
@@ -127,18 +127,21 @@ static const nsSTSPreload kSTSPreloadLis
{ "passwd.io", true },
{ "paste.linode.com", false },
{ "pastebin.linode.com", false },
{ "pay.gigahost.dk", true },
{ "paymill.com", true },
{ "paymill.de", false },
{ "piratenlogin.de", true },
{ "pixi.me", true },
+ { "plus.google.com", false },
+ { "plus.sandbox.google.com", false },
{ "publications.qld.gov.au", false },
{ "riseup.net", true },
+ { "roddis.net", false },
{ "romab.com", true },
{ "roundcube.mayfirst.org", false },
{ "sandbox.mydigipass.com", false },
{ "securityheaders.com", true },
{ "shodan.io", true },
{ "silentcircle.com", false },
{ "simbolo.co.uk", false },
{ "simple.com", false },
@@ -173,16 +176,17 @@ static const nsSTSPreload kSTSPreloadLis
{ "www.irccloud.com", false },
{ "www.linode.com", false },
{ "www.lookout.com", false },
{ "www.makeyourlaws.org", false },
{ "www.mydigipass.com", false },
{ "www.mylookout.com", false },
{ "www.noisebridge.net", false },
{ "www.opsmate.com", true },
+ { "www.roddis.net", false },
{ "www.simbolo.co.uk", false },
{ "www.simple.com", false },
{ "www.therapynotes.com", false },
{ "www.torproject.org", false },
{ "www.twitter.com", false },
{ "www.zenpayroll.com", false },
{ "zenpayroll.com", false },
};
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -1918,17 +1918,17 @@ AndroidBridge::IsContentDocumentDisplaye
JNIEnv* env = GetJNIEnv();
if (!env || !mLayerClient)
return false;
return mLayerClient->IsContentDocumentDisplayed();
}
bool
-AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, ScreenRect& aCompositionBounds, CSSToScreenScale& aZoom)
+AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, ParentLayerRect& aCompositionBounds, CSSToParentLayerScale& aZoom)
{
GeckoLayerClient *client = mLayerClient;
if (!client) {
ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
return false;
}
jobject progressiveUpdateDataJObj = client->ProgressiveUpdateCallback(aHasPendingNewThebesContent,
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -172,17 +172,17 @@ public:
bool GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult);
bool GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId, uint32_t aFrameId, nsCString & aResult);
nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer);
void GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
void ContentDocumentChanged();
bool IsContentDocumentDisplayed();
- bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, ScreenRect& aCompositionBounds, CSSToScreenScale& aZoom);
+ bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, ParentLayerRect& aCompositionBounds, CSSToParentLayerScale& aZoom);
void SetLayerClient(JNIEnv* env, jobject jobj);
GeckoLayerClient* GetLayerClient() { return mLayerClient; }
bool GetHandlersForURL(const nsAString& aURL,
nsIMutableArray* handlersArray = nullptr,
nsIHandlerApp **aDefaultApp = nullptr,
const nsAString& aAction = EmptyString());
--- a/widget/xpwidgets/APZCCallbackHelper.cpp
+++ b/widget/xpwidgets/APZCCallbackHelper.cpp
@@ -83,17 +83,17 @@ MaybeAlignAndClampDisplayPort(mozilla::l
CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect();
displayPort = scrollableRect.Intersect(displayPort + aActualScrollOffset)
- aActualScrollOffset;
}
static void
RecenterDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics)
{
- CSSRect compositionBounds = aFrameMetrics.CalculateCompositedRectInCssPixels();
+ CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels());
aFrameMetrics.mDisplayPort.x = (compositionBounds.width - aFrameMetrics.mDisplayPort.width) / 2;
aFrameMetrics.mDisplayPort.y = (compositionBounds.height - aFrameMetrics.mDisplayPort.height) / 2;
}
static CSSPoint
ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccessOut)
{
aSuccessOut = false;
@@ -148,17 +148,17 @@ APZCCallbackHelper::UpdateRootFrame(nsID
// 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.
- CSSSize scrollPort = aMetrics.CalculateCompositedRectInCssPixels().Size();
+ CSSSize scrollPort = CSSSize(aMetrics.CalculateCompositedRectInCssPixels().Size());
aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
// Scroll the window to the desired spot
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
bool scrollUpdated = false;
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.mScrollOffset, scrollUpdated);
if (scrollUpdated) {
@@ -180,17 +180,17 @@ APZCCallbackHelper::UpdateRootFrame(nsID
// The mZoom variable on the frame metrics stores the CSS-to-screen scale for this
// frame. This scale includes all of the (cumulative) resolutions set on the presShells
// from the root down to this frame. However, when setting the resolution, we only
// want the piece of the resolution that corresponds to this presShell, rather than
// all of the cumulative stuff, so we need to divide out the parent resolutions.
// Finally, we multiply by a ScreenToLayerScale of 1.0f because the goal here is to
// take the async zoom calculated by the APZC and tell gecko about it (turning it into
// a "sync" zoom) which will update the resolution at which the layer is painted.
- mozilla::layers::ParentLayerToLayerScale presShellResolution =
+ ParentLayerToLayerScale presShellResolution =
aMetrics.mZoom
/ aMetrics.mDevPixelsPerCSSPixel
/ aMetrics.GetParentResolution()
* ScreenToLayerScale(1.0f);
aUtils->SetResolution(presShellResolution.scale, presShellResolution.scale);
// Finally, we set the displayport.
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.mScrollId);