mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
ad4a8588eb
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
"remote": "",
|
"remote": "",
|
||||||
"branch": ""
|
"branch": ""
|
||||||
},
|
},
|
||||||
"revision": "fbcff6610f8b99726ef14b0c6d894b4a7053eecf",
|
"revision": "d937413f736efd995436c211649f930191429b66",
|
||||||
"repo_path": "integration/gaia-central"
|
"repo_path": "integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f0e6d8bde961683b7862b4eb0bb04c49d9699f3c"/>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="7a865bd6163e9a0372861d27450b3434875ef5c1"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="58734e8a48157f99d5b733412b600c2e04c954fe"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||||
|
@ -1663,6 +1663,7 @@ pref("loop.server", "https://loop.services.mozilla.com/v0");
|
|||||||
pref("loop.seenToS", "unseen");
|
pref("loop.seenToS", "unseen");
|
||||||
pref("loop.gettingStarted.seen", false);
|
pref("loop.gettingStarted.seen", false);
|
||||||
pref("loop.gettingStarted.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/hello/start");
|
pref("loop.gettingStarted.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/hello/start");
|
||||||
|
pref("loop.gettingStarted.resumeOnFirstJoin", false);
|
||||||
pref("loop.learnMoreUrl", "https://www.firefox.com/hello/");
|
pref("loop.learnMoreUrl", "https://www.firefox.com/hello/");
|
||||||
pref("loop.legal.ToS_url", "https://www.mozilla.org/about/legal/terms/firefox-hello/");
|
pref("loop.legal.ToS_url", "https://www.mozilla.org/about/legal/terms/firefox-hello/");
|
||||||
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/firefox-hello/");
|
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/firefox-hello/");
|
||||||
|
@ -331,7 +331,9 @@ let gFxAccounts = {
|
|||||||
fxaMigrator.createFxAccount(window);
|
fxaMigrator.createFxAccount(window);
|
||||||
break;
|
break;
|
||||||
case "migrate-verify":
|
case "migrate-verify":
|
||||||
fxaMigrator.resendVerificationMail();
|
// Instead of using the migrator module directly here the UX calls for
|
||||||
|
// us to open prefs which has a "resend" button.
|
||||||
|
this.openPreferences();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.openAccountsPage(null, { entryPoint: "menupanel" });
|
this.openAccountsPage(null, { entryPoint: "menupanel" });
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
let LoopUI;
|
let LoopUI;
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI", "resource:///modules/loop/MozLoopAPI.jsm");
|
XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI", "resource:///modules/loop/MozLoopAPI.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "LoopRooms", "resource:///modules/loop/LoopRooms.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/loop/MozLoopService.jsm");
|
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/loop/MozLoopService.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/PanelFrame.jsm");
|
XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/PanelFrame.jsm");
|
||||||
|
|
||||||
@ -84,8 +85,70 @@ XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/Panel
|
|||||||
// Used to clear the temporary "login" state from the button.
|
// Used to clear the temporary "login" state from the button.
|
||||||
Services.obs.notifyObservers(null, "loop-status-changed", null);
|
Services.obs.notifyObservers(null, "loop-status-changed", null);
|
||||||
|
|
||||||
PanelFrame.showPopup(window, event ? event.target : this.toolbarButton.node,
|
this.shouldResumeTour().then((resume) => {
|
||||||
"loop", null, "about:looppanel", null, callback);
|
if (resume) {
|
||||||
|
// Assume the conversation with the visitor wasn't open since we would
|
||||||
|
// have resumed the tour as soon as the visitor joined if it was (and
|
||||||
|
// the pref would have been set to false already.
|
||||||
|
MozLoopService.resumeTour("waiting");
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelFrame.showPopup(window, event ? event.target : this.toolbarButton.node,
|
||||||
|
"loop", null, "about:looppanel", null, callback);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to know whether actions to open the panel should instead resume the tour.
|
||||||
|
*
|
||||||
|
* We need the panel to be opened via UITour so that it gets @noautohide.
|
||||||
|
*
|
||||||
|
* @return {Promise} resolving with a {Boolean} of whether the tour should be resumed instead of
|
||||||
|
* opening the panel.
|
||||||
|
*/
|
||||||
|
shouldResumeTour: Task.async(function* () {
|
||||||
|
// Resume the FTU tour if this is the first time a room was joined by
|
||||||
|
// someone else since the tour.
|
||||||
|
if (!Services.prefs.getBoolPref("loop.gettingStarted.resumeOnFirstJoin")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!LoopRooms.participantsCount) {
|
||||||
|
// Nobody is in the rooms
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let roomsWithNonOwners = yield this.roomsWithNonOwners();
|
||||||
|
if (!roomsWithNonOwners.length) {
|
||||||
|
// We were the only one in a room but we want to know about someone else joining.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Promise} resolved with an array of Rooms with participants (excluding owners)
|
||||||
|
*/
|
||||||
|
roomsWithNonOwners: function() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
LoopRooms.getAll((error, rooms) => {
|
||||||
|
let roomsWithNonOwners = [];
|
||||||
|
for (let room of rooms) {
|
||||||
|
if (!("participants" in room)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let numNonOwners = room.participants.filter(participant => !participant.owner).length;
|
||||||
|
if (!numNonOwners) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
roomsWithNonOwners.push(room);
|
||||||
|
}
|
||||||
|
resolve(roomsWithNonOwners);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -7476,6 +7476,7 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
|
|||||||
// Certain URLs can be switched to irrespective of the source or destination
|
// Certain URLs can be switched to irrespective of the source or destination
|
||||||
// window being in private browsing mode:
|
// window being in private browsing mode:
|
||||||
const kPrivateBrowsingWhitelist = new Set([
|
const kPrivateBrowsingWhitelist = new Set([
|
||||||
|
"about:addons",
|
||||||
"about:customizing",
|
"about:customizing",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -7737,7 +7738,8 @@ XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function openEyedropper() {
|
function openEyedropper() {
|
||||||
var eyedropper = new this.Eyedropper(this);
|
var eyedropper = new this.Eyedropper(this, { context: "menu",
|
||||||
|
copyOnSelect: true });
|
||||||
eyedropper.open();
|
eyedropper.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,3 +486,4 @@ skip-if = e10s # bug 1100687 - test directly manipulates content (content.docume
|
|||||||
[browser_mcb_redirect.js]
|
[browser_mcb_redirect.js]
|
||||||
skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account
|
skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account
|
||||||
[browser_windowactivation.js]
|
[browser_windowactivation.js]
|
||||||
|
[browser_bug963945.js]
|
||||||
|
30
browser/base/content/test/general/browser_bug963945.js
Normal file
30
browser/base/content/test/general/browser_bug963945.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test ensures the about:addons tab is only
|
||||||
|
* opened one time when in private browsing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
var win = OpenBrowserWindow({private: true});
|
||||||
|
|
||||||
|
whenDelayedStartupFinished(win, function() {
|
||||||
|
win.gBrowser.loadURI("about:addons");
|
||||||
|
|
||||||
|
waitForFocus(function() {
|
||||||
|
EventUtils.synthesizeKey("a", { ctrlKey: true, shiftKey: true }, win);
|
||||||
|
|
||||||
|
is(win.gBrowser.tabs.length, 1, "about:addons tab was re-focused.");
|
||||||
|
is(win.gBrowser.currentURI.spec, "about:addons", "Addons tab was opened.");
|
||||||
|
|
||||||
|
win.close();
|
||||||
|
finish();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -939,12 +939,24 @@
|
|||||||
this.closePopup();
|
this.closePopup();
|
||||||
controller.handleEscape();
|
controller.handleEscape();
|
||||||
|
|
||||||
// Fill in the search bar's value
|
|
||||||
searchBar.value = search;
|
|
||||||
|
|
||||||
// open the search results according to the clicking subtlety
|
// open the search results according to the clicking subtlety
|
||||||
var where = whereToOpenLink(aEvent, false, true);
|
var where = whereToOpenLink(aEvent, false, true);
|
||||||
|
|
||||||
|
// But open ctrl/cmd clicks on autocomplete items in a new background tab.
|
||||||
|
if (where == "tab" && (aEvent instanceof MouseEvent) &&
|
||||||
|
(aEvent.button == 1 ||
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
aEvent.metaKey))
|
||||||
|
#else
|
||||||
|
aEvent.ctrlKey))
|
||||||
|
#endif
|
||||||
|
where = "tab-background";
|
||||||
|
|
||||||
searchBar.doSearch(search, where);
|
searchBar.doSearch(search, where);
|
||||||
|
if (where == "tab-background")
|
||||||
|
searchBar.focus();
|
||||||
|
else
|
||||||
|
searchBar.value = search;
|
||||||
}
|
}
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -155,7 +155,7 @@ let LoopRoomsInternal = {
|
|||||||
* `Error` object or `null`. The second argument will
|
* `Error` object or `null`. The second argument will
|
||||||
* be the list of rooms, if it was fetched successfully.
|
* be the list of rooms, if it was fetched successfully.
|
||||||
*/
|
*/
|
||||||
getAll: function(version = null, callback) {
|
getAll: function(version = null, callback = null) {
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
callback = version;
|
callback = version;
|
||||||
version = null;
|
version = null;
|
||||||
|
@ -1099,6 +1099,33 @@ this.MozLoopService = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Resume the tour (re-opening the tab, if necessary) if someone else joins
|
||||||
|
// a room of ours and it's currently open.
|
||||||
|
LoopRooms.on("joined", (e, room, participant) => {
|
||||||
|
let isOwnerInRoom = false;
|
||||||
|
let isOtherInRoom = false;
|
||||||
|
|
||||||
|
if (!room.participants) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The particpant that joined isn't necessarily included in room.participants (depending on
|
||||||
|
// when the broadcast happens) so concatenate.
|
||||||
|
for (let participant of room.participants.concat(participant)) {
|
||||||
|
if (participant.owner) {
|
||||||
|
isOwnerInRoom = true;
|
||||||
|
} else {
|
||||||
|
isOtherInRoom = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOwnerInRoom || !isOtherInRoom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resumeTour("open");
|
||||||
|
});
|
||||||
|
|
||||||
// If expiresTime is not in the future and the user hasn't
|
// If expiresTime is not in the future and the user hasn't
|
||||||
// previously authenticated then skip registration.
|
// previously authenticated then skip registration.
|
||||||
if (!MozLoopServiceInternal.urlExpiryTimeIsInFuture() &&
|
if (!MozLoopServiceInternal.urlExpiryTimeIsInFuture() &&
|
||||||
@ -1476,23 +1503,64 @@ this.MozLoopService = {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tour URL.
|
||||||
|
*
|
||||||
|
* @param {String} aSrc A string representing the entry point to begin the tour, optional.
|
||||||
|
* @param {Object} aAdditionalParams An object with keys used as query parameter names
|
||||||
|
*/
|
||||||
|
getTourURL: function(aSrc = null, aAdditionalParams = {}) {
|
||||||
|
let urlStr = this.getLoopPref("gettingStarted.url");
|
||||||
|
let url = new URL(Services.urlFormatter.formatURL(urlStr));
|
||||||
|
for (let paramName in aAdditionalParams) {
|
||||||
|
url.searchParams.append(paramName, aAdditionalParams[paramName]);
|
||||||
|
}
|
||||||
|
if (aSrc) {
|
||||||
|
url.searchParams.set("utm_source", "firefox-browser");
|
||||||
|
url.searchParams.set("utm_medium", "firefox-browser");
|
||||||
|
url.searchParams.set("utm_campaign", aSrc);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
|
||||||
|
resumeTour: function(aIncomingConversationState) {
|
||||||
|
let url = this.getTourURL("resume-with-conversation", {
|
||||||
|
incomingConversation: aIncomingConversationState,
|
||||||
|
});
|
||||||
|
|
||||||
|
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||||
|
|
||||||
|
this.setLoopPref("gettingStarted.resumeOnFirstJoin", false);
|
||||||
|
|
||||||
|
// The query parameters of the url can vary but we always want to re-use a Loop tour tab that's
|
||||||
|
// already open so we ignore the fragment and query string.
|
||||||
|
let hadExistingTab = win.switchToTabHavingURI(url, true, {
|
||||||
|
ignoreFragment: true,
|
||||||
|
ignoreQueryString: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the tab was already open, send an event instead of using the query
|
||||||
|
// parameter above (that we don't replace on existing tabs to avoid a reload).
|
||||||
|
if (hadExistingTab) {
|
||||||
|
UITour.notify("Loop:IncomingConversation", {
|
||||||
|
conversationOpen: aIncomingConversationState === "open",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the Getting Started tour in the browser.
|
* Opens the Getting Started tour in the browser.
|
||||||
*
|
*
|
||||||
* @param {String} aSrc
|
* @param {String} [aSrc] A string representing the entry point to begin the tour, optional.
|
||||||
* - The UI element that the user used to begin the tour, optional.
|
|
||||||
*/
|
*/
|
||||||
openGettingStartedTour: Task.async(function(aSrc = null) {
|
openGettingStartedTour: Task.async(function(aSrc = null) {
|
||||||
try {
|
try {
|
||||||
let urlStr = Services.prefs.getCharPref("loop.gettingStarted.url");
|
let url = this.getTourURL(aSrc);
|
||||||
let url = new URL(Services.urlFormatter.formatURL(urlStr));
|
|
||||||
if (aSrc) {
|
|
||||||
url.searchParams.set("utm_source", "firefox-browser");
|
|
||||||
url.searchParams.set("utm_medium", "firefox-browser");
|
|
||||||
url.searchParams.set("utm_campaign", aSrc);
|
|
||||||
}
|
|
||||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||||
win.switchToTabHavingURI(url, true, {replaceQueryString: true});
|
win.switchToTabHavingURI(url, true, {
|
||||||
|
ignoreFragment: true,
|
||||||
|
replaceQueryString: true,
|
||||||
|
});
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
log.error("Error opening Getting Started tour", ex);
|
log.error("Error opening Getting Started tour", ex);
|
||||||
}
|
}
|
||||||
|
@ -166,11 +166,14 @@ loop.panel = (function(_, mozL10n) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var GettingStartedView = React.createClass({displayName: 'GettingStartedView',
|
var GettingStartedView = React.createClass({displayName: 'GettingStartedView',
|
||||||
|
mixins: [sharedMixins.WindowCloseMixin],
|
||||||
|
|
||||||
handleButtonClick: function() {
|
handleButtonClick: function() {
|
||||||
navigator.mozLoop.openGettingStartedTour("getting-started");
|
navigator.mozLoop.openGettingStartedTour("getting-started");
|
||||||
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
|
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
|
||||||
var event = new CustomEvent("GettingStartedSeen");
|
var event = new CustomEvent("GettingStartedSeen");
|
||||||
window.dispatchEvent(event);
|
window.dispatchEvent(event);
|
||||||
|
this.closeWindow();
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
@ -269,7 +272,7 @@ loop.panel = (function(_, mozL10n) {
|
|||||||
* Panel settings (gear) menu.
|
* Panel settings (gear) menu.
|
||||||
*/
|
*/
|
||||||
var SettingsDropdown = React.createClass({displayName: 'SettingsDropdown',
|
var SettingsDropdown = React.createClass({displayName: 'SettingsDropdown',
|
||||||
mixins: [sharedMixins.DropdownMenuMixin],
|
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.WindowCloseMixin],
|
||||||
|
|
||||||
handleClickSettingsEntry: function() {
|
handleClickSettingsEntry: function() {
|
||||||
// XXX to be implemented at the same time as unhiding the entry
|
// XXX to be implemented at the same time as unhiding the entry
|
||||||
@ -300,6 +303,7 @@ loop.panel = (function(_, mozL10n) {
|
|||||||
|
|
||||||
openGettingStartedTour: function() {
|
openGettingStartedTour: function() {
|
||||||
navigator.mozLoop.openGettingStartedTour("settings-menu");
|
navigator.mozLoop.openGettingStartedTour("settings-menu");
|
||||||
|
this.closeWindow();
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -166,11 +166,14 @@ loop.panel = (function(_, mozL10n) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var GettingStartedView = React.createClass({
|
var GettingStartedView = React.createClass({
|
||||||
|
mixins: [sharedMixins.WindowCloseMixin],
|
||||||
|
|
||||||
handleButtonClick: function() {
|
handleButtonClick: function() {
|
||||||
navigator.mozLoop.openGettingStartedTour("getting-started");
|
navigator.mozLoop.openGettingStartedTour("getting-started");
|
||||||
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
|
navigator.mozLoop.setLoopPref("gettingStarted.seen", true);
|
||||||
var event = new CustomEvent("GettingStartedSeen");
|
var event = new CustomEvent("GettingStartedSeen");
|
||||||
window.dispatchEvent(event);
|
window.dispatchEvent(event);
|
||||||
|
this.closeWindow();
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
@ -269,7 +272,7 @@ loop.panel = (function(_, mozL10n) {
|
|||||||
* Panel settings (gear) menu.
|
* Panel settings (gear) menu.
|
||||||
*/
|
*/
|
||||||
var SettingsDropdown = React.createClass({
|
var SettingsDropdown = React.createClass({
|
||||||
mixins: [sharedMixins.DropdownMenuMixin],
|
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.WindowCloseMixin],
|
||||||
|
|
||||||
handleClickSettingsEntry: function() {
|
handleClickSettingsEntry: function() {
|
||||||
// XXX to be implemented at the same time as unhiding the entry
|
// XXX to be implemented at the same time as unhiding the entry
|
||||||
@ -300,6 +303,7 @@ loop.panel = (function(_, mozL10n) {
|
|||||||
|
|
||||||
openGettingStartedTour: function() {
|
openGettingStartedTour: function() {
|
||||||
navigator.mozLoop.openGettingStartedTour("settings-menu");
|
navigator.mozLoop.openGettingStartedTour("settings-menu");
|
||||||
|
this.closeWindow();
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -89,6 +89,9 @@ let gSubDialog = {
|
|||||||
this._overlay.style.visibility = "";
|
this._overlay.style.visibility = "";
|
||||||
// Clear the sizing inline styles.
|
// Clear the sizing inline styles.
|
||||||
this._frame.removeAttribute("style");
|
this._frame.removeAttribute("style");
|
||||||
|
// Clear the sizing attributes
|
||||||
|
this._box.removeAttribute("width");
|
||||||
|
this._box.removeAttribute("height");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Unload the dialog after the event listeners run so that the load of about:blank isn't
|
// Unload the dialog after the event listeners run so that the load of about:blank isn't
|
||||||
|
@ -9,6 +9,12 @@ XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () {
|
|||||||
return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
|
return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
|
||||||
|
"resource://gre/modules/FxAccounts.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "fxaMigrator",
|
||||||
|
"resource://services-sync/FxaMigrator.jsm");
|
||||||
|
|
||||||
const PAGE_NO_ACCOUNT = 0;
|
const PAGE_NO_ACCOUNT = 0;
|
||||||
const PAGE_HAS_ACCOUNT = 1;
|
const PAGE_HAS_ACCOUNT = 1;
|
||||||
const PAGE_NEEDS_UPDATE = 2;
|
const PAGE_NEEDS_UPDATE = 2;
|
||||||
@ -25,7 +31,6 @@ const FXA_LOGIN_UNVERIFIED = 1;
|
|||||||
const FXA_LOGIN_FAILED = 2;
|
const FXA_LOGIN_FAILED = 2;
|
||||||
|
|
||||||
let gSyncPane = {
|
let gSyncPane = {
|
||||||
_stringBundle: null,
|
|
||||||
prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
|
prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
|
||||||
"engine.tabs", "engine.history"],
|
"engine.tabs", "engine.history"],
|
||||||
|
|
||||||
@ -91,6 +96,7 @@ let gSyncPane = {
|
|||||||
"weave:service:setup-complete",
|
"weave:service:setup-complete",
|
||||||
"weave:service:logout:finish",
|
"weave:service:logout:finish",
|
||||||
FxAccountsCommon.ONVERIFIED_NOTIFICATION];
|
FxAccountsCommon.ONVERIFIED_NOTIFICATION];
|
||||||
|
let migrateTopic = "fxa-migration:state-changed";
|
||||||
|
|
||||||
// Add the observers now and remove them on unload
|
// Add the observers now and remove them on unload
|
||||||
//XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
|
//XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
|
||||||
@ -98,14 +104,30 @@ let gSyncPane = {
|
|||||||
topics.forEach(function (topic) {
|
topics.forEach(function (topic) {
|
||||||
Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
|
Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
|
||||||
}, this);
|
}, this);
|
||||||
|
// The FxA migration observer is a special case.
|
||||||
|
Weave.Svc.Obs.add(migrateTopic, this.updateMigrationState, this);
|
||||||
|
|
||||||
window.addEventListener("unload", function() {
|
window.addEventListener("unload", function() {
|
||||||
topics.forEach(function (topic) {
|
topics.forEach(function (topic) {
|
||||||
Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
|
Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
|
||||||
}, gSyncPane);
|
}, gSyncPane);
|
||||||
|
Weave.Svc.Obs.remove(migrateTopic, gSyncPane.updateMigrationState, gSyncPane);
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
this._stringBundle =
|
// ask the migration module to broadcast its current state (and nothing will
|
||||||
Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
|
// happen if it's not loaded - which is good, as that means no migration
|
||||||
|
// is pending/necessary) - we don't want to suck that module in just to
|
||||||
|
// find there's nothing to do.
|
||||||
|
Services.obs.notifyObservers(null, "fxa-migration:state-request", null);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, '_stringBundle', () => {
|
||||||
|
return Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
|
||||||
|
}),
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, '_accountsStringBundle', () => {
|
||||||
|
return Services.strings.createBundle("chrome://browser/locale/accounts.properties");
|
||||||
|
}),
|
||||||
|
|
||||||
this.updateWeavePrefs();
|
this.updateWeavePrefs();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -192,6 +214,17 @@ let gSyncPane = {
|
|||||||
});
|
});
|
||||||
setEventListener("tosPP-small-ToS", "click", gSyncPane.openToS);
|
setEventListener("tosPP-small-ToS", "click", gSyncPane.openToS);
|
||||||
setEventListener("tosPP-small-PP", "click", gSyncPane.openPrivacyPolicy);
|
setEventListener("tosPP-small-PP", "click", gSyncPane.openPrivacyPolicy);
|
||||||
|
setEventListener("sync-migrate-upgrade", "click", function () {
|
||||||
|
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||||
|
fxaMigrator.createFxAccount(win);
|
||||||
|
});
|
||||||
|
setEventListener("sync-migrate-forget", "click", function () {
|
||||||
|
fxaMigrator.forgetFxAccount();
|
||||||
|
});
|
||||||
|
setEventListener("sync-migrate-resend", "click", function () {
|
||||||
|
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||||
|
fxaMigrator.resendVerificationMail(win);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateWeavePrefs: function () {
|
updateWeavePrefs: function () {
|
||||||
@ -203,7 +236,6 @@ let gSyncPane = {
|
|||||||
if (service.fxAccountsEnabled) {
|
if (service.fxAccountsEnabled) {
|
||||||
// determine the fxa status...
|
// determine the fxa status...
|
||||||
this.page = PAGE_PLEASE_WAIT;
|
this.page = PAGE_PLEASE_WAIT;
|
||||||
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
|
|
||||||
fxAccounts.getSignedInUser().then(data => {
|
fxAccounts.getSignedInUser().then(data => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.page = FXA_PAGE_LOGGED_OUT;
|
this.page = FXA_PAGE_LOGGED_OUT;
|
||||||
@ -262,6 +294,45 @@ let gSyncPane = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateMigrationState: function(subject, state) {
|
||||||
|
let selIndex;
|
||||||
|
switch (state) {
|
||||||
|
case fxaMigrator.STATE_USER_FXA: {
|
||||||
|
let sb = this._accountsStringBundle;
|
||||||
|
let button = document.getElementById("sync-migrate-upgrade");
|
||||||
|
button.setAttribute("label", sb.GetStringFromName("upgradeToFxA.label"));
|
||||||
|
button.setAttribute("accesskey", sb.GetStringFromName("upgradeToFxA.accessKey"));
|
||||||
|
selIndex = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case fxaMigrator.STATE_USER_FXA_VERIFIED: {
|
||||||
|
let sb = this._accountsStringBundle;
|
||||||
|
let email = subject.QueryInterface(Components.interfaces.nsISupportsString).data;
|
||||||
|
let label = sb.formatStringFromName("needVerifiedUserLong", [email], 1);
|
||||||
|
let elt = document.getElementById("sync-migrate-verify-label");
|
||||||
|
elt.setAttribute("value", label);
|
||||||
|
// The "resend" button.
|
||||||
|
let button = document.getElementById("sync-migrate-resend");
|
||||||
|
button.setAttribute("label", sb.GetStringFromName("resendVerificationEmail.label"));
|
||||||
|
button.setAttribute("accesskey", sb.GetStringFromName("resendVerificationEmail.accessKey"));
|
||||||
|
// The "forget" button.
|
||||||
|
button = document.getElementById("sync-migrate-forget");
|
||||||
|
button.setAttribute("label", sb.GetStringFromName("forgetMigration.label"));
|
||||||
|
button.setAttribute("accesskey", sb.GetStringFromName("forgetMigration.accessKey"));
|
||||||
|
selIndex = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (state) { // |null| is expected, but everything else is not.
|
||||||
|
Cu.reportError("updateMigrationState has unknown state: " + state);
|
||||||
|
}
|
||||||
|
document.getElementById("sync-migration").hidden = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.getElementById("sync-migration").hidden = false;
|
||||||
|
document.getElementById("sync-migration-deck").selectedIndex = selIndex;
|
||||||
|
},
|
||||||
|
|
||||||
startOver: function (showDialog) {
|
startOver: function (showDialog) {
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
|
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
|
||||||
@ -375,14 +446,13 @@ let gSyncPane = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
verifyFirefoxAccount: function() {
|
verifyFirefoxAccount: function() {
|
||||||
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
|
|
||||||
fxAccounts.resendVerificationEmail().then(() => {
|
fxAccounts.resendVerificationEmail().then(() => {
|
||||||
fxAccounts.getSignedInUser().then(data => {
|
fxAccounts.getSignedInUser().then(data => {
|
||||||
let sb = this._stringBundle;
|
let sb = this._accountsStringBundle;
|
||||||
let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
|
let title = sb.GetStringFromName("verificationSentTitle");
|
||||||
let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
|
let heading = sb.formatStringFromName("verificationSentHeading",
|
||||||
[data.email], 1);
|
[data.email], 1);
|
||||||
let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
|
let description = sb.GetStringFromName("verificationSentDescription");
|
||||||
|
|
||||||
let factory = Cc["@mozilla.org/prompter;1"]
|
let factory = Cc["@mozilla.org/prompter;1"]
|
||||||
.getService(Ci.nsIPromptFactory);
|
.getService(Ci.nsIPromptFactory);
|
||||||
@ -430,7 +500,6 @@ let gSyncPane = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
|
||||||
fxAccounts.signOut().then(() => {
|
fxAccounts.signOut().then(() => {
|
||||||
this.updateWeavePrefs();
|
this.updateWeavePrefs();
|
||||||
});
|
});
|
||||||
|
@ -37,6 +37,31 @@
|
|||||||
<label class="header-name">&paneSync.title;</label>
|
<label class="header-name">&paneSync.title;</label>
|
||||||
</hbox>
|
</hbox>
|
||||||
|
|
||||||
|
<hbox id="sync-migration-container"
|
||||||
|
data-category="paneSync"
|
||||||
|
hidden="true">
|
||||||
|
|
||||||
|
<vbox id="sync-migration" flex="1" hidden="true">
|
||||||
|
|
||||||
|
<deck id="sync-migration-deck">
|
||||||
|
<!-- When we are in the "need FxA user" state -->
|
||||||
|
<hbox align="center">
|
||||||
|
<label>&migrate.upgradeNeeded;</label>
|
||||||
|
<spacer flex="1"/>
|
||||||
|
<button id="sync-migrate-upgrade"/>
|
||||||
|
</hbox>
|
||||||
|
|
||||||
|
<!-- When we are in the "need the user to be verified" state -->
|
||||||
|
<hbox align="center">
|
||||||
|
<label id="sync-migrate-verify-label"/>
|
||||||
|
<spacer flex="1"/>
|
||||||
|
<button id="sync-migrate-forget"/>
|
||||||
|
<button id="sync-migrate-resend"/>
|
||||||
|
</hbox>
|
||||||
|
</deck>
|
||||||
|
</vbox>
|
||||||
|
</hbox>
|
||||||
|
|
||||||
<deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
|
<deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
|
||||||
<!-- These panels are for the "legacy" sync provider -->
|
<!-- These panels are for the "legacy" sync provider -->
|
||||||
<vbox id="noAccount" align="center">
|
<vbox id="noAccount" align="center">
|
||||||
|
@ -285,11 +285,11 @@ let gSyncPane = {
|
|||||||
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
|
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
|
||||||
fxAccounts.resendVerificationEmail().then(() => {
|
fxAccounts.resendVerificationEmail().then(() => {
|
||||||
fxAccounts.getSignedInUser().then(data => {
|
fxAccounts.getSignedInUser().then(data => {
|
||||||
let sb = this._stringBundle;
|
let sb = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
|
||||||
let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
|
let title = sb.GetStringFromName("verificationSentTitle");
|
||||||
let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
|
let heading = sb.formatStringFromName("verificationSentHeading",
|
||||||
[data.email], 1);
|
[data.email], 1);
|
||||||
let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
|
let description = sb.GetStringFromName("verificationSentDescription");
|
||||||
|
|
||||||
Services.prompt.alert(window, title, heading + "\n\n" + description);
|
Services.prompt.alert(window, title, heading + "\n\n" + description);
|
||||||
});
|
});
|
||||||
|
@ -472,6 +472,8 @@
|
|||||||
var textValue = textBox.value;
|
var textValue = textBox.value;
|
||||||
|
|
||||||
var where = "current";
|
var where = "current";
|
||||||
|
|
||||||
|
// Open ctrl/cmd clicks on one-off buttons in a new background tab.
|
||||||
if (aEvent && aEvent.originalTarget.getAttribute("anonid") == "search-go-button") {
|
if (aEvent && aEvent.originalTarget.getAttribute("anonid") == "search-go-button") {
|
||||||
if (aEvent.button == 2)
|
if (aEvent.button == 2)
|
||||||
return;
|
return;
|
||||||
@ -479,11 +481,20 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab");
|
var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab");
|
||||||
if ((aEvent && aEvent.altKey) ^ newTabPref)
|
if (((aEvent instanceof KeyboardEvent) && aEvent.altKey) ^ newTabPref)
|
||||||
where = "tab";
|
where = "tab";
|
||||||
|
if ((aEvent instanceof MouseEvent) && (aEvent.button == 1 ||
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
aEvent.metaKey))
|
||||||
|
#else
|
||||||
|
aEvent.ctrlKey))
|
||||||
|
#endif
|
||||||
|
where = "tab-background";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.doSearch(textValue, where, aEngine);
|
this.doSearch(textValue, where, aEngine);
|
||||||
|
if (where == "tab-background")
|
||||||
|
this.focus();
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
@ -509,7 +520,13 @@
|
|||||||
var submission = engine.getSubmission(aData, null, "searchbar");
|
var submission = engine.getSubmission(aData, null, "searchbar");
|
||||||
BrowserSearch.recordSearchInHealthReport(engine, "searchbar");
|
BrowserSearch.recordSearchInHealthReport(engine, "searchbar");
|
||||||
// null parameter below specifies HTML response for search
|
// null parameter below specifies HTML response for search
|
||||||
openUILinkIn(submission.uri.spec, aWhere, null, submission.postData);
|
let params = {
|
||||||
|
postData: submission.postData,
|
||||||
|
inBackground: aWhere == "tab-background"
|
||||||
|
};
|
||||||
|
openUILinkIn(submission.uri.spec,
|
||||||
|
aWhere == "tab-background" ? "tab" : aWhere,
|
||||||
|
params);
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
</implementation>
|
</implementation>
|
||||||
|
@ -38,7 +38,9 @@ exports.items = [{
|
|||||||
let chromeWindow = context.environment.chromeWindow;
|
let chromeWindow = context.environment.chromeWindow;
|
||||||
let target = context.environment.target;
|
let target = context.environment.target;
|
||||||
|
|
||||||
let dropper = EyedropperManager.createInstance(chromeWindow);
|
let dropper = EyedropperManager.createInstance(chromeWindow,
|
||||||
|
{ context: "command",
|
||||||
|
copyOnSelect: true });
|
||||||
dropper.open();
|
dropper.open();
|
||||||
|
|
||||||
eventEmitter.emit("changed", { target: target });
|
eventEmitter.emit("changed", { target: target });
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
const {Cc, Ci, Cu} = require("chrome");
|
const {Cc, Ci, Cu} = require("chrome");
|
||||||
const {rgbToHsl} = require("devtools/css-color").colorUtils;
|
const {rgbToHsl} = require("devtools/css-color").colorUtils;
|
||||||
|
const Telemetry = require("devtools/shared/telemetry");
|
||||||
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||||
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||||
const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
|
const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||||
@ -61,13 +62,13 @@ let EyedropperManager = {
|
|||||||
return this._instances.get(chromeWindow);
|
return this._instances.get(chromeWindow);
|
||||||
},
|
},
|
||||||
|
|
||||||
createInstance: function(chromeWindow) {
|
createInstance: function(chromeWindow, options) {
|
||||||
let dropper = this.getInstance(chromeWindow);
|
let dropper = this.getInstance(chromeWindow);
|
||||||
if (dropper) {
|
if (dropper) {
|
||||||
return dropper;
|
return dropper;
|
||||||
}
|
}
|
||||||
|
|
||||||
dropper = new Eyedropper(chromeWindow);
|
dropper = new Eyedropper(chromeWindow, options);
|
||||||
this._instances.set(chromeWindow, dropper);
|
this._instances.set(chromeWindow, dropper);
|
||||||
|
|
||||||
dropper.on("destroy", () => {
|
dropper.on("destroy", () => {
|
||||||
@ -100,9 +101,9 @@ exports.EyedropperManager = EyedropperManager;
|
|||||||
* @param {DOMWindow} chromeWindow
|
* @param {DOMWindow} chromeWindow
|
||||||
* window to inspect
|
* window to inspect
|
||||||
* @param {object} opts
|
* @param {object} opts
|
||||||
* optional options object, with 'copyOnSelect'
|
* optional options object, with 'copyOnSelect', 'context'
|
||||||
*/
|
*/
|
||||||
function Eyedropper(chromeWindow, opts = { copyOnSelect: true }) {
|
function Eyedropper(chromeWindow, opts = { copyOnSelect: true, context: "other" }) {
|
||||||
this.copyOnSelect = opts.copyOnSelect;
|
this.copyOnSelect = opts.copyOnSelect;
|
||||||
|
|
||||||
this._onFirstMouseMove = this._onFirstMouseMove.bind(this);
|
this._onFirstMouseMove = this._onFirstMouseMove.bind(this);
|
||||||
@ -134,6 +135,18 @@ function Eyedropper(chromeWindow, opts = { copyOnSelect: true }) {
|
|||||||
let mm = this._contentTab.linkedBrowser.messageManager;
|
let mm = this._contentTab.linkedBrowser.messageManager;
|
||||||
mm.loadFrameScript("resource:///modules/devtools/eyedropper/eyedropper-child.js", true);
|
mm.loadFrameScript("resource:///modules/devtools/eyedropper/eyedropper-child.js", true);
|
||||||
|
|
||||||
|
// record if this was opened via the picker or standalone
|
||||||
|
var telemetry = new Telemetry();
|
||||||
|
if (opts.context == "command") {
|
||||||
|
telemetry.toolOpened("eyedropper");
|
||||||
|
}
|
||||||
|
else if (opts.context == "menu") {
|
||||||
|
telemetry.toolOpened("menueyedropper");
|
||||||
|
}
|
||||||
|
else if (opts.context == "picker") {
|
||||||
|
telemetry.toolOpened("pickereyedropper");
|
||||||
|
}
|
||||||
|
|
||||||
EventEmitter.decorate(this);
|
EventEmitter.decorate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
|||||||
const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
|
const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
|
||||||
const MAX_LABEL_LENGTH = 40;
|
const MAX_LABEL_LENGTH = 40;
|
||||||
|
|
||||||
let promise = require("devtools/toolkit/deprecated-sync-thenables");
|
let promise = require("resource://gre/modules/Promise.jsm").Promise;
|
||||||
|
|
||||||
const LOW_PRIORITY_ELEMENTS = {
|
const LOW_PRIORITY_ELEMENTS = {
|
||||||
"HEAD": true,
|
"HEAD": true,
|
||||||
@ -138,13 +138,14 @@ HTMLBreadcrumbs.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print any errors (except selection guard errors).
|
* Warn if rejection was caused by selection change, print an error otherwise.
|
||||||
*/
|
*/
|
||||||
selectionGuardEnd: function(err) {
|
selectionGuardEnd: function(err) {
|
||||||
if (err != "selection-changed") {
|
if (err === "selection-changed") {
|
||||||
|
console.warn("Asynchronous operation was aborted as selection changed.");
|
||||||
|
} else {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
promise.reject(err);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +8,7 @@ const {Cc, Ci, Cu, Cr} = require("chrome");
|
|||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
let promise = require("devtools/toolkit/deprecated-sync-thenables");
|
let promise = require("resource://gre/modules/Promise.jsm").Promise;
|
||||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||||
let clipboard = require("sdk/clipboard");
|
let clipboard = require("sdk/clipboard");
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const promise = require("devtools/toolkit/deprecated-sync-thenables");
|
const promise = require("resource://gre/modules/Promise.jsm").Promise;
|
||||||
loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
|
loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
|
||||||
loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
|
loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
|
||||||
|
|
||||||
|
@ -170,6 +170,18 @@ Telemetry.prototype = {
|
|||||||
userHistogram: "DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG",
|
userHistogram: "DEVTOOLS_RESPONSIVE_OPENED_PER_USER_FLAG",
|
||||||
timerHistogram: "DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS"
|
timerHistogram: "DEVTOOLS_RESPONSIVE_TIME_ACTIVE_SECONDS"
|
||||||
},
|
},
|
||||||
|
eyedropper: {
|
||||||
|
histogram: "DEVTOOLS_EYEDROPPER_OPENED_BOOLEAN",
|
||||||
|
userHistogram: "DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||||
|
},
|
||||||
|
menueyedropper: {
|
||||||
|
histogram: "DEVTOOLS_MENU_EYEDROPPER_OPENED_BOOLEAN",
|
||||||
|
userHistogram: "DEVTOOLS_MENU_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||||
|
},
|
||||||
|
pickereyedropper: {
|
||||||
|
histogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN",
|
||||||
|
userHistogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG",
|
||||||
|
},
|
||||||
developertoolbar: {
|
developertoolbar: {
|
||||||
histogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_BOOLEAN",
|
histogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_BOOLEAN",
|
||||||
userHistogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG",
|
userHistogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG",
|
||||||
|
@ -50,6 +50,7 @@ support-files =
|
|||||||
[browser_tableWidget_keyboard_interaction.js]
|
[browser_tableWidget_keyboard_interaction.js]
|
||||||
[browser_tableWidget_mouse_interaction.js]
|
[browser_tableWidget_mouse_interaction.js]
|
||||||
skip-if = buildapp == 'mulet'
|
skip-if = buildapp == 'mulet'
|
||||||
|
[browser_telemetry_button_eyedropper.js]
|
||||||
[browser_telemetry_button_paintflashing.js]
|
[browser_telemetry_button_paintflashing.js]
|
||||||
[browser_telemetry_button_responsive.js]
|
[browser_telemetry_button_responsive.js]
|
||||||
[browser_telemetry_button_scratchpad.js]
|
[browser_telemetry_button_scratchpad.js]
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_button_eyedropper.js</p><div>test</div>";
|
||||||
|
|
||||||
|
let promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise;
|
||||||
|
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||||
|
|
||||||
|
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||||
|
let Telemetry = require("devtools/shared/telemetry");
|
||||||
|
|
||||||
|
let { EyedropperManager } = require("devtools/eyedropper/eyedropper");
|
||||||
|
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
Telemetry.prototype.telemetryInfo = {};
|
||||||
|
Telemetry.prototype._oldlog = Telemetry.prototype.log;
|
||||||
|
Telemetry.prototype.log = function(histogramId, value) {
|
||||||
|
if (!this.telemetryInfo) {
|
||||||
|
// Can be removed when Bug 992911 lands (see Bug 1011652 Comment 10)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (histogramId) {
|
||||||
|
if (!this.telemetryInfo[histogramId]) {
|
||||||
|
this.telemetryInfo[histogramId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.telemetryInfo[histogramId].push(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
testButton("command-button-eyedropper");
|
||||||
|
}
|
||||||
|
|
||||||
|
function testButton(id) {
|
||||||
|
info("Testing " + id);
|
||||||
|
|
||||||
|
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||||
|
|
||||||
|
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||||
|
info("inspector opened");
|
||||||
|
|
||||||
|
let button = toolbox.doc.querySelector("#" + id);
|
||||||
|
ok(button, "Captain, we have the button");
|
||||||
|
|
||||||
|
// open the eyedropper
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
checkResults("_EYEDROPPER_");
|
||||||
|
}).then(null, console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickButton(node, clicks) {
|
||||||
|
for (let i = 0; i < clicks; i++) {
|
||||||
|
info("Clicking button " + node.id);
|
||||||
|
node.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkResults(histIdFocus) {
|
||||||
|
let result = Telemetry.prototype.telemetryInfo;
|
||||||
|
|
||||||
|
for (let [histId, value] of Iterator(result)) {
|
||||||
|
if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
|
||||||
|
!histId.contains(histIdFocus)) {
|
||||||
|
// Inspector stats are tested in
|
||||||
|
// browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
|
||||||
|
// because we only open the inspector once for this test.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (histId.endsWith("OPENED_PER_USER_FLAG")) {
|
||||||
|
ok(value.length === 1 && value[0] === true,
|
||||||
|
"Per user value " + histId + " has a single value of true");
|
||||||
|
} else if (histId.endsWith("OPENED_BOOLEAN")) {
|
||||||
|
ok(value.length == 1, histId + " has one entry");
|
||||||
|
|
||||||
|
let okay = value.every(function(element) {
|
||||||
|
return element === true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(okay, "All " + histId + " entries are === true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finishUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishUp() {
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
|
||||||
|
Telemetry.prototype.log = Telemetry.prototype._oldlog;
|
||||||
|
delete Telemetry.prototype._oldlog;
|
||||||
|
delete Telemetry.prototype.telemetryInfo;
|
||||||
|
|
||||||
|
TargetFactory = Services = promise = require = null;
|
||||||
|
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||||
|
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||||
|
waitForFocus(init, content);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
content.location = TEST_URI;
|
||||||
|
}
|
@ -1086,7 +1086,8 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
|
|||||||
chromeWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
chromeWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||||
chromeWindow.focus();
|
chromeWindow.focus();
|
||||||
}
|
}
|
||||||
let dropper = new Eyedropper(chromeWindow, { copyOnSelect: false });
|
let dropper = new Eyedropper(chromeWindow, { copyOnSelect: false,
|
||||||
|
context: "picker" });
|
||||||
|
|
||||||
dropper.once("select", (event, color) => {
|
dropper.once("select", (event, color) => {
|
||||||
if (toolboxWindow) {
|
if (toolboxWindow) {
|
||||||
|
@ -4,6 +4,19 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// So we can test collecting telemetry on the eyedropper
|
||||||
|
let oldCanRecord = Services.telemetry.canRecord;
|
||||||
|
Services.telemetry.canRecord = true;
|
||||||
|
registerCleanupFunction(function () {
|
||||||
|
Services.telemetry.canRecord = oldCanRecord;
|
||||||
|
});
|
||||||
|
const HISTOGRAM_ID = "DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN";
|
||||||
|
const FLAG_HISTOGRAM_ID = "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG";
|
||||||
|
const EXPECTED_TELEMETRY = {
|
||||||
|
"DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN": 2,
|
||||||
|
"DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG": 1
|
||||||
|
}
|
||||||
|
|
||||||
const PAGE_CONTENT = [
|
const PAGE_CONTENT = [
|
||||||
'<style type="text/css">',
|
'<style type="text/css">',
|
||||||
' body {',
|
' body {',
|
||||||
@ -34,6 +47,9 @@ const EXPECTED_COLOR = "rgb(255, 255, 85)"; // #ff5
|
|||||||
// to close it, and clicking the page to select a color.
|
// to close it, and clicking the page to select a color.
|
||||||
|
|
||||||
add_task(function*() {
|
add_task(function*() {
|
||||||
|
// clear telemetry so we can get accurate counts
|
||||||
|
clearTelemetry();
|
||||||
|
|
||||||
yield addTab("data:text/html;charset=utf-8,rule view eyedropper test");
|
yield addTab("data:text/html;charset=utf-8,rule view eyedropper test");
|
||||||
content.document.body.innerHTML = PAGE_CONTENT;
|
content.document.body.innerHTML = PAGE_CONTENT;
|
||||||
|
|
||||||
@ -57,6 +73,8 @@ add_task(function*() {
|
|||||||
ok(dropper, "dropper opened");
|
ok(dropper, "dropper opened");
|
||||||
|
|
||||||
yield testSelect(swatch, dropper);
|
yield testSelect(swatch, dropper);
|
||||||
|
|
||||||
|
checkTelemetry();
|
||||||
});
|
});
|
||||||
|
|
||||||
function testESC(swatch, dropper) {
|
function testESC(swatch, dropper) {
|
||||||
@ -97,6 +115,23 @@ function testSelect(swatch, dropper) {
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearTelemetry() {
|
||||||
|
for (let histogramId in EXPECTED_TELEMETRY) {
|
||||||
|
let histogram = Services.telemetry.getHistogramById(histogramId);
|
||||||
|
histogram.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkTelemetry() {
|
||||||
|
for (let histogramId in EXPECTED_TELEMETRY) {
|
||||||
|
let expected = EXPECTED_TELEMETRY[histogramId];
|
||||||
|
let histogram = Services.telemetry.getHistogramById(histogramId);
|
||||||
|
let snapshot = histogram.snapshot();
|
||||||
|
|
||||||
|
is (snapshot.counts[1], expected,
|
||||||
|
"eyedropper telemetry value correct for " + histogramId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Helpers */
|
/* Helpers */
|
||||||
|
|
||||||
|
@ -28,12 +28,20 @@ function spawnTest() {
|
|||||||
"curve": "Float32Array"
|
"curve": "Float32Array"
|
||||||
}, "WaveShaper's `curve` is listed as an `Float32Array`.");
|
}, "WaveShaper's `curve` is listed as an `Float32Array`.");
|
||||||
|
|
||||||
|
let aVar = gVars.getScopeAtIndex(0).get("curve")
|
||||||
|
let state = aVar.target.querySelector(".theme-twisty").hasAttribute("invisible");
|
||||||
|
ok(state, "Float32Array property should not have a dropdown.");
|
||||||
|
|
||||||
click(panelWin, findGraphNode(panelWin, nodeIds[1]));
|
click(panelWin, findGraphNode(panelWin, nodeIds[1]));
|
||||||
yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
|
yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
|
||||||
checkVariableView(gVars, 0, {
|
checkVariableView(gVars, 0, {
|
||||||
"buffer": "AudioBuffer"
|
"buffer": "AudioBuffer"
|
||||||
}, "AudioBufferSourceNode's `buffer` is listed as an `AudioBuffer`.");
|
}, "AudioBufferSourceNode's `buffer` is listed as an `AudioBuffer`.");
|
||||||
|
|
||||||
|
aVar = gVars.getScopeAtIndex(0).get("buffer")
|
||||||
|
state = aVar.target.querySelector(".theme-twisty").hasAttribute("invisible");
|
||||||
|
ok(state, "AudioBuffer property should not have a dropdown.");
|
||||||
|
|
||||||
yield teardown(panel);
|
yield teardown(panel);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,10 @@ let InspectorView = {
|
|||||||
value: value,
|
value: value,
|
||||||
writable: !flags || !flags.readonly,
|
writable: !flags || !flags.readonly,
|
||||||
};
|
};
|
||||||
audioParamsScope.addItem(param, descriptor);
|
let item = audioParamsScope.addItem(param, descriptor);
|
||||||
|
|
||||||
|
// No items should currently display a dropdown
|
||||||
|
item.twisty = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
audioParamsScope.expanded = true;
|
audioParamsScope.expanded = true;
|
||||||
|
@ -17,3 +17,17 @@ needVerifiedUserLong = Please click the verification link in the email sent to %
|
|||||||
|
|
||||||
resendVerificationEmail.label = Resend
|
resendVerificationEmail.label = Resend
|
||||||
resendVerificationEmail.accessKey = R
|
resendVerificationEmail.accessKey = R
|
||||||
|
|
||||||
|
forgetMigration.label = Forget
|
||||||
|
forgetMigration.accessKey = F
|
||||||
|
|
||||||
|
# These strings are used in a dialog we display after the user requests we resend
|
||||||
|
# a verification email.
|
||||||
|
verificationSentTitle = Verification Sent
|
||||||
|
# LOCALIZATION NOTE (verificationSentHeading) - %S = Email address of user's Firefox Account
|
||||||
|
verificationSentHeading = A verification link has been sent to %S
|
||||||
|
verificationSentDescription = Please check your email and click the link to begin syncing.
|
||||||
|
|
||||||
|
verificationNotSentTitle = Unable to Send Verification
|
||||||
|
verificationNotSentHeading = We are unable to send a verification mail at this time
|
||||||
|
verificationNotSentDescription = Please try again later.
|
||||||
|
@ -137,9 +137,3 @@ syncUnlinkConfirm.label=Unlink
|
|||||||
featureEnableRequiresRestart=%S must restart to enable this feature.
|
featureEnableRequiresRestart=%S must restart to enable this feature.
|
||||||
featureDisableRequiresRestart=%S must restart to disable this feature.
|
featureDisableRequiresRestart=%S must restart to disable this feature.
|
||||||
shouldRestartTitle=Restart %S
|
shouldRestartTitle=Restart %S
|
||||||
|
|
||||||
###Preferences::Sync::Firefox Accounts
|
|
||||||
firefoxAccountsVerificationSentTitle=Verification Sent
|
|
||||||
# LOCALIZATION NOTE: %S = user's email address.
|
|
||||||
firefoxAccountsVerificationSentHeading=A verification link has been sent to %S
|
|
||||||
firefoxAccountVerificationSentDescription=Please check your email and click the link to begin syncing.
|
|
||||||
|
@ -78,3 +78,6 @@ both, to better adapt this sentence to their language.
|
|||||||
<!ENTITY welcome.createAccount.label "Create Account">
|
<!ENTITY welcome.createAccount.label "Create Account">
|
||||||
|
|
||||||
<!ENTITY welcome.useOldSync.label "Using an older version of Sync?">
|
<!ENTITY welcome.useOldSync.label "Using an older version of Sync?">
|
||||||
|
|
||||||
|
<!-- Sync Migration -->
|
||||||
|
<!ENTITY migrate.upgradeNeeded "The sync account system is being discontinued. A new Firefox Account is required to sync.">
|
||||||
|
@ -543,6 +543,16 @@ this.UITour = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "setConfiguration": {
|
||||||
|
if (typeof data.configuration != "string") {
|
||||||
|
log.warn("setConfiguration: No configuration option specified");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setConfiguration(data.configuration, data.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "showFirefoxAccounts": {
|
case "showFirefoxAccounts": {
|
||||||
// 'signup' is the only action that makes sense currently, so we don't
|
// 'signup' is the only action that makes sense currently, so we don't
|
||||||
// accept arbitrary actions just to be safe...
|
// accept arbitrary actions just to be safe...
|
||||||
@ -1321,7 +1331,7 @@ this.UITour = {
|
|||||||
|
|
||||||
// An event object is expected but we don't want to toggle the panel with a click if the panel
|
// An event object is expected but we don't want to toggle the panel with a click if the panel
|
||||||
// is already open.
|
// is already open.
|
||||||
aWindow.LoopUI.openCallPanel({ target: toolbarButton.node, }).then(() => {
|
aWindow.LoopUI.openCallPanel({ target: toolbarButton.node, }, "rooms").then(() => {
|
||||||
if (aOpenCallback) {
|
if (aOpenCallback) {
|
||||||
aOpenCallback();
|
aOpenCallback();
|
||||||
}
|
}
|
||||||
@ -1479,6 +1489,18 @@ this.UITour = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setConfiguration: function(aConfiguration, aValue) {
|
||||||
|
switch (aConfiguration) {
|
||||||
|
case "Loop:ResumeTourOnFirstJoin":
|
||||||
|
// Ignore aValue in this case to avoid accidentally setting it to false.
|
||||||
|
Services.prefs.setBoolPref("loop.gettingStarted.resumeOnFirstJoin", true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.error("setConfiguration: Unknown configuration requested: " + aConfiguration);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getAvailableTargets: function(aMessageManager, aChromeWindow, aCallbackID) {
|
getAvailableTargets: function(aMessageManager, aChromeWindow, aCallbackID) {
|
||||||
Task.spawn(function*() {
|
Task.spawn(function*() {
|
||||||
let window = aChromeWindow;
|
let window = aChromeWindow;
|
||||||
|
@ -173,6 +173,68 @@ let tests = [
|
|||||||
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be underneath");
|
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be underneath");
|
||||||
is(popup.popupBoxObject.alignmentPosition, "after_end", "Check " + currentTarget + " position");
|
is(popup.popupBoxObject.alignmentPosition, "after_end", "Check " + currentTarget + " position");
|
||||||
}),
|
}),
|
||||||
|
taskify(function* test_setConfiguration() {
|
||||||
|
is(Services.prefs.getBoolPref("loop.gettingStarted.resumeOnFirstJoin"), false, "pref should be false but exist");
|
||||||
|
gContentAPI.setConfiguration("Loop:ResumeTourOnFirstJoin", true);
|
||||||
|
|
||||||
|
yield waitForConditionPromise(() => {
|
||||||
|
return Services.prefs.getBoolPref("loop.gettingStarted.resumeOnFirstJoin");
|
||||||
|
}, "Pref should change to true via setConfiguration");
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
||||||
|
}),
|
||||||
|
taskify(function* test_resumeViaMenuPanel_roomClosedTabOpen() {
|
||||||
|
Services.prefs.setBoolPref("loop.gettingStarted.resumeOnFirstJoin", true);
|
||||||
|
|
||||||
|
// Create a fake room and then add a fake non-owner participant
|
||||||
|
let roomsMap = setupFakeRoom();
|
||||||
|
roomsMap.get("fakeTourRoom").participants = [{
|
||||||
|
owner: false,
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Set the tour URL to be the current page with a different query param
|
||||||
|
let gettingStartedURL = gTestTab.linkedBrowser.currentURI.resolve("?gettingstarted=1");
|
||||||
|
Services.prefs.setCharPref("loop.gettingStarted.url", gettingStartedURL);
|
||||||
|
|
||||||
|
let observationPromise = new Promise((resolve) => {
|
||||||
|
gContentAPI.observe((event, params) => {
|
||||||
|
is(event, "Loop:IncomingConversation", "Page should have been notified about incoming conversation");
|
||||||
|
ise(params.conversationOpen, false, "conversationOpen should be false");
|
||||||
|
is(gBrowser.selectedTab, gTestTab, "The same tab should be selected");
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now open the menu while that non-owner is in the fake room to trigger resuming the tour
|
||||||
|
yield showMenuPromise("loop");
|
||||||
|
|
||||||
|
yield observationPromise;
|
||||||
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
||||||
|
}),
|
||||||
|
taskify(function* test_resumeViaMenuPanel_roomClosedTabClosed() {
|
||||||
|
Services.prefs.setBoolPref("loop.gettingStarted.resumeOnFirstJoin", true);
|
||||||
|
|
||||||
|
// Create a fake room and then add a fake non-owner participant
|
||||||
|
let roomsMap = setupFakeRoom();
|
||||||
|
roomsMap.get("fakeTourRoom").participants = [{
|
||||||
|
owner: false,
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Set the tour URL to a page that's not open yet
|
||||||
|
Services.prefs.setCharPref("loop.gettingStarted.url", gBrowser.currentURI.prePath);
|
||||||
|
|
||||||
|
let newTabPromise = waitForConditionPromise(() => {
|
||||||
|
return gBrowser.currentURI.path.contains("incomingConversation=waiting");
|
||||||
|
}, "New tab with incomingConversation=waiting should have opened");
|
||||||
|
|
||||||
|
// Now open the menu while that non-owner is in the fake room to trigger resuming the tour
|
||||||
|
yield showMenuPromise("loop");
|
||||||
|
|
||||||
|
yield newTabPromise;
|
||||||
|
|
||||||
|
yield gBrowser.removeCurrentTab();
|
||||||
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
// End tests
|
// End tests
|
||||||
@ -188,9 +250,11 @@ function setupFakeRoom() {
|
|||||||
let room = {};
|
let room = {};
|
||||||
for (let prop of ["roomToken", "roomName", "roomOwner", "roomUrl", "participants"])
|
for (let prop of ["roomToken", "roomName", "roomOwner", "roomUrl", "participants"])
|
||||||
room[prop] = "fakeTourRoom";
|
room[prop] = "fakeTourRoom";
|
||||||
LoopRooms.stubCache(new Map([
|
let roomsMap = new Map([
|
||||||
[room.roomToken, room]
|
[room.roomToken, room]
|
||||||
]));
|
]);
|
||||||
|
LoopRooms.stubCache(roomsMap);
|
||||||
|
return roomsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Services.prefs.getBoolPref("loop.enabled")) {
|
if (Services.prefs.getBoolPref("loop.enabled")) {
|
||||||
@ -201,7 +265,9 @@ if (Services.prefs.getBoolPref("loop.enabled")) {
|
|||||||
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
|
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
|
||||||
|
|
||||||
registerCleanupFunction(() => {
|
registerCleanupFunction(() => {
|
||||||
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
||||||
Services.prefs.clearUserPref("loop.gettingStarted.seen");
|
Services.prefs.clearUserPref("loop.gettingStarted.seen");
|
||||||
|
Services.prefs.clearUserPref("loop.gettingStarted.url");
|
||||||
Services.prefs.clearUserPref("loop.server");
|
Services.prefs.clearUserPref("loop.server");
|
||||||
Services.prefs.clearUserPref("services.push.serverURL");
|
Services.prefs.clearUserPref("services.push.serverURL");
|
||||||
|
|
||||||
@ -214,6 +280,9 @@ if (Services.prefs.getBoolPref("loop.enabled")) {
|
|||||||
if (frame) {
|
if (frame) {
|
||||||
frame.remove();
|
frame.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the stubbed rooms
|
||||||
|
LoopRooms.stubCache(null);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ok(true, "Loop is disabled so skip the UITour Loop tests");
|
ok(true, "Loop is disabled so skip the UITour Loop tests");
|
||||||
|
@ -223,6 +223,13 @@ if (typeof Mozilla == 'undefined') {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Mozilla.UITour.setConfiguration = function(configName, configValue) {
|
||||||
|
_sendEvent('setConfiguration', {
|
||||||
|
configuration: configName,
|
||||||
|
value: configValue,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Mozilla.UITour.showFirefoxAccounts = function() {
|
Mozilla.UITour.showFirefoxAccounts = function() {
|
||||||
_sendEvent('showFirefoxAccounts');
|
_sendEvent('showFirefoxAccounts');
|
||||||
};
|
};
|
||||||
|
@ -87,6 +87,18 @@ label.small {
|
|||||||
-moz-box-flex: 1;
|
-moz-box-flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Privacy Pane */
|
||||||
|
|
||||||
|
/* styles for the link elements copied from .text-link in global.css */
|
||||||
|
.inline-link {
|
||||||
|
color: -moz-nativehyperlinktext;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* Modeless Window Dialogs */
|
/* Modeless Window Dialogs */
|
||||||
.windowDialog,
|
.windowDialog,
|
||||||
.windowDialog prefpane {
|
.windowDialog prefpane {
|
||||||
|
@ -184,6 +184,24 @@ caption {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Pane
|
||||||
|
*/
|
||||||
|
|
||||||
|
html|a.inline-link {
|
||||||
|
color: -moz-nativehyperlinktext;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
html|a.inline-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
html|a.inline-link:-moz-focusring {
|
||||||
|
outline-width: 0;
|
||||||
|
box-shadow: @focusRingShadow@;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Preferences
|
* Update Preferences
|
||||||
*/
|
*/
|
||||||
|
@ -173,16 +173,6 @@ description > html|a {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#offlineAppsList,
|
|
||||||
#syncEnginesList {
|
|
||||||
-moz-appearance: none;
|
|
||||||
color: #333333;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #C1C1C1;
|
|
||||||
border-radius: 2px;
|
|
||||||
background-color: #FBFBFB;
|
|
||||||
}
|
|
||||||
|
|
||||||
#noFxaAccount {
|
#noFxaAccount {
|
||||||
/* Overriding the margins from the base preferences.css theme file.
|
/* Overriding the margins from the base preferences.css theme file.
|
||||||
These overrides can be simplified by fixing bug 1027174 */
|
These overrides can be simplified by fixing bug 1027174 */
|
||||||
@ -293,3 +283,20 @@ description > html|a {
|
|||||||
/**
|
/**
|
||||||
* End Dialog
|
* End Dialog
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync migration
|
||||||
|
*/
|
||||||
|
#sync-migration {
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.32);
|
||||||
|
background-color: InfoBackground;
|
||||||
|
color: InfoText;
|
||||||
|
text-shadow: none;
|
||||||
|
margin: 5px 0 0 0;
|
||||||
|
animation: fadein 3000ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadein {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
@ -83,6 +83,18 @@ label.small {
|
|||||||
-moz-box-flex: 1;
|
-moz-box-flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Privacy Pane */
|
||||||
|
|
||||||
|
/* styles for the link elements copied from .text-link in global.css */
|
||||||
|
.inline-link {
|
||||||
|
color: -moz-nativehyperlinktext;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* Modeless Window Dialogs */
|
/* Modeless Window Dialogs */
|
||||||
.windowDialog,
|
.windowDialog,
|
||||||
.windowDialog prefpane {
|
.windowDialog prefpane {
|
||||||
|
@ -3856,7 +3856,6 @@ if test -n "$MOZ_FMP4"; then
|
|||||||
else
|
else
|
||||||
MOZ_FMP4=
|
MOZ_FMP4=
|
||||||
fi
|
fi
|
||||||
MOZ_EME=1
|
|
||||||
MOZ_FFMPEG=
|
MOZ_FFMPEG=
|
||||||
MOZ_WEBRTC=1
|
MOZ_WEBRTC=1
|
||||||
MOZ_PEERCONNECTION=
|
MOZ_PEERCONNECTION=
|
||||||
@ -5327,6 +5326,7 @@ MOZ_ARG_DISABLE_BOOL(fmp4,
|
|||||||
|
|
||||||
if test -n "$MOZ_FMP4"; then
|
if test -n "$MOZ_FMP4"; then
|
||||||
AC_DEFINE(MOZ_FMP4)
|
AC_DEFINE(MOZ_FMP4)
|
||||||
|
MOZ_EME=1
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
dnl ========================================================
|
dnl ========================================================
|
||||||
@ -5339,6 +5339,9 @@ MOZ_ARG_DISABLE_BOOL(eme,
|
|||||||
MOZ_EME=1)
|
MOZ_EME=1)
|
||||||
|
|
||||||
if test -n "$MOZ_EME"; then
|
if test -n "$MOZ_EME"; then
|
||||||
|
if test -z "$MOZ_FMP4"; then
|
||||||
|
AC_MSG_ERROR([Encrypted Media Extension support requires Fragmented MP4 support])
|
||||||
|
fi
|
||||||
AC_DEFINE(MOZ_EME)
|
AC_DEFINE(MOZ_EME)
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ let URL = '<!DOCTYPE html><style>' +
|
|||||||
|
|
||||||
let TESTS = [{
|
let TESTS = [{
|
||||||
desc: "Changing the width of the test element",
|
desc: "Changing the width of the test element",
|
||||||
|
searchFor: "Paint",
|
||||||
setup: function(div) {
|
setup: function(div) {
|
||||||
div.setAttribute("class", "resize-change-color");
|
div.setAttribute("class", "resize-change-color");
|
||||||
},
|
},
|
||||||
@ -35,6 +36,7 @@ let TESTS = [{
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
desc: "Changing the test element's background color",
|
desc: "Changing the test element's background color",
|
||||||
|
searchFor: "Paint",
|
||||||
setup: function(div) {
|
setup: function(div) {
|
||||||
div.setAttribute("class", "change-color");
|
div.setAttribute("class", "change-color");
|
||||||
},
|
},
|
||||||
@ -52,6 +54,7 @@ let TESTS = [{
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
desc: "Changing the test element's classname",
|
desc: "Changing the test element's classname",
|
||||||
|
searchFor: "Paint",
|
||||||
setup: function(div) {
|
setup: function(div) {
|
||||||
div.setAttribute("class", "change-color add-class");
|
div.setAttribute("class", "change-color add-class");
|
||||||
},
|
},
|
||||||
@ -63,6 +66,7 @@ let TESTS = [{
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
desc: "sync console.time/timeEnd",
|
desc: "sync console.time/timeEnd",
|
||||||
|
searchFor: "ConsoleTime",
|
||||||
setup: function(div, docShell) {
|
setup: function(div, docShell) {
|
||||||
content.console.time("FOOBAR");
|
content.console.time("FOOBAR");
|
||||||
content.console.timeEnd("FOOBAR");
|
content.console.timeEnd("FOOBAR");
|
||||||
@ -102,7 +106,7 @@ let test = Task.async(function*() {
|
|||||||
info("Start recording");
|
info("Start recording");
|
||||||
docShell.recordProfileTimelineMarkers = true;
|
docShell.recordProfileTimelineMarkers = true;
|
||||||
|
|
||||||
for (let {desc, setup, check} of TESTS) {
|
for (let {desc, searchFor, setup, check} of TESTS) {
|
||||||
|
|
||||||
info("Running test: " + desc);
|
info("Running test: " + desc);
|
||||||
|
|
||||||
@ -110,7 +114,7 @@ let test = Task.async(function*() {
|
|||||||
docShell.popProfileTimelineMarkers();
|
docShell.popProfileTimelineMarkers();
|
||||||
|
|
||||||
info("Running the test setup function");
|
info("Running the test setup function");
|
||||||
let onMarkers = waitForMarkers(docShell);
|
let onMarkers = waitForMarkers(docShell, searchFor);
|
||||||
setup(div, docShell);
|
setup(div, docShell);
|
||||||
info("Waiting for new markers on the docShell");
|
info("Waiting for new markers on the docShell");
|
||||||
let markers = yield onMarkers;
|
let markers = yield onMarkers;
|
||||||
@ -140,21 +144,20 @@ function openUrl(url) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForMarkers(docshell) {
|
function waitForMarkers(docshell, searchFor) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
let waitIterationCount = 0;
|
let waitIterationCount = 0;
|
||||||
let maxWaitIterationCount = 10; // Wait for 2sec maximum
|
let maxWaitIterationCount = 10; // Wait for 2sec maximum
|
||||||
|
let markers = [];
|
||||||
|
|
||||||
let interval = setInterval(() => {
|
let interval = setInterval(() => {
|
||||||
let markers = docshell.popProfileTimelineMarkers();
|
let newMarkers = docshell.popProfileTimelineMarkers();
|
||||||
if (markers.length > 0) {
|
markers = [...markers, ...newMarkers];
|
||||||
|
if (newMarkers.some(m => m.name == searchFor) ||
|
||||||
|
waitIterationCount > maxWaitIterationCount) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
resolve(markers);
|
resolve(markers);
|
||||||
}
|
}
|
||||||
if (waitIterationCount > maxWaitIterationCount) {
|
|
||||||
clearInterval(interval);
|
|
||||||
resolve([]);
|
|
||||||
}
|
|
||||||
waitIterationCount++;
|
waitIterationCount++;
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
|
@ -20,10 +20,11 @@ using namespace mozilla;
|
|||||||
CameraControlImpl::CameraControlImpl()
|
CameraControlImpl::CameraControlImpl()
|
||||||
: mListenerLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"))
|
: mListenerLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock"))
|
||||||
, mPreviewState(CameraControlListener::kPreviewStopped)
|
, mPreviewState(CameraControlListener::kPreviewStopped)
|
||||||
, mHardwareState(CameraControlListener::kHardwareClosed)
|
, mHardwareState(CameraControlListener::kHardwareUninitialized)
|
||||||
, mHardwareStateChangeReason(NS_OK)
|
, mHardwareStateChangeReason(NS_OK)
|
||||||
{
|
{
|
||||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||||
|
mCurrentConfiguration.mMode = ICameraControl::kUnspecifiedMode;
|
||||||
|
|
||||||
// reuse the same camera thread to conserve resources
|
// reuse the same camera thread to conserve resources
|
||||||
nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
|
nsCOMPtr<nsIThread> ct = do_QueryInterface(sCameraThread);
|
||||||
@ -79,7 +80,7 @@ CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aN
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PR_LOGGING
|
#ifdef PR_LOGGING
|
||||||
const char* state[] = { "closed", "open", "failed" };
|
const char* state[] = { "uninitialized", "closed", "open", "failed" };
|
||||||
MOZ_ASSERT(aNewState >= 0);
|
MOZ_ASSERT(aNewState >= 0);
|
||||||
if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
|
if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
|
||||||
DOM_CAMERA_LOGI("New hardware state is '%s' (reason=0x%x)\n",
|
DOM_CAMERA_LOGI("New hardware state is '%s' (reason=0x%x)\n",
|
||||||
|
@ -34,6 +34,7 @@ public:
|
|||||||
|
|
||||||
enum HardwareState
|
enum HardwareState
|
||||||
{
|
{
|
||||||
|
kHardwareUninitialized,
|
||||||
kHardwareClosed,
|
kHardwareClosed,
|
||||||
kHardwareOpen,
|
kHardwareOpen,
|
||||||
kHardwareOpenFailed
|
kHardwareOpenFailed
|
||||||
|
@ -202,6 +202,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
|||||||
, mGetCameraPromise(aPromise)
|
, mGetCameraPromise(aPromise)
|
||||||
, mWindow(aWindow)
|
, mWindow(aWindow)
|
||||||
, mPreviewState(CameraControlListener::kPreviewStopped)
|
, mPreviewState(CameraControlListener::kPreviewStopped)
|
||||||
|
, mSetInitialConfig(false)
|
||||||
{
|
{
|
||||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||||
mInput = new CameraPreviewMediaStream(this);
|
mInput = new CameraPreviewMediaStream(this);
|
||||||
@ -236,8 +237,14 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (haveInitialConfig) {
|
if (haveInitialConfig) {
|
||||||
config.mPreviewSize.width = aInitialConfig.mPreviewSize.mWidth;
|
rv = SelectPreviewSize(aInitialConfig.mPreviewSize, config.mPreviewSize);
|
||||||
config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
|
if (NS_FAILED(rv)) {
|
||||||
|
mListener->OnUserError(DOMCameraControlListener::kInStartCamera, rv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.mPictureSize.width = aInitialConfig.mPictureSize.mWidth;
|
||||||
|
config.mPictureSize.height = aInitialConfig.mPictureSize.mHeight;
|
||||||
config.mRecorderProfile = aInitialConfig.mRecorderProfile;
|
config.mRecorderProfile = aInitialConfig.mRecorderProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +281,9 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
|||||||
// Start the camera...
|
// Start the camera...
|
||||||
if (haveInitialConfig) {
|
if (haveInitialConfig) {
|
||||||
rv = mCameraControl->Start(&config);
|
rv = mCameraControl->Start(&config);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
mSetInitialConfig = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rv = mCameraControl->Start();
|
rv = mCameraControl->Start();
|
||||||
}
|
}
|
||||||
@ -281,6 +291,9 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
|||||||
} else {
|
} else {
|
||||||
if (haveInitialConfig) {
|
if (haveInitialConfig) {
|
||||||
rv = mCameraControl->SetConfiguration(config);
|
rv = mCameraControl->SetConfiguration(config);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
mSetInitialConfig = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rv = NS_OK;
|
rv = NS_OK;
|
||||||
}
|
}
|
||||||
@ -308,6 +321,46 @@ nsDOMCameraControl::IsWindowStillActive()
|
|||||||
return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID());
|
return nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsDOMCameraControl::SelectPreviewSize(const CameraSize& aRequestedPreviewSize, ICameraControl::Size& aSelectedPreviewSize)
|
||||||
|
{
|
||||||
|
if (aRequestedPreviewSize.mWidth && aRequestedPreviewSize.mHeight) {
|
||||||
|
aSelectedPreviewSize.width = aRequestedPreviewSize.mWidth;
|
||||||
|
aSelectedPreviewSize.height = aRequestedPreviewSize.mHeight;
|
||||||
|
} else {
|
||||||
|
/* Use the window width and height if no preview size is provided.
|
||||||
|
Note that the width and height are actually reversed from the
|
||||||
|
camera perspective. */
|
||||||
|
int32_t width = 0;
|
||||||
|
int32_t height = 0;
|
||||||
|
float ratio = 0.0;
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
|
rv = mWindow->GetDevicePixelRatio(&ratio);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = mWindow->GetInnerWidth(&height);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = mWindow->GetInnerHeight(&width);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(width > 0);
|
||||||
|
MOZ_ASSERT(height > 0);
|
||||||
|
MOZ_ASSERT(ratio > 0.0);
|
||||||
|
aSelectedPreviewSize.width = std::ceil(width * ratio);
|
||||||
|
aSelectedPreviewSize.height = std::ceil(height * ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Setter for weighted regions: { top, bottom, left, right, weight }
|
// Setter for weighted regions: { top, bottom, left, right, weight }
|
||||||
nsresult
|
nsresult
|
||||||
nsDOMCameraControl::Set(uint32_t aKey, const Optional<Sequence<CameraRegion> >& aValue, uint32_t aLimit)
|
nsDOMCameraControl::Set(uint32_t aKey, const Optional<Sequence<CameraRegion> >& aValue, uint32_t aLimit)
|
||||||
@ -801,9 +854,14 @@ nsDOMCameraControl::SetConfiguration(const CameraConfiguration& aConfiguration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ICameraControl::Configuration config;
|
ICameraControl::Configuration config;
|
||||||
|
aRv = SelectPreviewSize(aConfiguration.mPreviewSize, config.mPreviewSize);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
config.mRecorderProfile = aConfiguration.mRecorderProfile;
|
config.mRecorderProfile = aConfiguration.mRecorderProfile;
|
||||||
config.mPreviewSize.width = aConfiguration.mPreviewSize.mWidth;
|
config.mPictureSize.width = aConfiguration.mPictureSize.mWidth;
|
||||||
config.mPreviewSize.height = aConfiguration.mPreviewSize.mHeight;
|
config.mPictureSize.height = aConfiguration.mPictureSize.mHeight;
|
||||||
config.mMode = ICameraControl::kPictureMode;
|
config.mMode = ICameraControl::kPictureMode;
|
||||||
if (aConfiguration.mMode == CameraMode::Video) {
|
if (aConfiguration.mMode == CameraMode::Video) {
|
||||||
config.mMode = ICameraControl::kVideoMode;
|
config.mMode = ICameraControl::kVideoMode;
|
||||||
@ -1041,6 +1099,20 @@ nsDOMCameraControl::DispatchStateEvent(const nsString& aType, const nsString& aS
|
|||||||
DispatchTrustedEvent(event);
|
DispatchTrustedEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsDOMCameraControl::OnGetCameraComplete()
|
||||||
|
{
|
||||||
|
// The hardware is open, so we can return a camera to JS, even if
|
||||||
|
// the preview hasn't started yet.
|
||||||
|
nsRefPtr<Promise> promise = mGetCameraPromise.forget();
|
||||||
|
if (promise) {
|
||||||
|
CameraGetPromiseData data;
|
||||||
|
data.mCamera = this;
|
||||||
|
data.mConfiguration = *mCurrentConfiguration;
|
||||||
|
promise->MaybeResolve(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Camera Control event handlers--must only be called from the Main Thread!
|
// Camera Control event handlers--must only be called from the Main Thread!
|
||||||
void
|
void
|
||||||
nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState,
|
nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState aState,
|
||||||
@ -1055,22 +1127,16 @@ nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState a
|
|||||||
case CameraControlListener::kHardwareOpen:
|
case CameraControlListener::kHardwareOpen:
|
||||||
DOM_CAMERA_LOGI("DOM OnHardwareStateChange: open\n");
|
DOM_CAMERA_LOGI("DOM OnHardwareStateChange: open\n");
|
||||||
MOZ_ASSERT(aReason == NS_OK);
|
MOZ_ASSERT(aReason == NS_OK);
|
||||||
{
|
if (!mSetInitialConfig) {
|
||||||
// The hardware is open, so we can return a camera to JS, even if
|
// The hardware is open, so we can return a camera to JS, even if
|
||||||
// the preview hasn't started yet.
|
// the preview hasn't started yet.
|
||||||
nsRefPtr<Promise> promise = mGetCameraPromise.forget();
|
OnGetCameraComplete();
|
||||||
if (promise) {
|
|
||||||
CameraGetPromiseData data;
|
|
||||||
data.mCamera = this;
|
|
||||||
data.mConfiguration = *mCurrentConfiguration;
|
|
||||||
promise->MaybeResolve(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CameraControlListener::kHardwareClosed:
|
case CameraControlListener::kHardwareClosed:
|
||||||
DOM_CAMERA_LOGI("DOM OnHardwareStateChange: closed\n");
|
DOM_CAMERA_LOGI("DOM OnHardwareStateChange: closed\n");
|
||||||
{
|
if (!mSetInitialConfig) {
|
||||||
nsRefPtr<Promise> promise = mReleasePromise.forget();
|
nsRefPtr<Promise> promise = mReleasePromise.forget();
|
||||||
if (promise) {
|
if (promise) {
|
||||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||||
@ -1102,6 +1168,9 @@ nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState a
|
|||||||
NS_LITERAL_STRING("close"),
|
NS_LITERAL_STRING("close"),
|
||||||
eventInit);
|
eventInit);
|
||||||
DispatchTrustedEvent(event);
|
DispatchTrustedEvent(event);
|
||||||
|
} else {
|
||||||
|
// The configuration failed and we forced the camera to shutdown.
|
||||||
|
OnUserError(DOMCameraControlListener::kInStartCamera, NS_ERROR_NOT_AVAILABLE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1111,6 +1180,9 @@ nsDOMCameraControl::OnHardwareStateChange(CameraControlListener::HardwareState a
|
|||||||
OnUserError(DOMCameraControlListener::kInStartCamera, NS_ERROR_NOT_AVAILABLE);
|
OnUserError(DOMCameraControlListener::kInStartCamera, NS_ERROR_NOT_AVAILABLE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CameraControlListener::kHardwareUninitialized:
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DOM_CAMERA_LOGE("DOM OnHardwareStateChange: UNKNOWN=%d\n", aState);
|
DOM_CAMERA_LOGE("DOM OnHardwareStateChange: UNKNOWN=%d\n", aState);
|
||||||
MOZ_ASSERT_UNREACHABLE("Unanticipated camera hardware state");
|
MOZ_ASSERT_UNREACHABLE("Unanticipated camera hardware state");
|
||||||
@ -1227,9 +1299,17 @@ nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration
|
|||||||
mCurrentConfiguration->mMaxMeteringAreas);
|
mCurrentConfiguration->mMaxMeteringAreas);
|
||||||
DOM_CAMERA_LOGI(" preview size (w x h) : %d x %d\n",
|
DOM_CAMERA_LOGI(" preview size (w x h) : %d x %d\n",
|
||||||
mCurrentConfiguration->mPreviewSize.mWidth, mCurrentConfiguration->mPreviewSize.mHeight);
|
mCurrentConfiguration->mPreviewSize.mWidth, mCurrentConfiguration->mPreviewSize.mHeight);
|
||||||
|
DOM_CAMERA_LOGI(" picture size (w x h) : %d x %d\n",
|
||||||
|
mCurrentConfiguration->mPictureSize.mWidth, mCurrentConfiguration->mPictureSize.mHeight);
|
||||||
DOM_CAMERA_LOGI(" recorder profile : %s\n",
|
DOM_CAMERA_LOGI(" recorder profile : %s\n",
|
||||||
NS_ConvertUTF16toUTF8(mCurrentConfiguration->mRecorderProfile).get());
|
NS_ConvertUTF16toUTF8(mCurrentConfiguration->mRecorderProfile).get());
|
||||||
|
|
||||||
|
if (mSetInitialConfig) {
|
||||||
|
OnGetCameraComplete();
|
||||||
|
mSetInitialConfig = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsRefPtr<Promise> promise = mSetConfigurationPromise.forget();
|
nsRefPtr<Promise> promise = mSetConfigurationPromise.forget();
|
||||||
if (promise) {
|
if (promise) {
|
||||||
promise->MaybeResolve(*aConfiguration);
|
promise->MaybeResolve(*aConfiguration);
|
||||||
@ -1241,6 +1321,9 @@ nsDOMCameraControl::OnConfigurationChange(DOMCameraConfiguration* aConfiguration
|
|||||||
eventInit.mPreviewSize = new DOMRect(static_cast<DOMMediaStream*>(this), 0, 0,
|
eventInit.mPreviewSize = new DOMRect(static_cast<DOMMediaStream*>(this), 0, 0,
|
||||||
mCurrentConfiguration->mPreviewSize.mWidth,
|
mCurrentConfiguration->mPreviewSize.mWidth,
|
||||||
mCurrentConfiguration->mPreviewSize.mHeight);
|
mCurrentConfiguration->mPreviewSize.mHeight);
|
||||||
|
eventInit.mPictureSize = new DOMRect(static_cast<DOMMediaStream*>(this), 0, 0,
|
||||||
|
mCurrentConfiguration->mPictureSize.mWidth,
|
||||||
|
mCurrentConfiguration->mPictureSize.mHeight);
|
||||||
|
|
||||||
nsRefPtr<CameraConfigurationEvent> event =
|
nsRefPtr<CameraConfigurationEvent> event =
|
||||||
CameraConfigurationEvent::Constructor(this,
|
CameraConfigurationEvent::Constructor(this,
|
||||||
@ -1359,6 +1442,16 @@ nsDOMCameraControl::OnUserError(CameraControlListener::UserContext aContext, nsr
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CameraControlListener::kInSetConfiguration:
|
case CameraControlListener::kInSetConfiguration:
|
||||||
|
if (mSetInitialConfig) {
|
||||||
|
// If the SetConfiguration() call in the constructor fails, there
|
||||||
|
// is nothing we can do except release the camera hardware. This
|
||||||
|
// will trigger a hardware state change, and when the flag that
|
||||||
|
// got us here is set in that handler, we replace the normal reason
|
||||||
|
// code with one that indicates the hardware isn't available.
|
||||||
|
DOM_CAMERA_LOGI("Failed to configure cached camera, stopping\n");
|
||||||
|
mCameraControl->Stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
promise = mSetConfigurationPromise.forget();
|
promise = mSetConfigurationPromise.forget();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -171,6 +171,7 @@ protected:
|
|||||||
void OnTakePictureComplete(nsIDOMBlob* aPicture);
|
void OnTakePictureComplete(nsIDOMBlob* aPicture);
|
||||||
void OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces);
|
void OnFacesDetected(const nsTArray<ICameraControl::Face>& aFaces);
|
||||||
|
|
||||||
|
void OnGetCameraComplete();
|
||||||
void OnHardwareStateChange(DOMCameraControlListener::HardwareState aState, nsresult aReason);
|
void OnHardwareStateChange(DOMCameraControlListener::HardwareState aState, nsresult aReason);
|
||||||
void OnPreviewStateChange(DOMCameraControlListener::PreviewState aState);
|
void OnPreviewStateChange(DOMCameraControlListener::PreviewState aState);
|
||||||
void OnRecorderStateChange(CameraControlListener::RecorderState aState, int32_t aStatus, int32_t aTrackNum);
|
void OnRecorderStateChange(CameraControlListener::RecorderState aState, int32_t aStatus, int32_t aTrackNum);
|
||||||
@ -179,6 +180,7 @@ protected:
|
|||||||
void OnUserError(CameraControlListener::UserContext aContext, nsresult aError);
|
void OnUserError(CameraControlListener::UserContext aContext, nsresult aError);
|
||||||
|
|
||||||
bool IsWindowStillActive();
|
bool IsWindowStillActive();
|
||||||
|
nsresult SelectPreviewSize(const dom::CameraSize& aRequestedPreviewSize, ICameraControl::Size& aSelectedPreviewSize);
|
||||||
|
|
||||||
nsresult NotifyRecordingStatusChange(const nsString& aMsg);
|
nsresult NotifyRecordingStatusChange(const nsString& aMsg);
|
||||||
|
|
||||||
@ -222,6 +224,8 @@ protected:
|
|||||||
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
||||||
DOMCameraControlListener::PreviewState mPreviewState;
|
DOMCameraControlListener::PreviewState mPreviewState;
|
||||||
|
|
||||||
|
bool mSetInitialConfig;
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
#ifdef MOZ_WIDGET_GONK
|
||||||
// cached camera control, to improve start-up time
|
// cached camera control, to improve start-up time
|
||||||
static StaticRefPtr<ICameraControl> sCachedCameraControl;
|
static StaticRefPtr<ICameraControl> sCachedCameraControl;
|
||||||
|
@ -215,6 +215,8 @@ DOMCameraControlListener::OnConfigurationChange(const CameraListenerConfiguratio
|
|||||||
config->mRecorderProfile = mConfiguration.mRecorderProfile;
|
config->mRecorderProfile = mConfiguration.mRecorderProfile;
|
||||||
config->mPreviewSize.mWidth = mConfiguration.mPreviewSize.width;
|
config->mPreviewSize.mWidth = mConfiguration.mPreviewSize.width;
|
||||||
config->mPreviewSize.mHeight = mConfiguration.mPreviewSize.height;
|
config->mPreviewSize.mHeight = mConfiguration.mPreviewSize.height;
|
||||||
|
config->mPictureSize.mWidth = mConfiguration.mPictureSize.width;
|
||||||
|
config->mPictureSize.mHeight = mConfiguration.mPictureSize.height;
|
||||||
config->mMaxMeteringAreas = mConfiguration.mMaxMeteringAreas;
|
config->mMaxMeteringAreas = mConfiguration.mMaxMeteringAreas;
|
||||||
config->mMaxFocusAreas = mConfiguration.mMaxFocusAreas;
|
config->mMaxFocusAreas = mConfiguration.mMaxFocusAreas;
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@ using namespace android;
|
|||||||
// Construct nsGonkCameraControl on the main thread.
|
// Construct nsGonkCameraControl on the main thread.
|
||||||
nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
|
nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
|
||||||
: mCameraId(aCameraId)
|
: mCameraId(aCameraId)
|
||||||
, mLastPictureSize({0, 0})
|
|
||||||
, mLastThumbnailSize({0, 0})
|
, mLastThumbnailSize({0, 0})
|
||||||
, mPreviewFps(30)
|
, mPreviewFps(30)
|
||||||
, mResumePreviewAfterTakingPicture(false) // XXXmikeh - see bug 950102
|
, mResumePreviewAfterTakingPicture(false) // XXXmikeh - see bug 950102
|
||||||
@ -136,10 +135,16 @@ nsGonkCameraControl::StartInternal(const Configuration* aInitialConfig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
OnHardwareStateChange(CameraControlListener::kHardwareOpen, NS_OK);
|
OnHardwareStateChange(CameraControlListener::kHardwareOpen, NS_OK);
|
||||||
if (aInitialConfig) {
|
|
||||||
return StartPreviewImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (aInitialConfig) {
|
||||||
|
rv = StartPreviewInternal();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnConfigurationChange();
|
||||||
|
OnPreviewStateChange(CameraControlListener::kPreviewStarted);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +185,7 @@ nsGonkCameraControl::Initialize()
|
|||||||
mParams.Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS, areas);
|
mParams.Get(CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS, areas);
|
||||||
mCurrentConfiguration.mMaxFocusAreas = areas != -1 ? areas : 0;
|
mCurrentConfiguration.mMaxFocusAreas = areas != -1 ? areas : 0;
|
||||||
|
|
||||||
mParams.Get(CAMERA_PARAM_PICTURE_SIZE, mLastPictureSize);
|
mParams.Get(CAMERA_PARAM_PICTURE_SIZE, mCurrentConfiguration.mPictureSize);
|
||||||
mParams.Get(CAMERA_PARAM_PREVIEWSIZE, mCurrentConfiguration.mPreviewSize);
|
mParams.Get(CAMERA_PARAM_PREVIEWSIZE, mCurrentConfiguration.mPreviewSize);
|
||||||
|
|
||||||
nsString luminance; // check for support
|
nsString luminance; // check for support
|
||||||
@ -197,7 +202,7 @@ nsGonkCameraControl::Initialize()
|
|||||||
DOM_CAMERA_LOGI(" - maximum metering areas: %u\n", mCurrentConfiguration.mMaxMeteringAreas);
|
DOM_CAMERA_LOGI(" - maximum metering areas: %u\n", mCurrentConfiguration.mMaxMeteringAreas);
|
||||||
DOM_CAMERA_LOGI(" - maximum focus areas: %u\n", mCurrentConfiguration.mMaxFocusAreas);
|
DOM_CAMERA_LOGI(" - maximum focus areas: %u\n", mCurrentConfiguration.mMaxFocusAreas);
|
||||||
DOM_CAMERA_LOGI(" - default picture size: %u x %u\n",
|
DOM_CAMERA_LOGI(" - default picture size: %u x %u\n",
|
||||||
mLastPictureSize.width, mLastPictureSize.height);
|
mCurrentConfiguration.mPictureSize.width, mCurrentConfiguration.mPictureSize.height);
|
||||||
DOM_CAMERA_LOGI(" - default picture file format: %s\n",
|
DOM_CAMERA_LOGI(" - default picture file format: %s\n",
|
||||||
NS_ConvertUTF16toUTF8(mFileFormat).get());
|
NS_ConvertUTF16toUTF8(mFileFormat).get());
|
||||||
DOM_CAMERA_LOGI(" - default picture quality: %f\n", quality);
|
DOM_CAMERA_LOGI(" - default picture quality: %f\n", quality);
|
||||||
@ -222,6 +227,11 @@ nsGonkCameraControl::Initialize()
|
|||||||
mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
|
mParams.Get(CAMERA_PARAM_VIDEOSIZE, mLastRecorderSize);
|
||||||
DOM_CAMERA_LOGI(" - default video recorder size: %u x %u\n",
|
DOM_CAMERA_LOGI(" - default video recorder size: %u x %u\n",
|
||||||
mLastRecorderSize.width, mLastRecorderSize.height);
|
mLastRecorderSize.width, mLastRecorderSize.height);
|
||||||
|
|
||||||
|
Size preferred;
|
||||||
|
mParams.Get(CAMERA_PARAM_PREFERRED_PREVIEWSIZE_FOR_VIDEO, preferred);
|
||||||
|
DOM_CAMERA_LOGI(" - preferred video preview size: %u x %u\n",
|
||||||
|
preferred.width, preferred.height);
|
||||||
} else {
|
} else {
|
||||||
mLastRecorderSize = mCurrentConfiguration.mPreviewSize;
|
mLastRecorderSize = mCurrentConfiguration.mPreviewSize;
|
||||||
}
|
}
|
||||||
@ -261,23 +271,66 @@ nsGonkCameraControl::~nsGonkCameraControl()
|
|||||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsGonkCameraControl::ValidateConfiguration(const Configuration& aConfig, Configuration& aValidatedConfig)
|
||||||
|
{
|
||||||
|
nsAutoTArray<Size, 16> supportedSizes;
|
||||||
|
Get(CAMERA_PARAM_SUPPORTED_PICTURESIZES, supportedSizes);
|
||||||
|
|
||||||
|
nsresult rv = GetSupportedSize(aConfig.mPictureSize, supportedSizes,
|
||||||
|
aValidatedConfig.mPictureSize);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
DOM_CAMERA_LOGW("Unable to find a picture size close to %ux%u\n",
|
||||||
|
aConfig.mPictureSize.width, aConfig.mPictureSize.height);
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = LoadRecorderProfiles();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsString profileName = aConfig.mRecorderProfile;
|
||||||
|
if (profileName.IsEmpty()) {
|
||||||
|
profileName.AssignASCII("default");
|
||||||
|
}
|
||||||
|
|
||||||
|
RecorderProfile* profile;
|
||||||
|
if (!mRecorderProfiles.Get(profileName, &profile)) {
|
||||||
|
DOM_CAMERA_LOGE("Recorder profile '%s' is not supported\n",
|
||||||
|
NS_ConvertUTF16toUTF8(aConfig.mRecorderProfile).get());
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
aValidatedConfig.mMode = aConfig.mMode;
|
||||||
|
aValidatedConfig.mPreviewSize = aConfig.mPreviewSize;
|
||||||
|
aValidatedConfig.mRecorderProfile = profile->GetName();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::SetConfigurationInternal(const Configuration& aConfig)
|
nsGonkCameraControl::SetConfigurationInternal(const Configuration& aConfig)
|
||||||
{
|
{
|
||||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||||
|
|
||||||
nsresult rv;
|
// Ensure sanity of all provided parameters and determine defaults if
|
||||||
|
// none are provided when given a new configuration
|
||||||
|
Configuration config;
|
||||||
|
nsresult rv = ValidateConfiguration(aConfig, config);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ICameraControlParameterSetAutoEnter set(this);
|
ICameraControlParameterSetAutoEnter set(this);
|
||||||
|
|
||||||
switch (aConfig.mMode) {
|
switch (config.mMode) {
|
||||||
case kPictureMode:
|
case kPictureMode:
|
||||||
rv = SetPictureConfiguration(aConfig);
|
rv = SetPictureConfiguration(config);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kVideoMode:
|
case kVideoMode:
|
||||||
rv = SetVideoConfiguration(aConfig);
|
rv = SetVideoConfiguration(config);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -291,16 +344,15 @@ nsGonkCameraControl::SetConfigurationInternal(const Configuration& aConfig)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = Set(CAMERA_PARAM_RECORDINGHINT, aConfig.mMode == kVideoMode);
|
rv = Set(CAMERA_PARAM_RECORDINGHINT, config.mMode == kVideoMode);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
DOM_CAMERA_LOGE("Failed to set recording hint (0x%x)\n", rv);
|
DOM_CAMERA_LOGE("Failed to set recording hint (0x%x)\n", rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentConfiguration.mMode = aConfig.mMode;
|
mCurrentConfiguration.mMode = config.mMode;
|
||||||
mCurrentConfiguration.mRecorderProfile = aConfig.mRecorderProfile;
|
mCurrentConfiguration.mRecorderProfile = config.mRecorderProfile;
|
||||||
|
mCurrentConfiguration.mPictureSize = config.mPictureSize;
|
||||||
OnConfigurationChange();
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +387,18 @@ nsGonkCameraControl::SetConfigurationImpl(const Configuration& aConfig)
|
|||||||
|
|
||||||
// Restart the preview
|
// Restart the preview
|
||||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||||
return StartPreviewImpl();
|
rv = StartPreviewInternal();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
StopPreviewImpl();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnConfigurationChange() indicates the success case of this operation.
|
||||||
|
// It must not be fired until all intermediate steps, including starting
|
||||||
|
// the preview, have completed successfully.
|
||||||
|
OnConfigurationChange();
|
||||||
|
OnPreviewStateChange(CameraControlListener::kPreviewStarted);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -412,39 +475,29 @@ nsGonkCameraControl::SetPictureConfiguration(const Configuration& aConfig)
|
|||||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||||
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
||||||
|
|
||||||
nsTArray<Size> sizes;
|
Size max({0, 0});
|
||||||
nsresult rv = Get(CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, sizes);
|
nsresult rv = SelectCaptureAndPreviewSize(aConfig.mPreviewSize,
|
||||||
|
aConfig.mPictureSize, max,
|
||||||
|
CAMERA_PARAM_PICTURE_SIZE);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size preview;
|
|
||||||
rv = GetSupportedSize(aConfig.mPreviewSize, sizes, preview);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
DOM_CAMERA_LOGE(
|
|
||||||
"Failed to find a supported preview size, requested size %ux%u (0x%x)",
|
|
||||||
aConfig.mPreviewSize.width, aConfig.mPreviewSize.height, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = Set(CAMERA_PARAM_PREVIEWSIZE, preview);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
DOM_CAMERA_LOGE("Failed to set supported preview size %ux%u (0x%x)",
|
|
||||||
preview.width, preview.height, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
mCurrentConfiguration.mPreviewSize = preview;
|
|
||||||
|
|
||||||
if (mSeparateVideoAndPreviewSizesSupported) {
|
if (mSeparateVideoAndPreviewSizesSupported) {
|
||||||
MaybeAdjustVideoSize();
|
MaybeAdjustVideoSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rv = UpdateThumbnailSize();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
mParams.Get(CAMERA_PARAM_PREVIEWFRAMERATE, mPreviewFps);
|
mParams.Get(CAMERA_PARAM_PREVIEWFRAMERATE, mPreviewFps);
|
||||||
|
|
||||||
DOM_CAMERA_LOGI("picture mode preview: wanted %ux%u, got %ux%u (%u fps)\n",
|
DOM_CAMERA_LOGI("picture mode preview: wanted %ux%u, got %ux%u (%u fps)\n",
|
||||||
aConfig.mPreviewSize.width, aConfig.mPreviewSize.height,
|
aConfig.mPreviewSize.width, aConfig.mPreviewSize.height,
|
||||||
preview.width, preview.height,
|
mCurrentConfiguration.mPreviewSize.width,
|
||||||
|
mCurrentConfiguration.mPreviewSize.height,
|
||||||
mPreviewFps);
|
mPreviewFps);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -683,7 +736,7 @@ nsGonkCameraControl::SetLocation(const Position& aLocation)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::StartPreviewImpl()
|
nsGonkCameraControl::StartPreviewInternal()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
||||||
RETURN_IF_NO_CAMERA_HW();
|
RETURN_IF_NO_CAMERA_HW();
|
||||||
@ -702,10 +755,19 @@ nsGonkCameraControl::StartPreviewImpl()
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnPreviewStateChange(CameraControlListener::kPreviewStarted);
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsGonkCameraControl::StartPreviewImpl()
|
||||||
|
{
|
||||||
|
nsresult rv = StartPreviewInternal();
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
OnPreviewStateChange(CameraControlListener::kPreviewStarted);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::StopPreviewImpl()
|
nsGonkCameraControl::StopPreviewImpl()
|
||||||
{
|
{
|
||||||
@ -814,8 +876,8 @@ nsGonkCameraControl::SetThumbnailSizeImpl(const Size& aSize)
|
|||||||
|
|
||||||
if (area != 0 &&
|
if (area != 0 &&
|
||||||
delta < smallestDelta &&
|
delta < smallestDelta &&
|
||||||
supportedSizes[i].width * mLastPictureSize.height ==
|
supportedSizes[i].width * mCurrentConfiguration.mPictureSize.height ==
|
||||||
mLastPictureSize.width * supportedSizes[i].height) {
|
mCurrentConfiguration.mPictureSize.width * supportedSizes[i].height) {
|
||||||
smallestDelta = delta;
|
smallestDelta = delta;
|
||||||
smallestDeltaIndex = i;
|
smallestDeltaIndex = i;
|
||||||
}
|
}
|
||||||
@ -898,7 +960,8 @@ nsGonkCameraControl::SetPictureSizeImpl(const Size& aSize)
|
|||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aSize.width == mLastPictureSize.width && aSize.height == mLastPictureSize.height) {
|
if (aSize.width == mCurrentConfiguration.mPictureSize.width &&
|
||||||
|
aSize.height == mCurrentConfiguration.mPictureSize.height) {
|
||||||
DOM_CAMERA_LOGI("Requested picture size %ux%u unchanged\n", aSize.width, aSize.height);
|
DOM_CAMERA_LOGI("Requested picture size %ux%u unchanged\n", aSize.width, aSize.height);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -926,7 +989,7 @@ nsGonkCameraControl::SetPictureSizeImpl(const Size& aSize)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastPictureSize = best;
|
mCurrentConfiguration.mPictureSize = best;
|
||||||
|
|
||||||
// Finally, update the thumbnail size in case the picture aspect ratio changed.
|
// Finally, update the thumbnail size in case the picture aspect ratio changed.
|
||||||
// Some drivers will fail to take a picture if the thumbnail size is not the
|
// Some drivers will fail to take a picture if the thumbnail size is not the
|
||||||
@ -1377,6 +1440,11 @@ nsGonkCameraControl::GetSupportedSize(const Size& aSize,
|
|||||||
uint32_t minSizeDelta = UINT32_MAX;
|
uint32_t minSizeDelta = UINT32_MAX;
|
||||||
uint32_t delta;
|
uint32_t delta;
|
||||||
|
|
||||||
|
if (aSupportedSizes.IsEmpty()) {
|
||||||
|
// no valid sizes
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
if (!aSize.width && !aSize.height) {
|
if (!aSize.width && !aSize.height) {
|
||||||
// no size specified, take the first supported size
|
// no size specified, take the first supported size
|
||||||
best = aSupportedSizes[0];
|
best = aSupportedSizes[0];
|
||||||
@ -1432,91 +1500,41 @@ nsGonkCameraControl::GetSupportedSize(const Size& aSize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsGonkCameraControl::SetVideoAndPreviewSize(const Size& aPreviewSize, const Size& aVideoSize)
|
nsGonkCameraControl::SelectCaptureAndPreviewSize(const Size& aPreviewSize,
|
||||||
|
const Size& aCaptureSize,
|
||||||
|
const Size& aMaxSize,
|
||||||
|
uint32_t aCaptureSizeKey)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
||||||
MOZ_ASSERT(mSeparateVideoAndPreviewSizesSupported);
|
|
||||||
|
|
||||||
DOM_CAMERA_LOGI("Setting video size to %ux%u, preview size to %ux%u\n",
|
// At this point, we know the capture size has been validated and replaced
|
||||||
aVideoSize.width, aVideoSize.height,
|
// if necessary with the best matching supported value.
|
||||||
aPreviewSize.width, aPreviewSize.height);
|
DOM_CAMERA_LOGI("Select capture size %ux%u, preview size %ux%u, maximum size %ux%u\n",
|
||||||
|
aCaptureSize.width, aCaptureSize.height,
|
||||||
|
aPreviewSize.width, aPreviewSize.height,
|
||||||
|
aMaxSize.width, aMaxSize.height);
|
||||||
|
|
||||||
Size oldSize;
|
nsAutoTArray<Size, 16> sizes;
|
||||||
nsresult rv = Get(CAMERA_PARAM_PREVIEWSIZE, oldSize);
|
nsresult rv = Get(CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, sizes);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = Set(CAMERA_PARAM_PREVIEWSIZE, aPreviewSize);
|
// May optionally apply a ceiling to the preview size. Any supported preview
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
// size with an area larger than the maximum will be ignored regardless of
|
||||||
return rv;
|
// aspect ratio or delta to requested preview size.
|
||||||
}
|
uint32_t maxArea = aMaxSize.width * aMaxSize.height;
|
||||||
rv = Set(CAMERA_PARAM_VIDEOSIZE, aVideoSize);
|
if (maxArea == 0) {
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
maxArea = UINT32_MAX;
|
||||||
Set(CAMERA_PARAM_VIDEOSIZE, oldSize); // error, try to restore the original preview size
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentConfiguration.mPreviewSize = aPreviewSize;
|
const uint32_t previewArea = aPreviewSize.width * aPreviewSize.height;
|
||||||
mLastRecorderSize = aVideoSize;
|
|
||||||
|
|
||||||
return NS_OK;
|
// We should select a preview size with the same aspect ratio as the capture
|
||||||
}
|
// size and minimize the delta with the requested preview size. If we are
|
||||||
|
// unable to find any supported preview sizes which match the aspect ratio
|
||||||
nsresult
|
// of the capture size, we fallback to only minimizing the delta with the
|
||||||
nsGonkCameraControl::SelectVideoAndPreviewSize(const Configuration& aConfig, const Size& aVideoSize)
|
// requested preview size.
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
|
|
||||||
MOZ_ASSERT(mSeparateVideoAndPreviewSizesSupported);
|
|
||||||
|
|
||||||
nsTArray<Size> sizes;
|
|
||||||
|
|
||||||
nsresult rv = Get(CAMERA_PARAM_SUPPORTED_VIDEOSIZES, sizes);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
Size video;
|
|
||||||
rv = GetSupportedSize(aVideoSize, sizes, video);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
DOM_CAMERA_LOGE("Failed to find a supported video size, requested size %ux%u",
|
|
||||||
aVideoSize.width, aVideoSize.height);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = Get(CAMERA_PARAM_SUPPORTED_PREVIEWSIZES, sizes);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
Size preview;
|
|
||||||
rv = GetSupportedSize(aConfig.mPreviewSize, sizes, preview);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
DOM_CAMERA_LOGE("Failed to find a supported preview size, requested size %ux%u",
|
|
||||||
aConfig.mPreviewSize.width, aConfig.mPreviewSize.height);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
Size preferred;
|
|
||||||
rv = Get(CAMERA_PARAM_PREFERRED_PREVIEWSIZE_FOR_VIDEO, preferred);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the requested preview size has the same aspect ratio as the
|
|
||||||
// requested video size, *and* is the same size or smaller than
|
|
||||||
// the preferred video size, then we're done.
|
|
||||||
const uint32_t preferredArea = preferred.width * preferred.height;
|
|
||||||
if (video.width * aConfig.mPreviewSize.height == aConfig.mPreviewSize.width * video.height &&
|
|
||||||
preview.width * preview.height <= preferredArea) {
|
|
||||||
// We're done: set the video and preview sizes and return...
|
|
||||||
return SetVideoAndPreviewSize(preview, video);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, if the requested preview size is larger than the preferred
|
|
||||||
// size, or there is an aspect ratio mismatch, then we need to set the
|
|
||||||
// preview size to the closest size smaller than the preferred size,
|
|
||||||
// preferably with the same aspect ratio as the requested video size.
|
|
||||||
|
|
||||||
SizeIndex bestSizeMatch = 0; // initializers to keep warnings away
|
SizeIndex bestSizeMatch = 0; // initializers to keep warnings away
|
||||||
SizeIndex bestSizeMatchWithAspectRatio = 0;
|
SizeIndex bestSizeMatchWithAspectRatio = 0;
|
||||||
@ -1528,13 +1546,19 @@ nsGonkCameraControl::SelectVideoAndPreviewSize(const Configuration& aConfig, con
|
|||||||
|
|
||||||
for (SizeIndex i = 0; i < sizes.Length(); ++i) {
|
for (SizeIndex i = 0; i < sizes.Length(); ++i) {
|
||||||
const Size& s = sizes[i];
|
const Size& s = sizes[i];
|
||||||
const uint32_t area = s.width * s.height;
|
|
||||||
if (area > preferredArea) {
|
// preview size must be smaller or equal to the capture size
|
||||||
|
if (aCaptureSize.width < s.width || aCaptureSize.height < s.height) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t delta = preferredArea - area;
|
const uint32_t area = s.width * s.height;
|
||||||
if (s.width * video.height == video.width * s.height) {
|
if (area > maxArea) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t delta = abs(static_cast<long int>(previewArea - area));
|
||||||
|
if (s.width * aCaptureSize.height == aCaptureSize.width * s.height) {
|
||||||
if (delta == 0) {
|
if (delta == 0) {
|
||||||
// exact match, including aspect ratio--we can stop now
|
// exact match, including aspect ratio--we can stop now
|
||||||
bestSizeMatchWithAspectRatio = i;
|
bestSizeMatchWithAspectRatio = i;
|
||||||
@ -1553,19 +1577,41 @@ nsGonkCameraControl::SelectVideoAndPreviewSize(const Configuration& aConfig, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Size previewSize;
|
||||||
if (foundSizeMatchWithAspectRatio) {
|
if (foundSizeMatchWithAspectRatio) {
|
||||||
preview = sizes[bestSizeMatchWithAspectRatio];
|
previewSize = sizes[bestSizeMatchWithAspectRatio];
|
||||||
} else if (foundSizeMatch) {
|
} else if (foundSizeMatch) {
|
||||||
DOM_CAMERA_LOGW("Unable to match a preview size with aspect ratio of video size %ux%u\n",
|
DOM_CAMERA_LOGW("Unable to match a preview size with aspect ratio of capture size %ux%u\n",
|
||||||
video.width, video.height);
|
aCaptureSize.width, aCaptureSize.height);
|
||||||
preview = sizes[bestSizeMatch];
|
previewSize = sizes[bestSizeMatch];
|
||||||
} else {
|
} else {
|
||||||
DOM_CAMERA_LOGE("Unable to find a preview size for video size %ux%u\n",
|
DOM_CAMERA_LOGE("Unable to find a preview size for capture size %ux%u\n",
|
||||||
video.width, video.height);
|
aCaptureSize.width, aCaptureSize.height);
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SetVideoAndPreviewSize(preview, video);
|
DOM_CAMERA_LOGI("Setting capture size to %ux%u, preview size to %ux%u\n",
|
||||||
|
aCaptureSize.width, aCaptureSize.height,
|
||||||
|
previewSize.width, previewSize.height);
|
||||||
|
|
||||||
|
Size oldSize;
|
||||||
|
rv = Get(CAMERA_PARAM_PREVIEWSIZE, oldSize);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = Set(CAMERA_PARAM_PREVIEWSIZE, previewSize);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
rv = Set(aCaptureSizeKey, aCaptureSize);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
Set(CAMERA_PARAM_PREVIEWSIZE, oldSize); // error, try to restore the original preview size
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentConfiguration.mPreviewSize = previewSize;
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
@ -1573,13 +1619,6 @@ nsGonkCameraControl::SetVideoConfiguration(const Configuration& aConfig)
|
|||||||
{
|
{
|
||||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||||
|
|
||||||
// The application may cache an old configuration and already have
|
|
||||||
// a desired recorder profile without checking the capabilities first
|
|
||||||
nsresult rv = LoadRecorderProfiles();
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RecorderProfile* profile;
|
RecorderProfile* profile;
|
||||||
if (!mRecorderProfiles.Get(aConfig.mRecorderProfile, &profile)) {
|
if (!mRecorderProfiles.Get(aConfig.mRecorderProfile, &profile)) {
|
||||||
DOM_CAMERA_LOGE("Recorder profile '%s' is not supported\n",
|
DOM_CAMERA_LOGE("Recorder profile '%s' is not supported\n",
|
||||||
@ -1605,7 +1644,14 @@ nsGonkCameraControl::SetVideoConfiguration(const Configuration& aConfig)
|
|||||||
if (mSeparateVideoAndPreviewSizesSupported) {
|
if (mSeparateVideoAndPreviewSizesSupported) {
|
||||||
// The camera supports two video streams: a low(er) resolution preview
|
// The camera supports two video streams: a low(er) resolution preview
|
||||||
// stream and and a potentially high(er) resolution stream for encoding.
|
// stream and and a potentially high(er) resolution stream for encoding.
|
||||||
rv = SelectVideoAndPreviewSize(aConfig, size);
|
Size preferred;
|
||||||
|
rv = Get(CAMERA_PARAM_PREFERRED_PREVIEWSIZE_FOR_VIDEO, preferred);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = SelectCaptureAndPreviewSize(aConfig.mPreviewSize, size, preferred,
|
||||||
|
CAMERA_PARAM_VIDEOSIZE);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
DOM_CAMERA_LOGE("Failed to set video and preview sizes (0x%x)\n", rv);
|
DOM_CAMERA_LOGE("Failed to set video and preview sizes (0x%x)\n", rv);
|
||||||
return rv;
|
return rv;
|
||||||
@ -1623,6 +1669,8 @@ nsGonkCameraControl::SetVideoConfiguration(const Configuration& aConfig)
|
|||||||
mCurrentConfiguration.mPreviewSize = size;
|
mCurrentConfiguration.mPreviewSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLastRecorderSize = size;
|
||||||
|
|
||||||
rv = Set(CAMERA_PARAM_PREVIEWFRAMERATE, static_cast<int>(fps));
|
rv = Set(CAMERA_PARAM_PREVIEWFRAMERATE, static_cast<int>(fps));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
DOM_CAMERA_LOGE("Failed to set video mode frame rate (0x%x)\n", rv);
|
DOM_CAMERA_LOGE("Failed to set video mode frame rate (0x%x)\n", rv);
|
||||||
@ -1903,9 +1951,12 @@ nsGonkCameraControl::LoadRecorderProfiles()
|
|||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsTArray<RecorderProfile>::size_type bestIndexMatch = 0;
|
||||||
|
int bestAreaMatch = 0;
|
||||||
|
|
||||||
// Limit profiles to those video sizes supported by the camera hardware...
|
// Limit profiles to those video sizes supported by the camera hardware...
|
||||||
for (nsTArray<RecorderProfile>::size_type i = 0; i < profiles.Length(); ++i) {
|
for (nsTArray<RecorderProfile>::size_type i = 0; i < profiles.Length(); ++i) {
|
||||||
int width = profiles[i]->GetVideo().GetSize().width;
|
int width = profiles[i]->GetVideo().GetSize().width;
|
||||||
int height = profiles[i]->GetVideo().GetSize().height;
|
int height = profiles[i]->GetVideo().GetSize().height;
|
||||||
if (width < 0 || height < 0) {
|
if (width < 0 || height < 0) {
|
||||||
DOM_CAMERA_LOGW("Ignoring weird profile '%s' with width and/or height < 0\n",
|
DOM_CAMERA_LOGW("Ignoring weird profile '%s' with width and/or height < 0\n",
|
||||||
@ -1916,10 +1967,22 @@ nsGonkCameraControl::LoadRecorderProfiles()
|
|||||||
if (static_cast<uint32_t>(width) == sizes[n].width &&
|
if (static_cast<uint32_t>(width) == sizes[n].width &&
|
||||||
static_cast<uint32_t>(height) == sizes[n].height) {
|
static_cast<uint32_t>(height) == sizes[n].height) {
|
||||||
mRecorderProfiles.Put(profiles[i]->GetName(), profiles[i]);
|
mRecorderProfiles.Put(profiles[i]->GetName(), profiles[i]);
|
||||||
|
int area = width * height;
|
||||||
|
if (area > bestAreaMatch) {
|
||||||
|
bestIndexMatch = i;
|
||||||
|
bestAreaMatch = area;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default profile is the one with the largest area.
|
||||||
|
if (bestAreaMatch > 0) {
|
||||||
|
nsAutoString name;
|
||||||
|
name.AssignASCII("default");
|
||||||
|
mRecorderProfiles.Put(name, profiles[bestIndexMatch]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -105,10 +105,12 @@ protected:
|
|||||||
|
|
||||||
nsresult Initialize();
|
nsresult Initialize();
|
||||||
|
|
||||||
|
nsresult ValidateConfiguration(const Configuration& aConfig, Configuration& aValidatedConfig);
|
||||||
nsresult SetConfigurationInternal(const Configuration& aConfig);
|
nsresult SetConfigurationInternal(const Configuration& aConfig);
|
||||||
nsresult SetPictureConfiguration(const Configuration& aConfig);
|
nsresult SetPictureConfiguration(const Configuration& aConfig);
|
||||||
nsresult SetVideoConfiguration(const Configuration& aConfig);
|
nsresult SetVideoConfiguration(const Configuration& aConfig);
|
||||||
nsresult StartInternal(const Configuration* aInitialConfig);
|
nsresult StartInternal(const Configuration* aInitialConfig);
|
||||||
|
nsresult StartPreviewInternal();
|
||||||
nsresult StopInternal();
|
nsresult StopInternal();
|
||||||
|
|
||||||
template<class T> nsresult SetAndPush(uint32_t aKey, const T& aValue);
|
template<class T> nsresult SetAndPush(uint32_t aKey, const T& aValue);
|
||||||
@ -133,8 +135,8 @@ protected:
|
|||||||
nsresult SetupRecording(int aFd, int aRotation, uint64_t aMaxFileSizeBytes,
|
nsresult SetupRecording(int aFd, int aRotation, uint64_t aMaxFileSizeBytes,
|
||||||
uint64_t aMaxVideoLengthMs);
|
uint64_t aMaxVideoLengthMs);
|
||||||
nsresult SetupRecordingFlash(bool aAutoEnableLowLightTorch);
|
nsresult SetupRecordingFlash(bool aAutoEnableLowLightTorch);
|
||||||
nsresult SelectVideoAndPreviewSize(const Configuration& aConfig, const Size& aVideoSize);
|
nsresult SelectCaptureAndPreviewSize(const Size& aPreviewSize, const Size& aCaptureSize,
|
||||||
nsresult SetVideoAndPreviewSize(const Size& aPreviewSize, const Size& aVideoSize);
|
const Size& aMaxSize, uint32_t aCaptureSizeKey);
|
||||||
nsresult MaybeAdjustVideoSize();
|
nsresult MaybeAdjustVideoSize();
|
||||||
nsresult PausePreview();
|
nsresult PausePreview();
|
||||||
nsresult GetSupportedSize(const Size& aSize, const nsTArray<Size>& supportedSizes, Size& best);
|
nsresult GetSupportedSize(const Size& aSize, const nsTArray<Size>& supportedSizes, Size& best);
|
||||||
@ -158,7 +160,6 @@ protected:
|
|||||||
|
|
||||||
android::sp<android::GonkCameraHardware> mCameraHw;
|
android::sp<android::GonkCameraHardware> mCameraHw;
|
||||||
|
|
||||||
Size mLastPictureSize;
|
|
||||||
Size mLastThumbnailSize;
|
Size mLastThumbnailSize;
|
||||||
Size mLastRecorderSize;
|
Size mLastRecorderSize;
|
||||||
uint32_t mPreviewFps;
|
uint32_t mPreviewFps;
|
||||||
|
@ -145,6 +145,7 @@ public:
|
|||||||
struct Configuration {
|
struct Configuration {
|
||||||
Mode mMode;
|
Mode mMode;
|
||||||
Size mPreviewSize;
|
Size mPreviewSize;
|
||||||
|
Size mPictureSize;
|
||||||
nsString mRecorderProfile;
|
nsString mRecorderProfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,3 +13,5 @@ support-files = camera_common.js
|
|||||||
[test_bug1022766.html]
|
[test_bug1022766.html]
|
||||||
[test_bug1037322.html]
|
[test_bug1037322.html]
|
||||||
[test_bug1099390.html]
|
[test_bug1099390.html]
|
||||||
|
[test_bug1104913.html]
|
||||||
|
[test_camera_bad_initial_config.html]
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var config = {
|
var config = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var config = {
|
var config = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 320,
|
||||||
height: 288
|
height: 240
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,14 +57,17 @@ var Camera = {
|
|||||||
ok(cfg.mode === "unspecified", "Initial mode = " + cfg.mode);
|
ok(cfg.mode === "unspecified", "Initial mode = " + cfg.mode);
|
||||||
ok(cfg.previewSize.width === 0 && cfg.previewSize.height === 0,
|
ok(cfg.previewSize.width === 0 && cfg.previewSize.height === 0,
|
||||||
"Initial preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
|
"Initial preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
|
||||||
ok(cfg.recorderProfile === "",
|
ok(cfg.recorderProfile === "default",
|
||||||
"Initial recorder profile = '" + cfg.recorderProfile + "'");
|
"Initial recorder profile = '" + cfg.recorderProfile + "'");
|
||||||
|
|
||||||
// Apply our specific configuration
|
// Apply our specific configuration
|
||||||
camera.setConfiguration(config).then(setConfig_onSuccess, onError);
|
camera.setConfiguration(config).then(setConfig_onSuccess, onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
navigator.mozCameras.getCamera(whichCamera, {}).then(getCamera_onSuccess, onError);
|
var cfg = {
|
||||||
|
mode: 'unspecified',
|
||||||
|
};
|
||||||
|
navigator.mozCameras.getCamera(whichCamera, cfg).then(getCamera_onSuccess, onError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var config = {
|
var config = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
81
dom/camera/test/test_bug1104913.html
Normal file
81
dom/camera/test/test_bug1104913.html
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for bug 1104913</title>
|
||||||
|
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="camera_common.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<video id="viewfinder" width="200" height="200" autoplay></video>
|
||||||
|
<img src="#" alt="This image is going to load" id="testimage"/>
|
||||||
|
<script class="testbody" type="text/javascript;version=1.7">
|
||||||
|
|
||||||
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
|
var config = {
|
||||||
|
mode: 'picture',
|
||||||
|
recorderProfile: 'qvga',
|
||||||
|
pictureSize: {
|
||||||
|
width: 640,
|
||||||
|
height: 480
|
||||||
|
},
|
||||||
|
previewSize: {
|
||||||
|
width: 320,
|
||||||
|
height: 240
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function onError(e) {
|
||||||
|
ok(false, "Error: " + JSON.stringify(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
var Camera = {
|
||||||
|
cameraObj: null,
|
||||||
|
|
||||||
|
get viewfinder() {
|
||||||
|
return document.getElementById('viewfinder');
|
||||||
|
},
|
||||||
|
|
||||||
|
start: function test_start() {
|
||||||
|
function getCamera_onSuccess(d) {
|
||||||
|
var camera = d.camera;
|
||||||
|
var cfg = d.configuration;
|
||||||
|
Camera.cameraObj = camera;
|
||||||
|
Camera.viewfinder.mozSrcObject = camera;
|
||||||
|
Camera.viewfinder.play();
|
||||||
|
|
||||||
|
// Check the default configuration
|
||||||
|
ok(cfg.mode === config.mode, "Initial mode = " + cfg.mode);
|
||||||
|
ok(cfg.previewSize.width === config.previewSize.width &&
|
||||||
|
cfg.previewSize.height === config.previewSize.height,
|
||||||
|
"Initial preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
|
||||||
|
ok(cfg.pictureSize.width === config.pictureSize.width &&
|
||||||
|
cfg.pictureSize.height === config.pictureSize.height,
|
||||||
|
"Initial picture size = " + cfg.pictureSize.width + "x" + cfg.pictureSize.height);
|
||||||
|
ok(cfg.recorderProfile === config.recorderProfile,
|
||||||
|
"Initial recorder profile = '" + cfg.recorderProfile + "'");
|
||||||
|
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.mozCameras.getCamera(whichCamera, {}).then(getCamera_onSuccess, onError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', function() {
|
||||||
|
Camera.viewfinder.mozSrcObject = null;
|
||||||
|
if (Camera.cameraObj) {
|
||||||
|
Camera.cameraObj.release();
|
||||||
|
Camera.cameraObj = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Camera.start();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -17,10 +17,10 @@ const Cr = Components.results;
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var config = {
|
var config = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 320,
|
||||||
height: 288
|
height: 240
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var options = {
|
var options = {
|
||||||
@ -137,7 +137,7 @@ var tests = [
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
var recordingOptions = {
|
var recordingOptions = {
|
||||||
profile: 'cif',
|
profile: 'high',
|
||||||
rotation: 0
|
rotation: 0
|
||||||
};
|
};
|
||||||
camera.startRecording(recordingOptions,
|
camera.startRecording(recordingOptions,
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var options = {
|
var options = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 320,
|
||||||
height: 288
|
height: 240
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var options = {
|
var options = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 320,
|
||||||
height: 288
|
height: 240
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var options = {
|
var options = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
58
dom/camera/test/test_camera_bad_initial_config.html
Normal file
58
dom/camera/test/test_camera_bad_initial_config.html
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for bad initial configuration</title>
|
||||||
|
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="camera_common.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<video id="viewfinder" width="200" height="200" autoplay></video>
|
||||||
|
<img src="#" alt="This image is going to load" id="testimage"/>
|
||||||
|
<script class="testbody" type="text/javascript;version=1.7">
|
||||||
|
|
||||||
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
|
var config = {
|
||||||
|
mode: 'picture',
|
||||||
|
recorderProfile: 'foobar',
|
||||||
|
};
|
||||||
|
|
||||||
|
var Camera = {
|
||||||
|
cameraObj: null,
|
||||||
|
|
||||||
|
get viewfinder() {
|
||||||
|
return document.getElementById('viewfinder');
|
||||||
|
},
|
||||||
|
|
||||||
|
start: function test_start() {
|
||||||
|
function getCamera_onSuccess(d) {
|
||||||
|
ok(false, "Get camera should have failed");
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCamera_onError(e) {
|
||||||
|
ok(true, "Get camera failed as expected: " + JSON.stringify(e));
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.mozCameras.getCamera(whichCamera, config).then(getCamera_onSuccess, getCamera_onError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', function() {
|
||||||
|
Camera.viewfinder.mozSrcObject = null;
|
||||||
|
if (Camera.cameraObj) {
|
||||||
|
Camera.cameraObj.release();
|
||||||
|
Camera.cameraObj = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Camera.start();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -17,7 +17,7 @@
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var initialConfig = {
|
var initialConfig = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
@ -20,7 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=965421
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var initialConfig = {
|
var initialConfig = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
@ -20,7 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=965420
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var initialConfig = {
|
var initialConfig = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
@ -20,7 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=940424
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var initialConfig = {
|
var initialConfig = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
@ -22,7 +22,7 @@ SimpleTest.waitForExplicitFinish();
|
|||||||
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
|
||||||
var initialConfig = {
|
var initialConfig = {
|
||||||
mode: 'picture',
|
mode: 'picture',
|
||||||
recorderProfile: 'cif',
|
recorderProfile: 'high',
|
||||||
previewSize: {
|
previewSize: {
|
||||||
width: 352,
|
width: 352,
|
||||||
height: 288
|
height: 288
|
||||||
|
@ -362,21 +362,26 @@ MediaEngineGonkVideoSource::OnHardwareStateChange(HardwareState aState,
|
|||||||
nsresult aReason)
|
nsresult aReason)
|
||||||
{
|
{
|
||||||
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
|
||||||
if (aState == CameraControlListener::kHardwareClosed) {
|
switch (aState) {
|
||||||
// When the first CameraControl listener is added, it gets pushed
|
case CameraControlListener::kHardwareClosed:
|
||||||
// the current state of the camera--normally 'closed'. We only
|
case CameraControlListener::kHardwareOpenFailed:
|
||||||
// pay attention to that state if we've progressed out of the
|
|
||||||
// allocated state.
|
|
||||||
if (mState != kAllocated) {
|
|
||||||
mState = kReleased;
|
mState = kReleased;
|
||||||
mCallbackMonitor.Notify();
|
mCallbackMonitor.Notify();
|
||||||
}
|
break;
|
||||||
} else {
|
case CameraControlListener::kHardwareOpen:
|
||||||
// Can't read this except on MainThread (ugh)
|
// Can't read this except on MainThread (ugh)
|
||||||
NS_DispatchToMainThread(WrapRunnable(nsRefPtr<MediaEngineGonkVideoSource>(this),
|
NS_DispatchToMainThread(WrapRunnable(nsRefPtr<MediaEngineGonkVideoSource>(this),
|
||||||
&MediaEngineGonkVideoSource::GetRotation));
|
&MediaEngineGonkVideoSource::GetRotation));
|
||||||
mState = kStarted;
|
mState = kStarted;
|
||||||
mCallbackMonitor.Notify();
|
mCallbackMonitor.Notify();
|
||||||
|
break;
|
||||||
|
case CameraControlListener::kHardwareUninitialized:
|
||||||
|
// When the first CameraControl listener is added, it gets pushed
|
||||||
|
// the current state of the camera--normally 'uninitialized'.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT_UNREACHABLE("Unanticipated camera hardware state");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ MobileConnectionProvider.prototype = {
|
|||||||
deliverListenerEvent: function(aName, aArgs) {
|
deliverListenerEvent: function(aName, aArgs) {
|
||||||
let listeners = this._listeners.slice();
|
let listeners = this._listeners.slice();
|
||||||
for (let listener of listeners) {
|
for (let listener of listeners) {
|
||||||
if (listeners.indexOf(listener) === -1) {
|
if (this._listeners.indexOf(listener) === -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let handler = listener[aName];
|
let handler = listener[aName];
|
||||||
|
@ -461,8 +461,8 @@ WifiGeoPositionProvider.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
sendLocationRequest: function (wifiData) {
|
sendLocationRequest: function (wifiData) {
|
||||||
let data = {};
|
let data = { cellTowers: undefined, wifiAccessPoints: undefined };
|
||||||
if (wifiData) {
|
if (wifiData && wifiData.length >= 2) {
|
||||||
data.wifiAccessPoints = wifiData;
|
data.wifiAccessPoints = wifiData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
if (!this.ctypes) {
|
if (!this.ctypes) {
|
||||||
// We're likely being loaded as a JSM.
|
// We're likely being loaded as a JSM.
|
||||||
this.EXPORTED_SYMBOLS = [ "libcutils", "libnetutils", "netHelpers" ];
|
this.EXPORTED_SYMBOLS = [ "libcutils", "netHelpers" ];
|
||||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,96 +102,6 @@ this.libcutils = (function() {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
|
||||||
* Network-related functions from libnetutils.
|
|
||||||
*/
|
|
||||||
this.libnetutils = (function() {
|
|
||||||
let library;
|
|
||||||
try {
|
|
||||||
library = ctypes.open("libnetutils.so");
|
|
||||||
} catch(ex) {
|
|
||||||
if (DEBUG) {
|
|
||||||
dump("Could not load libnetutils.so!\n");
|
|
||||||
}
|
|
||||||
// For now we just fake the ctypes library interfacer to return
|
|
||||||
// no-op functions when library.declare() is called.
|
|
||||||
library = {
|
|
||||||
declare: function() {
|
|
||||||
return function fake_libnetutils_function() {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let iface = {
|
|
||||||
ifc_enable: library.declare("ifc_enable", ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
ifc_disable: library.declare("ifc_disable", ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
ifc_add_host_route: library.declare("ifc_add_host_route",
|
|
||||||
ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr,
|
|
||||||
ctypes.int),
|
|
||||||
ifc_remove_host_routes: library.declare("ifc_remove_host_routes",
|
|
||||||
ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
ifc_set_default_route: library.declare("ifc_set_default_route",
|
|
||||||
ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr,
|
|
||||||
ctypes.int),
|
|
||||||
ifc_get_default_route: library.declare("ifc_get_default_route",
|
|
||||||
ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
ifc_remove_default_route: library.declare("ifc_remove_default_route",
|
|
||||||
ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
ifc_configure: library.declare("ifc_configure", ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.int),
|
|
||||||
ifc_add_route: library.declare("ifc_add_route", ctypes.default_abi,
|
|
||||||
ctypes.int, // return value
|
|
||||||
ctypes.char.ptr, // ifname
|
|
||||||
ctypes.char.ptr, // dst
|
|
||||||
ctypes.int, // prefix_length
|
|
||||||
ctypes.char.ptr), // gw
|
|
||||||
ifc_remove_route: library.declare("ifc_remove_route", ctypes.default_abi,
|
|
||||||
ctypes.int, // return value
|
|
||||||
ctypes.char.ptr, // ifname
|
|
||||||
ctypes.char.ptr, // dst
|
|
||||||
ctypes.int, // prefix_length
|
|
||||||
ctypes.char.ptr), // gw
|
|
||||||
dhcp_stop: library.declare("dhcp_stop", ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
dhcp_release_lease: library.declare("dhcp_release_lease", ctypes.default_abi,
|
|
||||||
ctypes.int,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
dhcp_get_errmsg: library.declare("dhcp_get_errmsg", ctypes.default_abi,
|
|
||||||
ctypes.char.ptr),
|
|
||||||
|
|
||||||
// Constants for ifc_reset_connections.
|
|
||||||
// NOTE: Ignored in versions before ICS.
|
|
||||||
RESET_IPV4_ADDRESSES: 0x01,
|
|
||||||
RESET_IPV6_ADDRESSES: 0x02,
|
|
||||||
};
|
|
||||||
|
|
||||||
iface.RESET_ALL_ADDRESSES = iface.RESET_IPV4_ADDRESSES |
|
|
||||||
iface.RESET_IPV6_ADDRESSES;
|
|
||||||
|
|
||||||
return iface;
|
|
||||||
})();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helpers for conversions.
|
* Helpers for conversions.
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,7 @@ interface CameraConfigurationEvent : Event
|
|||||||
readonly attribute CameraMode mode;
|
readonly attribute CameraMode mode;
|
||||||
readonly attribute DOMString recorderProfile;
|
readonly attribute DOMString recorderProfile;
|
||||||
readonly attribute DOMRectReadOnly? previewSize;
|
readonly attribute DOMRectReadOnly? previewSize;
|
||||||
|
readonly attribute DOMRectReadOnly? pictureSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary CameraConfigurationEventInit : EventInit
|
dictionary CameraConfigurationEventInit : EventInit
|
||||||
@ -17,4 +18,5 @@ dictionary CameraConfigurationEventInit : EventInit
|
|||||||
CameraMode mode = "picture";
|
CameraMode mode = "picture";
|
||||||
DOMString recorderProfile = "cif";
|
DOMString recorderProfile = "cif";
|
||||||
DOMRectReadOnly? previewSize = null;
|
DOMRectReadOnly? previewSize = null;
|
||||||
|
DOMRectReadOnly? pictureSize = null;
|
||||||
};
|
};
|
||||||
|
@ -255,7 +255,10 @@ interface CameraControl : MediaStream
|
|||||||
|
|
||||||
/* the size of the picture to be returned by a call to takePicture();
|
/* the size of the picture to be returned by a call to takePicture();
|
||||||
an object with 'height' and 'width' properties that corresponds to
|
an object with 'height' and 'width' properties that corresponds to
|
||||||
one of the options returned by capabilities.pictureSizes. */
|
one of the options returned by capabilities.pictureSizes.
|
||||||
|
|
||||||
|
note that unlike when one uses setConfiguration instead to update the
|
||||||
|
picture size, this will not recalculate the ideal preview size. */
|
||||||
[Throws]
|
[Throws]
|
||||||
CameraSize getPictureSize();
|
CameraSize getPictureSize();
|
||||||
[Throws]
|
[Throws]
|
||||||
@ -287,6 +290,7 @@ interface CameraControl : MediaStream
|
|||||||
to the display; e.g. if 'sensorAngle' is 270 degrees (or -90 degrees),
|
to the display; e.g. if 'sensorAngle' is 270 degrees (or -90 degrees),
|
||||||
then the preview stream needs to be rotated +90 degrees to have the
|
then the preview stream needs to be rotated +90 degrees to have the
|
||||||
same orientation as the real world. */
|
same orientation as the real world. */
|
||||||
|
[Constant, Cached]
|
||||||
readonly attribute long sensorAngle;
|
readonly attribute long sensorAngle;
|
||||||
|
|
||||||
/* the mode the camera will use to determine the correct exposure of
|
/* the mode the camera will use to determine the correct exposure of
|
||||||
@ -360,11 +364,8 @@ interface CameraControl : MediaStream
|
|||||||
|
|
||||||
/* the event dispatched when the camera is successfully configured.
|
/* the event dispatched when the camera is successfully configured.
|
||||||
|
|
||||||
event type is CameraConfigurationEvent where:
|
event type is CameraConfigurationEvent which has the same members as
|
||||||
'mode' is the selected camera mode
|
CameraConfiguration. */
|
||||||
'recorderProfile' is the selected profile
|
|
||||||
'width' contains the preview width
|
|
||||||
'height' contains the preview height */
|
|
||||||
attribute EventHandler onconfigurationchange;
|
attribute EventHandler onconfigurationchange;
|
||||||
|
|
||||||
/* if focusMode is set to either 'continuous-picture' or 'continuous-video',
|
/* if focusMode is set to either 'continuous-picture' or 'continuous-video',
|
||||||
|
@ -15,13 +15,34 @@ dictionary CameraSize
|
|||||||
unsigned long height = 0;
|
unsigned long height = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Pre-emptive camera configuration options. */
|
/* Pre-emptive camera configuration options. If 'mode' is set to "unspecified",
|
||||||
|
the camera will not be configured immediately. If the 'mode' is set to
|
||||||
|
"video" or "picture", then the camera automatically configures itself and
|
||||||
|
will be ready for use upon return.
|
||||||
|
|
||||||
|
The remaining parameters are optional and are considered hints by the
|
||||||
|
camera. The application should use the values returned in the
|
||||||
|
GetCameraCallback configuration because while the camera makes a best effort
|
||||||
|
to adhere to the requested values, it may need to change them to ensure
|
||||||
|
optimal behavior.
|
||||||
|
|
||||||
|
If not specified, 'pictureSize' and 'recorderProfile' default to the best or
|
||||||
|
highest resolutions supported by the camera hardware.
|
||||||
|
|
||||||
|
To determine 'previewSize', one should generally provide the size of the
|
||||||
|
element which will contain the preview rather than guess which supported
|
||||||
|
preview size is the best. If not specified, 'previewSize' defaults to the
|
||||||
|
inner window size. */
|
||||||
dictionary CameraConfiguration
|
dictionary CameraConfiguration
|
||||||
{
|
{
|
||||||
CameraMode mode = "unspecified";
|
CameraMode mode = "picture";
|
||||||
CameraSize previewSize = null;
|
CameraSize previewSize = null;
|
||||||
DOMString recorderProfile = ""; // one of the profiles reported by
|
CameraSize pictureSize = null;
|
||||||
// CameraControl.capabilities.recorderProfiles
|
|
||||||
|
/* one of the profiles reported by
|
||||||
|
CameraControl.capabilities.recorderProfiles
|
||||||
|
*/
|
||||||
|
DOMString recorderProfile = "default";
|
||||||
};
|
};
|
||||||
|
|
||||||
[Func="nsDOMCameraManager::HasSupport"]
|
[Func="nsDOMCameraManager::HasSupport"]
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<ImageView android:id="@+id/icon"
|
<ImageView android:id="@+id/icon"
|
||||||
android:layout_width="48dip"
|
android:layout_width="@dimen/home_banner_icon_width"
|
||||||
android:layout_height="48dip"
|
android:layout_height="@dimen/home_banner_icon_height"
|
||||||
android:layout_marginLeft="10dp"
|
android:layout_marginLeft="10dp"
|
||||||
android:scaleType="centerInside"/>
|
android:scaleType="centerInside"/>
|
||||||
|
|
||||||
@ -26,7 +26,7 @@
|
|||||||
gecko:ellipsizeAtLine="3"/>
|
gecko:ellipsizeAtLine="3"/>
|
||||||
|
|
||||||
<ImageButton android:id="@+id/close"
|
<ImageButton android:id="@+id/close"
|
||||||
android:layout_width="34dip"
|
android:layout_width="@dimen/home_banner_close_width"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@drawable/home_banner"
|
android:background="@drawable/home_banner"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
|
@ -148,6 +148,9 @@
|
|||||||
|
|
||||||
<!-- Banner -->
|
<!-- Banner -->
|
||||||
<dimen name="home_banner_height">72dp</dimen>
|
<dimen name="home_banner_height">72dp</dimen>
|
||||||
|
<dimen name="home_banner_close_width">42dp</dimen>
|
||||||
|
<dimen name="home_banner_icon_height">48dip</dimen>
|
||||||
|
<dimen name="home_banner_icon_width">48dip</dimen>
|
||||||
|
|
||||||
<!-- Icon Grid -->
|
<!-- Icon Grid -->
|
||||||
<dimen name="icongrid_columnwidth">128dp</dimen>
|
<dimen name="icongrid_columnwidth">128dp</dimen>
|
||||||
|
@ -765,10 +765,11 @@ class GTestCommands(MachCommandBase):
|
|||||||
# current OS.
|
# current OS.
|
||||||
debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
|
debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
|
||||||
|
|
||||||
debuggerInfo = mozdebug.get_debugger_info(debugger, debugger_args)
|
if debugger:
|
||||||
if not debuggerInfo:
|
debuggerInfo = mozdebug.get_debugger_info(debugger, debugger_args)
|
||||||
print("Could not find a suitable debugger in your PATH.")
|
if not debuggerInfo:
|
||||||
return 1
|
print("Could not find a suitable debugger in your PATH.")
|
||||||
|
return 1
|
||||||
|
|
||||||
# Parameters come from the CLI. We need to convert them before
|
# Parameters come from the CLI. We need to convert them before
|
||||||
# their use.
|
# their use.
|
||||||
@ -942,10 +943,11 @@ class RunProgram(MachCommandBase):
|
|||||||
# current OS.
|
# current OS.
|
||||||
debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
|
debugger = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
|
||||||
|
|
||||||
self.debuggerInfo = mozdebug.get_debugger_info(debugger, debugparams)
|
if debugger:
|
||||||
if not self.debuggerInfo:
|
self.debuggerInfo = mozdebug.get_debugger_info(debugger, debugparams)
|
||||||
print("Could not find a suitable debugger in your PATH.")
|
if not self.debuggerInfo:
|
||||||
return 1
|
print("Could not find a suitable debugger in your PATH.")
|
||||||
|
return 1
|
||||||
|
|
||||||
# Parameters come from the CLI. We need to convert them before
|
# Parameters come from the CLI. We need to convert them before
|
||||||
# their use.
|
# their use.
|
||||||
|
@ -350,12 +350,35 @@ Migrator.prototype = {
|
|||||||
// STATE_USER_FXA_VERIFIED state. When the user clicks on the link in
|
// STATE_USER_FXA_VERIFIED state. When the user clicks on the link in
|
||||||
// the mail we should see an ONVERIFIED_NOTIFICATION which will cause us
|
// the mail we should see an ONVERIFIED_NOTIFICATION which will cause us
|
||||||
// to complete the migration.
|
// to complete the migration.
|
||||||
resendVerificationMail: Task.async(function * () {
|
resendVerificationMail: Task.async(function * (win) {
|
||||||
// warn if we aren't in the expected state - but go ahead anyway!
|
// warn if we aren't in the expected state - but go ahead anyway!
|
||||||
if (this._state != this.STATE_USER_FXA_VERIFIED) {
|
if (this._state != this.STATE_USER_FXA_VERIFIED) {
|
||||||
this.log.warn("createFxAccount called in an unexpected state: ${}", this._state);
|
this.log.warn("createFxAccount called in an unexpected state: ${}", this._state);
|
||||||
}
|
}
|
||||||
return fxAccounts.resendVerificationEmail();
|
let ok = true;
|
||||||
|
try {
|
||||||
|
yield fxAccounts.resendVerificationEmail();
|
||||||
|
} catch (ex) {
|
||||||
|
this.log.error("Failed to resend verification mail: ${}", ex);
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
let fxauser = yield fxAccounts.getSignedInUser();
|
||||||
|
let sb = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
|
||||||
|
|
||||||
|
let heading = ok ?
|
||||||
|
sb.formatStringFromName("verificationSentHeading", [fxauser.email], 1) :
|
||||||
|
sb.GetStringFromName("verificationNotSentHeading");
|
||||||
|
let title = sb.GetStringFromName(ok ? "verificationSentTitle" : "verificationNotSentTitle");
|
||||||
|
let description = sb.GetStringFromName(ok ? "verificationSentDescription"
|
||||||
|
: "verificationNotSentDescription");
|
||||||
|
|
||||||
|
let factory = Cc["@mozilla.org/prompter;1"]
|
||||||
|
.getService(Ci.nsIPromptFactory);
|
||||||
|
let prompt = factory.getPrompt(win, Ci.nsIPrompt);
|
||||||
|
let bag = prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
|
||||||
|
bag.setPropertyAsBool("allowTabModal", true);
|
||||||
|
|
||||||
|
prompt.alert(title, heading + "\n\n" + description);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// "forget" about the current Firefox account. This should only be called
|
// "forget" about the current Firefox account. This should only be called
|
||||||
|
@ -1801,9 +1801,11 @@ class Mochitest(MochitestUtilsMixin):
|
|||||||
# TODO: use mozrunner.local.debugger_arguments:
|
# TODO: use mozrunner.local.debugger_arguments:
|
||||||
# https://github.com/mozilla/mozbase/blob/master/mozrunner/mozrunner/local.py#L42
|
# https://github.com/mozilla/mozbase/blob/master/mozrunner/mozrunner/local.py#L42
|
||||||
|
|
||||||
debuggerInfo = mozdebug.get_debugger_info(options.debugger,
|
debuggerInfo = None
|
||||||
options.debuggerArgs,
|
if options.debugger:
|
||||||
options.debuggerInteractive)
|
debuggerInfo = mozdebug.get_debugger_info(options.debugger,
|
||||||
|
options.debuggerArgs,
|
||||||
|
options.debuggerInteractive)
|
||||||
|
|
||||||
if options.useTestMediaDevices:
|
if options.useTestMediaDevices:
|
||||||
devices = findTestMediaDevices(self.log)
|
devices = findTestMediaDevices(self.log)
|
||||||
|
@ -135,6 +135,7 @@ add_task(function* test_emptytitle_export()
|
|||||||
// 9. empty bookmarks db and continue
|
// 9. empty bookmarks db and continue
|
||||||
|
|
||||||
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
||||||
|
yield promiseAsyncUpdates();
|
||||||
|
|
||||||
const NOTITLE_URL = "http://notitle.mozilla.org/";
|
const NOTITLE_URL = "http://notitle.mozilla.org/";
|
||||||
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||||
@ -144,6 +145,7 @@ add_task(function* test_emptytitle_export()
|
|||||||
test_bookmarks.unfiled.push({ title: "", url: NOTITLE_URL });
|
test_bookmarks.unfiled.push({ title: "", url: NOTITLE_URL });
|
||||||
|
|
||||||
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
|
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
|
||||||
|
yield promiseAsyncUpdates();
|
||||||
remove_all_bookmarks();
|
remove_all_bookmarks();
|
||||||
|
|
||||||
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
||||||
@ -177,6 +179,7 @@ add_task(function* test_import_chromefavicon()
|
|||||||
const CHROME_FAVICON_URI_2 = NetUtil.newURI("chrome://global/skin/icons/error-16.png");
|
const CHROME_FAVICON_URI_2 = NetUtil.newURI("chrome://global/skin/icons/error-16.png");
|
||||||
|
|
||||||
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
||||||
|
yield promiseAsyncUpdates();
|
||||||
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||||
PAGE_URI,
|
PAGE_URI,
|
||||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||||
@ -201,6 +204,7 @@ add_task(function* test_import_chromefavicon()
|
|||||||
{ title: "Test", url: PAGE_URI.spec, icon: base64Icon });
|
{ title: "Test", url: PAGE_URI.spec, icon: base64Icon });
|
||||||
|
|
||||||
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
|
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
|
||||||
|
yield promiseAsyncUpdates();
|
||||||
|
|
||||||
// Change the favicon to check it's really imported again later.
|
// Change the favicon to check it's really imported again later.
|
||||||
deferred = Promise.defer();
|
deferred = Promise.defer();
|
||||||
@ -236,7 +240,10 @@ add_task(function* test_import_ontop()
|
|||||||
// 4. run the test-suite
|
// 4. run the test-suite
|
||||||
|
|
||||||
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
||||||
|
yield promiseAsyncUpdates();
|
||||||
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
|
yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
|
||||||
|
yield promiseAsyncUpdates();
|
||||||
|
|
||||||
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
|
||||||
yield promiseAsyncUpdates();
|
yield promiseAsyncUpdates();
|
||||||
yield testImportedBookmarks();
|
yield testImportedBookmarks();
|
||||||
|
@ -5922,6 +5922,21 @@
|
|||||||
"kind": "boolean",
|
"kind": "boolean",
|
||||||
"description": "How many times has the devtool's Responsive View been opened via the toolbox button?"
|
"description": "How many times has the devtool's Responsive View been opened via the toolbox button?"
|
||||||
},
|
},
|
||||||
|
"DEVTOOLS_EYEDROPPER_OPENED_BOOLEAN": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "boolean",
|
||||||
|
"description": "How many times has the devtool's Eyedropper tool been opened?"
|
||||||
|
},
|
||||||
|
"DEVTOOLS_MENU_EYEDROPPER_OPENED_BOOLEAN": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "boolean",
|
||||||
|
"description": "How many times has the devtool's eyedropper been opened via the devtools menu?"
|
||||||
|
},
|
||||||
|
"DEVTOOLS_PICKER_EYEDROPPER_OPENED_BOOLEAN": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "boolean",
|
||||||
|
"description": "How many times has the devtool's eyedropper been opened via the color picker?"
|
||||||
|
},
|
||||||
"DEVTOOLS_DEVELOPERTOOLBAR_OPENED_BOOLEAN": {
|
"DEVTOOLS_DEVELOPERTOOLBAR_OPENED_BOOLEAN": {
|
||||||
"expires_in_version": "never",
|
"expires_in_version": "never",
|
||||||
"kind": "boolean",
|
"kind": "boolean",
|
||||||
@ -6047,6 +6062,21 @@
|
|||||||
"kind": "flag",
|
"kind": "flag",
|
||||||
"description": "How many users have opened the devtool's Responsive View been opened via the toolbox button?"
|
"description": "How many users have opened the devtool's Responsive View been opened via the toolbox button?"
|
||||||
},
|
},
|
||||||
|
"DEVTOOLS_EYEDROPPER_OPENED_PER_USER_FLAG": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "flag",
|
||||||
|
"description": "How many users have opened the devtool's Eyedropper via the toolbox button?"
|
||||||
|
},
|
||||||
|
"DEVTOOLS_MENU_EYEDROPPER_OPENED_PER_USER_FLAG": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "flag",
|
||||||
|
"description": "How many users have opened the devtool's Eyedropper via the devtools menu?"
|
||||||
|
},
|
||||||
|
"DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "flag",
|
||||||
|
"description": "How many users have opened the devtool's Eyedropper via the color picker?"
|
||||||
|
},
|
||||||
"DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG": {
|
"DEVTOOLS_DEVELOPERTOOLBAR_OPENED_PER_USER_FLAG": {
|
||||||
"expires_in_version": "never",
|
"expires_in_version": "never",
|
||||||
"kind": "flag",
|
"kind": "flag",
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
// Test that the timeline front's start/stop/isRecording methods work in a
|
// Test that the timeline front's start/stop/isRecording methods work in a
|
||||||
// simple use case, and that markers events are sent when operations occur.
|
// simple use case, and that markers events are sent when operations occur.
|
||||||
|
// Note that this test isn't concerned with which markers are actually recorded,
|
||||||
|
// just that markers are recorded at all.
|
||||||
|
// Trying to check marker types here may lead to intermittents, see bug 1066474.
|
||||||
|
|
||||||
const {TimelineFront} = require("devtools/server/actors/timeline");
|
const {TimelineFront} = require("devtools/server/actors/timeline");
|
||||||
|
|
||||||
@ -14,37 +17,40 @@ add_task(function*() {
|
|||||||
|
|
||||||
initDebuggerServer();
|
initDebuggerServer();
|
||||||
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||||
|
|
||||||
let form = yield connectDebuggerClient(client);
|
let form = yield connectDebuggerClient(client);
|
||||||
let front = TimelineFront(client, form);
|
let front = TimelineFront(client, form);
|
||||||
|
|
||||||
|
ok(front, "The TimelineFront was created");
|
||||||
|
|
||||||
let isActive = yield front.isRecording();
|
let isActive = yield front.isRecording();
|
||||||
ok(!isActive, "Not initially recording");
|
ok(!isActive, "The TimelineFront is not initially recording");
|
||||||
|
|
||||||
doc.body.innerHeight; // flush any pending reflow
|
info("Flush any pending reflows");
|
||||||
|
let forceSyncReflow = doc.body.innerHeight;
|
||||||
|
|
||||||
|
info("Start recording");
|
||||||
yield front.start();
|
yield front.start();
|
||||||
|
|
||||||
isActive = yield front.isRecording();
|
isActive = yield front.isRecording();
|
||||||
ok(isActive, "Recording after start()");
|
ok(isActive, "The TimelineFront is now recording");
|
||||||
|
|
||||||
|
info("Change some style on the page to cause style/reflow/paint");
|
||||||
|
let onMarkers = once(front, "markers");
|
||||||
doc.body.style.padding = "10px";
|
doc.body.style.padding = "10px";
|
||||||
|
let markers = yield onMarkers;
|
||||||
|
|
||||||
let markers = yield once(front, "markers");
|
ok(true, "The markers event was fired");
|
||||||
|
ok(markers.length > 0, "Markers were returned");
|
||||||
|
|
||||||
ok(markers.length > 0, "markers were returned");
|
info("Flush pending reflows again");
|
||||||
ok(markers.some(m => m.name == "Reflow"), "markers includes Reflow");
|
forceSyncReflow = doc.body.innerHeight;
|
||||||
ok(markers.some(m => m.name == "Paint"), "markers includes Paint");
|
|
||||||
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
|
|
||||||
|
|
||||||
|
info("Change some style on the page to cause style/paint");
|
||||||
|
onMarkers = once(front, "markers");
|
||||||
doc.body.style.backgroundColor = "red";
|
doc.body.style.backgroundColor = "red";
|
||||||
|
markers = yield onMarkers;
|
||||||
markers = yield once(front, "markers");
|
|
||||||
|
|
||||||
ok(markers.length > 0, "markers were returned");
|
ok(markers.length > 0, "markers were returned");
|
||||||
ok(!markers.some(m => m.name == "Reflow"), "markers doesn't include Reflow");
|
|
||||||
ok(markers.some(m => m.name == "Paint"), "markers includes Paint");
|
|
||||||
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
|
|
||||||
|
|
||||||
yield front.stop();
|
yield front.stop();
|
||||||
|
|
||||||
|
@ -83,6 +83,11 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||||||
throw new Error('Unsupported version: ' + version);
|
throw new Error('Unsupported version: ' + version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some source maps produce relative source paths like "./foo.js" instead of
|
||||||
|
// "foo.js". Normalize these first so that future comparisons will succeed.
|
||||||
|
// See bugzil.la/1090768.
|
||||||
|
sources = sources.map(util.normalize);
|
||||||
|
|
||||||
// Pass `true` below to allow duplicate names and sources. While source maps
|
// Pass `true` below to allow duplicate names and sources. While source maps
|
||||||
// are intended to be compressed and deduplicated, the TypeScript compiler
|
// are intended to be compressed and deduplicated, the TypeScript compiler
|
||||||
// sometimes generates source maps with duplicates in them. See Github issue
|
// sometimes generates source maps with duplicates in them. See Github issue
|
||||||
@ -307,6 +312,33 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||||||
return binarySearch.search(aNeedle, aMappings, aComparator);
|
return binarySearch.search(aNeedle, aMappings, aComparator);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the last column for each generated mapping. The last column is
|
||||||
|
* inclusive.
|
||||||
|
*/
|
||||||
|
SourceMapConsumer.prototype.computeColumnSpans =
|
||||||
|
function SourceMapConsumer_computeColumnSpans() {
|
||||||
|
for (var index = 0; index < this._generatedMappings.length; ++index) {
|
||||||
|
var mapping = this._generatedMappings[index];
|
||||||
|
|
||||||
|
// Mappings do not contain a field for the last generated columnt. We
|
||||||
|
// can come up with an optimistic estimate, however, by assuming that
|
||||||
|
// mappings are contiguous (i.e. given two consecutive mappings, the
|
||||||
|
// first mapping ends where the second one starts).
|
||||||
|
if (index + 1 < this._generatedMappings.length) {
|
||||||
|
var nextMapping = this._generatedMappings[index + 1];
|
||||||
|
|
||||||
|
if (mapping.generatedLine === nextMapping.generatedLine) {
|
||||||
|
mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last mapping for each line spans the entire line.
|
||||||
|
mapping.lastGeneratedColumn = Infinity;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the original source, line, and column information for the generated
|
* Returns the original source, line, and column information for the generated
|
||||||
* source's line and column positions provided. The only argument is an object
|
* source's line and column positions provided. The only argument is an object
|
||||||
@ -329,23 +361,27 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||||||
generatedColumn: util.getArg(aArgs, 'column')
|
generatedColumn: util.getArg(aArgs, 'column')
|
||||||
};
|
};
|
||||||
|
|
||||||
var mapping = this._findMapping(needle,
|
var index = this._findMapping(needle,
|
||||||
this._generatedMappings,
|
this._generatedMappings,
|
||||||
"generatedLine",
|
"generatedLine",
|
||||||
"generatedColumn",
|
"generatedColumn",
|
||||||
util.compareByGeneratedPositions);
|
util.compareByGeneratedPositions);
|
||||||
|
|
||||||
if (mapping && mapping.generatedLine === needle.generatedLine) {
|
if (index >= 0) {
|
||||||
var source = util.getArg(mapping, 'source', null);
|
var mapping = this._generatedMappings[index];
|
||||||
if (source != null && this.sourceRoot != null) {
|
|
||||||
source = util.join(this.sourceRoot, source);
|
if (mapping.generatedLine === needle.generatedLine) {
|
||||||
|
var source = util.getArg(mapping, 'source', null);
|
||||||
|
if (source != null && this.sourceRoot != null) {
|
||||||
|
source = util.join(this.sourceRoot, source);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
source: source,
|
||||||
|
line: util.getArg(mapping, 'originalLine', null),
|
||||||
|
column: util.getArg(mapping, 'originalColumn', null),
|
||||||
|
name: util.getArg(mapping, 'name', null)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
source: source,
|
|
||||||
line: util.getArg(mapping, 'originalLine', null),
|
|
||||||
column: util.getArg(mapping, 'originalColumn', null),
|
|
||||||
name: util.getArg(mapping, 'name', null)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -423,25 +459,82 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
|
|||||||
needle.source = util.relative(this.sourceRoot, needle.source);
|
needle.source = util.relative(this.sourceRoot, needle.source);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mapping = this._findMapping(needle,
|
var index = this._findMapping(needle,
|
||||||
this._originalMappings,
|
this._originalMappings,
|
||||||
"originalLine",
|
"originalLine",
|
||||||
"originalColumn",
|
"originalColumn",
|
||||||
util.compareByOriginalPositions);
|
util.compareByOriginalPositions);
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
var mapping = this._originalMappings[index];
|
||||||
|
|
||||||
if (mapping) {
|
|
||||||
return {
|
return {
|
||||||
line: util.getArg(mapping, 'generatedLine', null),
|
line: util.getArg(mapping, 'generatedLine', null),
|
||||||
column: util.getArg(mapping, 'generatedColumn', null)
|
column: util.getArg(mapping, 'generatedColumn', null),
|
||||||
|
lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
line: null,
|
line: null,
|
||||||
column: null
|
column: null,
|
||||||
|
lastColumn: null
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all generated line and column information for the original source
|
||||||
|
* and line provided. The only argument is an object with the following
|
||||||
|
* properties:
|
||||||
|
*
|
||||||
|
* - source: The filename of the original source.
|
||||||
|
* - line: The line number in the original source.
|
||||||
|
*
|
||||||
|
* and an array of objects is returned, each with the following properties:
|
||||||
|
*
|
||||||
|
* - line: The line number in the generated source, or null.
|
||||||
|
* - column: The column number in the generated source, or null.
|
||||||
|
*/
|
||||||
|
SourceMapConsumer.prototype.allGeneratedPositionsFor =
|
||||||
|
function SourceMapConsumer_allGeneratedPositionsFor(aArgs) {
|
||||||
|
// When there is no exact match, SourceMapConsumer.prototype._findMapping
|
||||||
|
// returns the index of the closest mapping less than the needle. By
|
||||||
|
// setting needle.originalColumn to Infinity, we thus find the last
|
||||||
|
// mapping for the given line, provided such a mapping exists.
|
||||||
|
var needle = {
|
||||||
|
source: util.getArg(aArgs, 'source'),
|
||||||
|
originalLine: util.getArg(aArgs, 'line'),
|
||||||
|
originalColumn: Infinity
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.sourceRoot != null) {
|
||||||
|
needle.source = util.relative(this.sourceRoot, needle.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
var mappings = [];
|
||||||
|
|
||||||
|
var index = this._findMapping(needle,
|
||||||
|
this._originalMappings,
|
||||||
|
"originalLine",
|
||||||
|
"originalColumn",
|
||||||
|
util.compareByOriginalPositions);
|
||||||
|
if (index >= 0) {
|
||||||
|
var mapping = this._originalMappings[index];
|
||||||
|
|
||||||
|
while (mapping && mapping.originalLine === needle.originalLine) {
|
||||||
|
mappings.push({
|
||||||
|
line: util.getArg(mapping, 'generatedLine', null),
|
||||||
|
column: util.getArg(mapping, 'generatedColumn', null),
|
||||||
|
lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
|
||||||
|
});
|
||||||
|
|
||||||
|
mapping = this._originalMappings[--index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappings.reverse();
|
||||||
|
};
|
||||||
|
|
||||||
SourceMapConsumer.GENERATED_ORDER = 1;
|
SourceMapConsumer.GENERATED_ORDER = 1;
|
||||||
SourceMapConsumer.ORIGINAL_ORDER = 2;
|
SourceMapConsumer.ORIGINAL_ORDER = 2;
|
||||||
|
|
||||||
@ -836,17 +929,17 @@ define('source-map/binary-search', ['require', 'exports', 'module' , ], function
|
|||||||
//
|
//
|
||||||
// 1. We find the exact element we are looking for.
|
// 1. We find the exact element we are looking for.
|
||||||
//
|
//
|
||||||
// 2. We did not find the exact element, but we can return the next
|
// 2. We did not find the exact element, but we can return the index of
|
||||||
// closest element that is less than that element.
|
// the next closest element that is less than that element.
|
||||||
//
|
//
|
||||||
// 3. We did not find the exact element, and there is no next-closest
|
// 3. We did not find the exact element, and there is no next-closest
|
||||||
// element which is less than the one we are searching for, so we
|
// element which is less than the one we are searching for, so we
|
||||||
// return null.
|
// return -1.
|
||||||
var mid = Math.floor((aHigh - aLow) / 2) + aLow;
|
var mid = Math.floor((aHigh - aLow) / 2) + aLow;
|
||||||
var cmp = aCompare(aNeedle, aHaystack[mid], true);
|
var cmp = aCompare(aNeedle, aHaystack[mid], true);
|
||||||
if (cmp === 0) {
|
if (cmp === 0) {
|
||||||
// Found the element we are looking for.
|
// Found the element we are looking for.
|
||||||
return aHaystack[mid];
|
return mid;
|
||||||
}
|
}
|
||||||
else if (cmp > 0) {
|
else if (cmp > 0) {
|
||||||
// aHaystack[mid] is greater than our needle.
|
// aHaystack[mid] is greater than our needle.
|
||||||
@ -856,7 +949,7 @@ define('source-map/binary-search', ['require', 'exports', 'module' , ], function
|
|||||||
}
|
}
|
||||||
// We did not find an exact match, return the next closest one
|
// We did not find an exact match, return the next closest one
|
||||||
// (termination case 2).
|
// (termination case 2).
|
||||||
return aHaystack[mid];
|
return mid;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// aHaystack[mid] is less than our needle.
|
// aHaystack[mid] is less than our needle.
|
||||||
@ -866,18 +959,16 @@ define('source-map/binary-search', ['require', 'exports', 'module' , ], function
|
|||||||
}
|
}
|
||||||
// The exact needle element was not found in this haystack. Determine if
|
// The exact needle element was not found in this haystack. Determine if
|
||||||
// we are in termination case (2) or (3) and return the appropriate thing.
|
// we are in termination case (2) or (3) and return the appropriate thing.
|
||||||
return aLow < 0
|
return aLow < 0 ? -1 : aLow;
|
||||||
? null
|
|
||||||
: aHaystack[aLow];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an implementation of binary search which will always try and return
|
* This is an implementation of binary search which will always try and return
|
||||||
* the next lowest value checked if there is no exact hit. This is because
|
* the index of next lowest value checked if there is no exact hit. This is
|
||||||
* mappings between original and generated line/col pairs are single points,
|
* because mappings between original and generated line/col pairs are single
|
||||||
* and there is an implicit region between each of them, so a miss just means
|
* points, and there is an implicit region between each of them, so a miss
|
||||||
* that you aren't on the very start of a region.
|
* just means that you aren't on the very start of a region.
|
||||||
*
|
*
|
||||||
* @param aNeedle The element you are looking for.
|
* @param aNeedle The element you are looking for.
|
||||||
* @param aHaystack The array that is being searched.
|
* @param aHaystack The array that is being searched.
|
||||||
@ -886,9 +977,10 @@ define('source-map/binary-search', ['require', 'exports', 'module' , ], function
|
|||||||
* than, equal to, or greater than the element, respectively.
|
* than, equal to, or greater than the element, respectively.
|
||||||
*/
|
*/
|
||||||
exports.search = function search(aNeedle, aHaystack, aCompare) {
|
exports.search = function search(aNeedle, aHaystack, aCompare) {
|
||||||
return aHaystack.length > 0
|
if (aHaystack.length === 0) {
|
||||||
? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare)
|
return -1;
|
||||||
: null;
|
}
|
||||||
|
return recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare)
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -142,6 +142,22 @@ define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-ma
|
|||||||
sourceRoot: '/the/root',
|
sourceRoot: '/the/root',
|
||||||
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
|
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
|
||||||
};
|
};
|
||||||
|
exports.testMapRelativeSources = {
|
||||||
|
version: 3,
|
||||||
|
file: 'min.js',
|
||||||
|
names: ['bar', 'baz', 'n'],
|
||||||
|
sources: ['./one.js', './two.js'],
|
||||||
|
sourcesContent: [
|
||||||
|
' ONE.foo = function (bar) {\n' +
|
||||||
|
' return baz(bar);\n' +
|
||||||
|
' };',
|
||||||
|
' TWO.inc = function (n) {\n' +
|
||||||
|
' return n + 1;\n' +
|
||||||
|
' };'
|
||||||
|
],
|
||||||
|
sourceRoot: '/the/root',
|
||||||
|
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
|
||||||
|
};
|
||||||
exports.emptyMap = {
|
exports.emptyMap = {
|
||||||
version: 3,
|
version: 3,
|
||||||
file: 'min.js',
|
file: 'min.js',
|
||||||
|
@ -28,7 +28,7 @@ define("test/source-map/test-binary-search", ["require", "exports", "module"], f
|
|||||||
binarySearch.search(needle, haystack, numberCompare);
|
binarySearch.search(needle, haystack, numberCompare);
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(binarySearch.search(needle, haystack, numberCompare), 20);
|
assert.equal(haystack[binarySearch.search(needle, haystack, numberCompare)], 20);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports['test too low'] = function (assert, util) {
|
exports['test too low'] = function (assert, util) {
|
||||||
@ -39,21 +39,21 @@ define("test/source-map/test-binary-search", ["require", "exports", "module"], f
|
|||||||
binarySearch.search(needle, haystack, numberCompare);
|
binarySearch.search(needle, haystack, numberCompare);
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(binarySearch.search(needle, haystack, numberCompare), null);
|
assert.equal(binarySearch.search(needle, haystack, numberCompare), -1);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports['test exact search'] = function (assert, util) {
|
exports['test exact search'] = function (assert, util) {
|
||||||
var needle = 4;
|
var needle = 4;
|
||||||
var haystack = [2,4,6,8,10,12,14,16,18,20];
|
var haystack = [2,4,6,8,10,12,14,16,18,20];
|
||||||
|
|
||||||
assert.equal(binarySearch.search(needle, haystack, numberCompare), 4);
|
assert.equal(haystack[binarySearch.search(needle, haystack, numberCompare)], 4);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports['test fuzzy search'] = function (assert, util) {
|
exports['test fuzzy search'] = function (assert, util) {
|
||||||
var needle = 19;
|
var needle = 19;
|
||||||
var haystack = [2,4,6,8,10,12,14,16,18,20];
|
var haystack = [2,4,6,8,10,12,14,16,18,20];
|
||||||
|
|
||||||
assert.equal(binarySearch.search(needle, haystack, numberCompare), 18);
|
assert.equal(haystack[binarySearch.search(needle, haystack, numberCompare)], 18);
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -257,6 +257,25 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
|
|||||||
}, Error);
|
}, Error);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports['test that we can get the original source content with relative source paths'] = function (assert, util) {
|
||||||
|
var map = new SourceMapConsumer(util.testMapRelativeSources);
|
||||||
|
var sources = map.sources;
|
||||||
|
|
||||||
|
assert.equal(map.sourceContentFor(sources[0]), ' ONE.foo = function (bar) {\n return baz(bar);\n };');
|
||||||
|
assert.equal(map.sourceContentFor(sources[1]), ' TWO.inc = function (n) {\n return n + 1;\n };');
|
||||||
|
assert.equal(map.sourceContentFor("one.js"), ' ONE.foo = function (bar) {\n return baz(bar);\n };');
|
||||||
|
assert.equal(map.sourceContentFor("two.js"), ' TWO.inc = function (n) {\n return n + 1;\n };');
|
||||||
|
assert.throws(function () {
|
||||||
|
map.sourceContentFor("");
|
||||||
|
}, Error);
|
||||||
|
assert.throws(function () {
|
||||||
|
map.sourceContentFor("/the/root/three.js");
|
||||||
|
}, Error);
|
||||||
|
assert.throws(function () {
|
||||||
|
map.sourceContentFor("three.js");
|
||||||
|
}, Error);
|
||||||
|
};
|
||||||
|
|
||||||
exports['test sourceRoot + generatedPositionFor'] = function (assert, util) {
|
exports['test sourceRoot + generatedPositionFor'] = function (assert, util) {
|
||||||
var map = new SourceMapGenerator({
|
var map = new SourceMapGenerator({
|
||||||
sourceRoot: 'foo/bar',
|
sourceRoot: 'foo/bar',
|
||||||
@ -295,6 +314,158 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
|
|||||||
assert.equal(pos.column, 2);
|
assert.equal(pos.column, 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports['test allGeneratedPositionsFor'] = function (assert, util) {
|
||||||
|
var map = new SourceMapGenerator({
|
||||||
|
file: 'generated.js'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 1, column: 1 },
|
||||||
|
generated: { line: 2, column: 2 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 1, column: 1 },
|
||||||
|
generated: { line: 2, column: 2 },
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 2, column: 1 },
|
||||||
|
generated: { line: 3, column: 2 },
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 2, column: 2 },
|
||||||
|
generated: { line: 3, column: 3 },
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 3, column: 1 },
|
||||||
|
generated: { line: 4, column: 2 },
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
map = new SourceMapConsumer(map.toString());
|
||||||
|
|
||||||
|
var mappings = map.allGeneratedPositionsFor({
|
||||||
|
line: 2,
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(mappings.length, 2);
|
||||||
|
assert.equal(mappings[0].line, 3);
|
||||||
|
assert.equal(mappings[0].column, 2);
|
||||||
|
assert.equal(mappings[1].line, 3);
|
||||||
|
assert.equal(mappings[1].column, 3);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports['test allGeneratedPositionsFor for line with no mappings'] = function (assert, util) {
|
||||||
|
var map = new SourceMapGenerator({
|
||||||
|
file: 'generated.js'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 1, column: 1 },
|
||||||
|
generated: { line: 2, column: 2 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 1, column: 1 },
|
||||||
|
generated: { line: 2, column: 2 },
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 3, column: 1 },
|
||||||
|
generated: { line: 4, column: 2 },
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
map = new SourceMapConsumer(map.toString());
|
||||||
|
|
||||||
|
var mappings = map.allGeneratedPositionsFor({
|
||||||
|
line: 2,
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(mappings.length, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports['test allGeneratedPositionsFor source map with no mappings'] = function (assert, util) {
|
||||||
|
var map = new SourceMapGenerator({
|
||||||
|
file: 'generated.js'
|
||||||
|
});
|
||||||
|
map = new SourceMapConsumer(map.toString());
|
||||||
|
|
||||||
|
var mappings = map.allGeneratedPositionsFor({
|
||||||
|
line: 2,
|
||||||
|
source: 'bar.coffee'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(mappings.length, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports['test computeColumnSpans'] = function (assert, util) {
|
||||||
|
var map = new SourceMapGenerator({
|
||||||
|
file: 'generated.js'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 1, column: 1 },
|
||||||
|
generated: { line: 1, column: 1 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 2, column: 1 },
|
||||||
|
generated: { line: 2, column: 1 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 2, column: 2 },
|
||||||
|
generated: { line: 2, column: 10 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 2, column: 3 },
|
||||||
|
generated: { line: 2, column: 20 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 3, column: 1 },
|
||||||
|
generated: { line: 3, column: 1 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map.addMapping({
|
||||||
|
original: { line: 3, column: 2 },
|
||||||
|
generated: { line: 3, column: 2 },
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
map = new SourceMapConsumer(map.toString());
|
||||||
|
|
||||||
|
map.computeColumnSpans();
|
||||||
|
|
||||||
|
var mappings = map.allGeneratedPositionsFor({
|
||||||
|
line: 1,
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(mappings.length, 1);
|
||||||
|
assert.equal(mappings[0].lastColumn, Infinity);
|
||||||
|
|
||||||
|
var mappings = map.allGeneratedPositionsFor({
|
||||||
|
line: 2,
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(mappings.length, 3);
|
||||||
|
assert.equal(mappings[0].lastColumn, 9);
|
||||||
|
assert.equal(mappings[1].lastColumn, 19);
|
||||||
|
assert.equal(mappings[2].lastColumn, Infinity);
|
||||||
|
|
||||||
|
var mappings = map.allGeneratedPositionsFor({
|
||||||
|
line: 3,
|
||||||
|
source: 'foo.coffee'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(mappings.length, 2);
|
||||||
|
assert.equal(mappings[0].lastColumn, 1);
|
||||||
|
assert.equal(mappings[1].lastColumn, Infinity);
|
||||||
|
};
|
||||||
|
|
||||||
exports['test sourceRoot + originalPositionFor'] = function (assert, util) {
|
exports['test sourceRoot + originalPositionFor'] = function (assert, util) {
|
||||||
var map = new SourceMapGenerator({
|
var map = new SourceMapGenerator({
|
||||||
sourceRoot: 'foo/bar',
|
sourceRoot: 'foo/bar',
|
||||||
|
@ -3,6 +3,7 @@ head = head_sourcemap.js
|
|||||||
tail =
|
tail =
|
||||||
support-files = Utils.jsm
|
support-files = Utils.jsm
|
||||||
|
|
||||||
|
[test_util.js]
|
||||||
[test_source_node.js]
|
[test_source_node.js]
|
||||||
[test_source_map_generator.js]
|
[test_source_map_generator.js]
|
||||||
[test_source_map_consumer.js]
|
[test_source_map_consumer.js]
|
||||||
|
@ -584,20 +584,29 @@ xul|filefield + xul|button {
|
|||||||
xul|richlistbox,
|
xul|richlistbox,
|
||||||
xul|listbox {
|
xul|listbox {
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
|
background-color: #fff;
|
||||||
border: 1px solid #c1c1c1;
|
border: 1px solid #c1c1c1;
|
||||||
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
xul|treechildren::-moz-tree-row,
|
xul|treechildren::-moz-tree-row,
|
||||||
xul|listbox xul|listitem {
|
xul|listbox xul|listitem {
|
||||||
padding: 5px;
|
padding: 0.3em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xul|treechildren::-moz-tree-row(hover),
|
||||||
|
xul|listbox xul|listitem:hover {
|
||||||
|
background-color: rgba(0,149,221,0.25);
|
||||||
|
}
|
||||||
|
|
||||||
xul|treechildren::-moz-tree-row(selected),
|
xul|treechildren::-moz-tree-row(selected),
|
||||||
xul|listbox xul|listitem[selected="true"] {
|
xul|listbox xul|listitem[selected="true"] {
|
||||||
background-color: #f1f1f1;
|
background-color: #0095dd;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Trees */
|
/* Trees */
|
||||||
@ -652,4 +661,18 @@ xul|treecol:not([hideheader="true"]) > xul|*.treecol-sortdirection[sortDirection
|
|||||||
xul|treecol:not([hideheader="true"]) > xul|*.treecol-sortdirection[sortDirection] {
|
xul|treecol:not([hideheader="true"]) > xul|*.treecol-sortdirection[sortDirection] {
|
||||||
list-style-image: url("chrome://global/skin/in-content/sorter@2x.png");
|
list-style-image: url("chrome://global/skin/in-content/sorter@2x.png");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the only way to increase the height of a tree row unfortunately */
|
||||||
|
xul|treechildren::-moz-tree-row {
|
||||||
|
min-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color needs to be set on tree cell in order to be applied */
|
||||||
|
xul|treechildren::-moz-tree-cell-text {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
xul|treechildren::-moz-tree-cell-text(selected) {
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
@ -154,9 +154,7 @@ HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur, gl::GLContext* aGLCont
|
|||||||
mRBSwapSupport = false;
|
mRBSwapSupport = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RegisterHwcEventCallback()) {
|
RegisterHwcEventCallback();
|
||||||
EnableVsync(true);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
char propValue[PROPERTY_VALUE_MAX];
|
char propValue[PROPERTY_VALUE_MAX];
|
||||||
property_get("ro.display.colorfill", propValue, "0");
|
property_get("ro.display.colorfill", propValue, "0");
|
||||||
@ -181,17 +179,22 @@ HwcComposer2D::GetInstance()
|
|||||||
return sInstance;
|
return sInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
HwcComposer2D::EnableVsync(bool aEnable)
|
HwcComposer2D::EnableVsync(bool aEnable)
|
||||||
{
|
{
|
||||||
#if ANDROID_VERSION >= 17
|
#if ANDROID_VERSION >= 17
|
||||||
if (NS_IsMainThread()) {
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
RunVsyncEventControl(aEnable);
|
if (!mHasHWVsync) {
|
||||||
} else {
|
return false;
|
||||||
nsRefPtr<nsIRunnable> event =
|
|
||||||
NS_NewRunnableMethodWithArg<bool>(this, &HwcComposer2D::RunVsyncEventControl, aEnable);
|
|
||||||
NS_DispatchToMainThread(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HwcDevice* device = (HwcDevice*)GetGonkDisplay()->GetHWCDevice();
|
||||||
|
if (!device) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, aEnable);
|
||||||
|
return aEnable;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,27 +211,10 @@ HwcComposer2D::RegisterHwcEventCallback()
|
|||||||
// Disable Vsync first, and then register callback functions.
|
// Disable Vsync first, and then register callback functions.
|
||||||
device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, false);
|
device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, false);
|
||||||
device->registerProcs(device, &sHWCProcs);
|
device->registerProcs(device, &sHWCProcs);
|
||||||
mHasHWVsync = true;
|
mHasHWVsync = gfxPrefs::HardwareVsyncEnabled();
|
||||||
|
|
||||||
if (!gfxPrefs::HardwareVsyncEnabled()) {
|
|
||||||
device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, false);
|
|
||||||
mHasHWVsync = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mHasHWVsync;
|
return mHasHWVsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
HwcComposer2D::RunVsyncEventControl(bool aEnable)
|
|
||||||
{
|
|
||||||
if (mHasHWVsync) {
|
|
||||||
HwcDevice* device = (HwcDevice*)GetGonkDisplay()->GetHWCDevice();
|
|
||||||
if (device && device->eventControl) {
|
|
||||||
device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, aEnable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
|
HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +91,7 @@ public:
|
|||||||
|
|
||||||
bool Render(EGLDisplay dpy, EGLSurface sur);
|
bool Render(EGLDisplay dpy, EGLSurface sur);
|
||||||
|
|
||||||
void EnableVsync(bool aEnable);
|
bool EnableVsync(bool aEnable);
|
||||||
#if ANDROID_VERSION >= 17
|
#if ANDROID_VERSION >= 17
|
||||||
bool RegisterHwcEventCallback();
|
bool RegisterHwcEventCallback();
|
||||||
void Vsync(int aDisplay, int64_t aTimestamp);
|
void Vsync(int aDisplay, int64_t aTimestamp);
|
||||||
@ -111,10 +111,6 @@ private:
|
|||||||
void setHwcGeometry(bool aGeometryChanged);
|
void setHwcGeometry(bool aGeometryChanged);
|
||||||
void SendtoLayerScope();
|
void SendtoLayerScope();
|
||||||
|
|
||||||
#if ANDROID_VERSION >= 17
|
|
||||||
void RunVsyncEventControl(bool aEnable);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
HwcDevice* mHwc;
|
HwcDevice* mHwc;
|
||||||
HwcList* mList;
|
HwcList* mList;
|
||||||
hwc_display_t mDpy;
|
hwc_display_t mDpy;
|
||||||
|
Loading…
Reference in New Issue
Block a user