author | Wes Kocher <wkocher@mozilla.com> |
Tue, 21 Jan 2014 17:34:46 -0800 | |
changeset 164561 | 9ab3440df7b8c2639ddbcbc7af0e071553ee2093 |
parent 164542 | 03bdec48d0ac18016bf0e59b0357d8d45c0db903 (current diff) |
parent 164560 | 8f4ecbf938cd15199f017b5b21ca3c3e167802a3 (diff) |
child 164562 | 554475555e21c65fb329e7b2ec200d962aec7d0c |
push id | 38744 |
push user | kwierso@gmail.com |
push date | Wed, 22 Jan 2014 01:36:02 +0000 |
treeherder | mozilla-inbound@554475555e21 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 29.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -183,19 +183,16 @@ pref("privacy.item.history", true); pref("privacy.item.formdata", true); pref("privacy.item.downloads", true); pref("privacy.item.passwords", true); pref("privacy.item.sessions", true); pref("privacy.item.geolocation", true); pref("privacy.item.siteSettings", true); pref("privacy.item.syncAccount", true); -// URL to the Learn More link XXX this is the firefox one. Bug 495578 fixes this. -pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/"); - // base url for the wifi geolocation network provider pref("geo.wifi.uri", "https://maps.googleapis.com/maps/api/browserlocation/json"); // enable geo pref("geo.enabled", true); // content sink control -- controls responsiveness during page load // see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9 @@ -337,17 +334,16 @@ pref("browser.safebrowsing.provider.0.ge // HTML report pages pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}"); pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}"); pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}"); pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}"); pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}"); // FAQ URLs -pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/%APP%/geolocation/"); // Name of the about: page contributed by safebrowsing to handle display of error // pages on phishing/malware hits. (bug 399233) pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4);
--- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -7,17 +7,17 @@ <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -6,17 +6,17 @@ <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="fce1a137746dbd354bca1918f02f96d51c40bad2"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/> <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -7,17 +7,17 @@ <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "a43f6c119d80637dd3e36975e8f38b7f19b5c95c", + "revision": "98abf6bda1c12b45389ec6bc2acd3e3e901e3163", "repo_path": "/integration/gaia-central" }
--- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -6,17 +6,17 @@ <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -5,17 +5,17 @@ <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml +++ b/b2g/config/inari/sources.xml @@ -7,17 +7,17 @@ <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/> <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml +++ b/b2g/config/leo/sources.xml @@ -6,17 +6,17 @@ <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml +++ b/b2g/config/mako/sources.xml @@ -6,17 +6,17 @@ <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="fce1a137746dbd354bca1918f02f96d51c40bad2"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/> <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -6,17 +6,17 @@ <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e0b7c709ddc21c407ee3360d3203e9eb84535b66"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8d18b1e2fd06c84a879f99f6e8ca1f104eeacb13"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/> <project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="e2f73049f8d52fb06cb9b5d923c1280557aa9238"/> <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -994,17 +994,17 @@ let BookmarkingUI = { if (event.target != event.currentTarget) return; let widget = CustomizableUI.getWidget("bookmarks-menu-button") .forWindow(window); if (widget.overflowed) { // Don't open a popup in the overflow popup, rather just open the Library. event.preventDefault(); - widget.node.removeAttribute("noautoclose"); + widget.node.removeAttribute("closemenu"); PlacesCommandHook.showPlacesOrganizer("BookmarksMenu"); return; } if (!this._popupNeedsUpdate) return; this._popupNeedsUpdate = false; @@ -1167,28 +1167,28 @@ let BookmarkingUI = { // Handle special case when the button is in the panel. let widgetGroup = CustomizableUI.getWidget("bookmarks-menu-button"); let widget = widgetGroup.forWindow(window); if (widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) { let view = document.getElementById("PanelUI-bookmarks"); view.addEventListener("ViewShowing", this.onPanelMenuViewShowing); view.addEventListener("ViewHiding", this.onPanelMenuViewHiding); - widget.node.setAttribute("noautoclose", "true"); + widget.node.setAttribute("closemenu", "none"); PanelUI.showSubView("PanelUI-bookmarks", widget.node, CustomizableUI.AREA_PANEL); return; } else if (widget.overflowed) { // Allow to close the panel if the page is already bookmarked, cause // we are going to open the edit bookmark panel. if (this._itemIds.length > 0) - widget.node.removeAttribute("noautoclose"); + widget.node.removeAttribute("closemenu"); else - widget.node.setAttribute("noautoclose", "true"); + widget.node.setAttribute("closemenu", "none"); } // Ignore clicks on the star if we are updating its state. if (!this._pendingStmt) { PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0); } },
--- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -1166,17 +1166,17 @@ SocialStatus = { // if we're a slice in the hamburger, use that panel instead let widgetGroup = CustomizableUI.getWidget(aToolbarButton.getAttribute("id")); let widget = widgetGroup.forWindow(window); let panel, showingEvent, hidingEvent; let inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL; if (inMenuPanel) { panel = document.getElementById("PanelUI-socialapi"); this._attachNotificatonPanel(panel, aToolbarButton, provider); - widget.node.setAttribute("noautoclose", "true"); + widget.node.setAttribute("closemenu", "none"); showingEvent = "ViewShowing"; hidingEvent = "ViewHiding"; } else { panel = document.getElementById("social-notification-panel"); this._attachNotificatonPanel(panel, aToolbarButton, provider); showingEvent = "popupshown"; hidingEvent = "popuphidden"; }
--- a/browser/base/content/socialmarks.xml +++ b/browser/base/content/socialmarks.xml @@ -18,17 +18,17 @@ <field name="inMenuPanel">false</field> <property name="panel"> <getter> let widgetGroup = CustomizableUI.getWidget(this.getAttribute("id")); let widget = widgetGroup.forWindow(window); this.inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL; if (this.inMenuPanel) { - widget.node.setAttribute("noautoclose", "true"); + widget.node.setAttribute("closemenu", "none"); return document.getElementById("PanelUI-socialapi"); } return document.getAnonymousElementByAttribute(this, "anonid", "panel"); </getter> </property> <property name="content"> <getter><![CDATA[
--- a/browser/components/customizableui/content/customizeMode.inc.xul +++ b/browser/components/customizableui/content/customizeMode.inc.xul @@ -2,18 +2,27 @@ - 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/. --> <hbox id="customization-container" flex="1" hidden="true"> <vbox flex="1" id="customization-palette-container"> <label id="customization-header"> &customizeMode.menuAndToolbars.header; </label> + <hbox id="customization-empty" hidden="true"> + <label>&customizeMode.menuAndToolbars.empty;</label> + <label onclick="BrowserOpenAddonsMgr('addons://discovery/');" + onkeypress="BrowserOpenAddonsMgr('addons://discovery/');" + id="customization-more-tools" + class="text-link"> + &customizeMode.menuAndToolbars.emptyLink; + </label> + </hbox> <vbox id="customization-palette" flex="1"/> - <spacer flex="1"/> + <spacer id="customization-spacer" flex="1"/> <hbox> <button id="customization-toolbar-visibility-button" label="&customizeMode.toolbars;" class="customizationmode-button" type="menu"> <menupopup id="customization-toolbar-menu" onpopupshowing="onViewToolbarsPopupShowing(event)"/> </button> <spacer flex="1"/> <button id="customization-reset-button" oncommand="gCustomizeMode.reset();" label="&customizeMode.restoreDefaults;" class="customizationmode-button"/> </hbox> </vbox>
--- a/browser/components/customizableui/content/panelUI.js +++ b/browser/components/customizableui/content/panelUI.js @@ -325,19 +325,25 @@ const PanelUI = { } }, /** * This function can be used as a command event listener for subviews * so that the panel knows if and when to close itself. */ onCommandHandler: function(aEvent) { - if (!aEvent.originalTarget.hasAttribute("noautoclose")) { - PanelUI.hide(); + let closemenu = aEvent.originalTarget.getAttribute("closemenu"); + if (closemenu == "none") { + return; } + if (closemenu == "single") { + this.showMainView(); + return; + } + this.hide(); }, /** * Open a dialog window that allow the user to customize listed character sets. */ onCharsetCustomizeCommand: function() { this.hide(); window.openDialog("chrome://global/content/customizeCharset.xul",
--- a/browser/components/customizableui/src/CustomizableUI.jsm +++ b/browser/components/customizableui/src/CustomizableUI.jsm @@ -1225,30 +1225,31 @@ let CustomizableUIInternal = { maybeAutoHidePanel: function(aEvent) { if (aEvent.type == "keypress") { if (aEvent.keyCode != aEvent.DOM_VK_ENTER && aEvent.keyCode != aEvent.DOM_VK_RETURN) { return; } // If the user hit enter/return, we don't check preventDefault - it makes sense // that this was prevented, but we probably still want to close the panel. - // If consumers don't want this to happen, they should specify noautoclose. + // If consumers don't want this to happen, they should specify the closemenu + // attribute. } else if (aEvent.type != "command") { // mouse events: if (aEvent.defaultPrevented || aEvent.button != 0) { return; } let isInteractive = this._isOnInteractiveElement(aEvent); LOG("maybeAutoHidePanel: interactive ? " + isInteractive); if (isInteractive) { return; } } - if (aEvent.target.getAttribute("noautoclose") == "true" || + if (aEvent.target.getAttribute("closemenu") == "none" || aEvent.target.getAttribute("widget-type") == "view") { return; } // If we get here, we can actually hide the popup: this.hidePanelForNode(aEvent.target); },
--- a/browser/components/customizableui/src/CustomizableWidgets.jsm +++ b/browser/components/customizableui/src/CustomizableWidgets.jsm @@ -39,22 +39,22 @@ function setAttributes(aNode, aAttrs) { } else { if (name == "label" || name == "tooltiptext") value = CustomizableUI.getLocalizedProperty({id: aAttrs.id}, name); aNode.setAttribute(name, value); } } } -function updateCombinedWidgetStyle(aNode, aArea, aModifyAutoclose) { +function updateCombinedWidgetStyle(aNode, aArea, aModifyCloseMenu) { let inPanel = (aArea == CustomizableUI.AREA_PANEL); let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1"; let attrs = {class: cls}; - if (aModifyAutoclose) { - attrs.noautoclose = inPanel ? true : null; + if (aModifyCloseMenu) { + attrs.closemenu = inPanel ? "none" : null; } for (let i = 0, l = aNode.childNodes.length; i < l; ++i) { if (aNode.childNodes[i].localName == "separator") continue; setAttributes(aNode.childNodes[i], attrs); } } @@ -306,38 +306,38 @@ const CustomizableWidgets = [{ id: "zoom-controls", type: "custom", defaultArea: CustomizableUI.AREA_PANEL, onBuild: function(aDocument) { const kPanelId = "PanelUI-popup"; let areaType = CustomizableUI.getAreaType(this.currentArea); let inPanel = areaType == CustomizableUI.TYPE_MENU_PANEL; let inToolbar = areaType == CustomizableUI.TYPE_TOOLBAR; - let noautoclose = inPanel ? "true" : null; + let closeMenu = inPanel ? "none" : null; let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1"; if (!this.currentArea) cls = null; let buttons = [{ id: "zoom-out-button", - noautoclose: noautoclose, + closemenu: closeMenu, command: "cmd_fullZoomReduce", class: cls, label: true, tooltiptext: true }, { id: "zoom-reset-button", - noautoclose: noautoclose, + closemenu: closeMenu, command: "cmd_fullZoomReset", class: cls, tooltiptext: true }, { id: "zoom-in-button", - noautoclose: noautoclose, + closemenu: closeMenu, command: "cmd_fullZoomEnlarge", class: cls, label: true, tooltiptext: true }]; let node = aDocument.createElementNS(kNSXUL, "toolbaritem"); node.setAttribute("id", "zoom-controls");
--- a/browser/components/customizableui/src/CustomizeMode.jsm +++ b/browser/components/customizableui/src/CustomizeMode.jsm @@ -43,16 +43,18 @@ function CustomizeMode(aWindow) { this.document = aWindow.document; this.browser = aWindow.gBrowser; // There are two palettes - there's the palette that can be overlayed with // toolbar items in browser.xul. This is invisible, and never seen by the // user. Then there's the visible palette, which gets populated and displayed // to the user when in customizing mode. this.visiblePalette = this.document.getElementById(kPaletteId); + this.paletteEmptyNotice = this.document.getElementById("customization-empty"); + this.paletteSpacer = this.document.getElementById("customization-spacer"); }; CustomizeMode.prototype = { _changed: false, _transitioning: false, window: null, document: null, // areas is used to cache the customizable areas when in customization mode. @@ -223,16 +225,18 @@ CustomizeMode.prototype = { CustomizableUI.addListener(this); window.PanelUI.endBatchUpdate(); this._customizing = true; this._transitioning = false; // Show the palette now that the transition has finished. this.visiblePalette.hidden = false; + this.paletteSpacer.hidden = true; + this._updateEmptyPaletteNotice(); this._handler.isEnteringCustomizeMode = false; this.dispatchToolboxEvent("customizationready"); if (!this._wantToBeInCustomizeMode) { this.exit(); } }.bind(this)).then(null, function(e) { ERROR(e); @@ -268,17 +272,19 @@ CustomizeMode.prototype = { this._removePanelCustomizationPlaceholders(); let window = this.window; let document = this.document; let documentElement = document.documentElement; // Hide the palette before starting the transition for increased perf. + this.paletteSpacer.hidden = false; this.visiblePalette.hidden = true; + this.paletteEmptyNotice.hidden = true; this._transitioning = true; Task.spawn(function() { yield this.depopulatePalette(); yield this._doTransition(false); @@ -908,19 +914,25 @@ CustomizeMode.prototype = { this.visiblePalette.appendChild(this.makePaletteItem(widget, "palette")); } } }, _onUIChange: function() { this._changed = true; this._updateResetButton(); + this._updateEmptyPaletteNotice(); this.dispatchToolboxEvent("customizationchange"); }, + _updateEmptyPaletteNotice: function() { + let paletteItems = this.visiblePalette.getElementsByTagName("toolbarpaletteitem"); + this.paletteEmptyNotice.hidden = !!paletteItems.length; + }, + _updateResetButton: function() { let btn = this.document.getElementById("customization-reset-button"); btn.disabled = CustomizableUI.inDefaultState; }, handleEvent: function(aEvent) { switch(aEvent.type) { case "toolbarvisibilitychange":
--- a/browser/components/customizableui/test/browser.ini +++ b/browser/components/customizableui/test/browser.ini @@ -32,16 +32,17 @@ skip-if = os == "mac" # Because of the specific widths, this test is fragile and has been disabled. # NB: it was designed for mac only, but started randomly failing there. skip-if = true [browser_914863_disabled_help_quit_buttons.js] [browser_918049_skipintoolbarset_dnd.js] [browser_923857_customize_mode_event_wrapping_during_reset.js] [browser_927717_customize_drag_empty_toolbar.js] +[browser_932928_show_notice_when_palette_empty.js] [browser_934113_menubar_removable.js] # Because this test is about the menubar, it can't be run on mac skip-if = os == "mac" [browser_946320_tabs_from_other_computers.js] skip-if = os == "linux"
new file mode 100644 --- /dev/null +++ b/browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js @@ -0,0 +1,35 @@ +/* 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/. */ + +"use strict"; + +// There should be an advert to get more addons when the palette is empty. +add_task(function() { + yield startCustomizing(); + let visiblePalette = document.getElementById("customization-palette"); + let emptyPaletteNotice = document.getElementById("customization-empty"); + is(emptyPaletteNotice.hidden, true, "The empty palette notice should not be shown when there are items in the palette."); + + while (visiblePalette.childElementCount) { + gCustomizeMode.addToToolbar(visiblePalette.children[0]); + } + is(visiblePalette.childElementCount, 0, "There shouldn't be any items remaining in the visible palette."); + is(emptyPaletteNotice.hidden, false, "The empty palette notice should be shown when there are no items in the palette."); + + yield endCustomizing(); + yield startCustomizing(); + visiblePalette = document.getElementById("customization-palette"); + emptyPaletteNotice = document.getElementById("customization-empty"); + is(emptyPaletteNotice.hidden, false, + "The empty palette notice should be shown when there are no items in the palette and cust. mode is re-entered."); + + gCustomizeMode.removeFromArea(document.getElementById("wrapper-home-button")); + is(emptyPaletteNotice.hidden, true, + "The empty palette notice should not be shown when there is at least one item in the palette."); +}); + +add_task(function asyncCleanup() { + yield endCustomizing(); + yield resetCustomization(); +});
--- a/browser/devtools/scratchpad/test/browser_scratchpad_wrong_window_focus.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_wrong_window_focus.js @@ -1,13 +1,14 @@ /* vim:set ts=2 sw=2 sts=2 et: */ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /* Bug 661762 */ + function test() { waitForExplicitFinish(); // To test for this bug we open a Scratchpad window, save its // reference and then open another one. This way the first window // loses its focus. // @@ -20,32 +21,25 @@ function test() // is currently active (it should be the older one). gBrowser.selectedTab = gBrowser.addTab(); gBrowser.selectedBrowser.addEventListener("load", function onLoad() { gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); openScratchpad(function () { let sw = gScratchpadWindow; + let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); openScratchpad(function () { - function onWebConsoleOpen(subj) { - Services.obs.removeObserver(onWebConsoleOpen, - "web-console-created"); - subj.QueryInterface(Ci.nsISupportsString); - - let hud = HUDService.getHudReferenceById(subj.data); + let target = devtools.TargetFactory.forTab(gBrowser.selectedTab); + gDevTools.showToolbox(target, "webconsole").then((toolbox) => { + let hud = toolbox.getCurrentPanel().hud; hud.jsterm.clearOutput(true); - executeSoon(testFocus.bind(null, sw, hud)); - } - - Services.obs. - addObserver(onWebConsoleOpen, "web-console-created", false); - - HUDService.toggleWebConsole(); + testFocus(sw, hud); + }); }); }); }, true); content.location = "data:text/html;charset=utf8,<p>test window focus for Scratchpad."; } function testFocus(sw, hud) {
--- a/browser/devtools/webconsole/hudservice.js +++ b/browser/devtools/webconsole/hudservice.js @@ -138,34 +138,16 @@ HUD_SERVICE.prototype = * @returns Object */ getHudReferenceById: function HS_getHudReferenceById(aId) { return this.consoles.get(aId); }, /** - * Toggle the Web Console for the current tab. - * - * @return object - * A promise for either the opening of the toolbox that holds the Web - * Console, or a Promise for the closing of the toolbox. - */ - toggleWebConsole: function HS_toggleWebConsole() - { - let window = this.currentContext(); - let target = devtools.TargetFactory.forTab(window.gBrowser.selectedTab); - let toolbox = gDevTools.getToolbox(target); - - return toolbox && toolbox.currentToolId == "webconsole" ? - toolbox.destroy() : - gDevTools.showToolbox(target, "webconsole"); - }, - - /** * Find if there is a Web Console open for the current tab and return the * instance. * @return object|null * The WebConsole object or null if the active tab has no open Web * Console. */ getOpenWebConsole: function HS_getOpenWebConsole() { @@ -739,17 +721,17 @@ BrowserConsole.prototype = Heritage.exte return this._bc_destroyer.promise; }, }); const HUDService = new HUD_SERVICE(); (() => { - let methods = ["openWebConsole", "openBrowserConsole", "toggleWebConsole", + let methods = ["openWebConsole", "openBrowserConsole", "toggleBrowserConsole", "getOpenWebConsole", "getBrowserConsole", "getHudByWindow", "getHudReferenceById"]; for (let method of methods) { exports[method] = HUDService[method].bind(HUDService); } exports.consoles = HUDService.consoles; exports.lastFinishedRequest = HUDService.lastFinishedRequest;
--- a/browser/devtools/webconsole/test/browser.ini +++ b/browser/devtools/webconsole/test/browser.ini @@ -110,16 +110,17 @@ support-files = [browser_bug_865288_repeat_different_objects.js] [browser_bug_865871_variables_view_close_on_esc_key.js] [browser_bug_869003_inspect_cross_domain_object.js] [browser_bug_871156_ctrlw_close_tab.js] [browser_cached_messages.js] [browser_console.js] [browser_console_addonsdk_loader_exception.js] [browser_console_clear_on_reload.js] +[browser_console_click_focus.js] [browser_console_consolejsm_output.js] [browser_console_dead_objects.js] [browser_console_error_source_click.js] [browser_console_filters.js] [browser_console_iframe_messages.js] [browser_console_keyboard_accessibility.js] [browser_console_log_inspectable_object.js] [browser_console_native_getters.js]
new file mode 100644 --- /dev/null +++ b/browser/devtools/webconsole/test/browser_console_click_focus.js @@ -0,0 +1,39 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests that the input field is focused when the console is opened. + +const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"; + +function test() { + addTab(TEST_URI); + browser.addEventListener("DOMContentLoaded", testInputFocus, false); +} + +function testInputFocus() { + browser.removeEventListener("DOMContentLoaded", testInputFocus, false); + + openConsole().then((hud) => { + let inputNode = hud.jsterm.inputNode; + ok(inputNode.getAttribute("focused"), "input node is focused"); + + let lostFocus = () => { + inputNode.removeEventListener("blur", lostFocus); + info("input node lost focus"); + } + + inputNode.addEventListener("blur", lostFocus); + + browser.ownerDocument.getElementById("urlbar").click(); + + ok(!inputNode.getAttribute("focused"), "input node is not focused"); + + hud.outputNode.click(); + + ok(inputNode.getAttribute("focused"), "input node is focused"); + + finishTest(); + }); +}
--- a/browser/devtools/webconsole/webconsole.js +++ b/browser/devtools/webconsole/webconsole.js @@ -564,16 +564,29 @@ WebConsoleFrame.prototype = { this.jsterm.init(); this.jsterm.inputNode.focus(); let toolbox = gDevTools.getToolbox(this.owner.target); if (toolbox) { toolbox.on("webconsole-selected", this._onPanelSelected); } + /* + * Focus input line whenever the output area is clicked. + * Only focus when the target node (or parent, as in source links) is + * not an anchor. + */ + this.outputNode.addEventListener("click", (e) => { + if ((e.button == 0) && + (e.target.nodeName.toLowerCase() != "a") && + (e.target.parentNode.nodeName.toLowerCase() != "a")) { + this.jsterm.inputNode.focus(); + } + }); + // Toggle the timestamp on preference change gDevTools.on("pref-changed", this._onToolboxPrefChanged); this._onToolboxPrefChanged("pref-changed", { pref: PREF_MESSAGE_TIMESTAMP, newValue: Services.prefs.getBoolPref(PREF_MESSAGE_TIMESTAMP), }); },
--- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -672,16 +672,18 @@ just addresses the organization to follo <!ENTITY social.learnMore.accesskey "l"> <!ENTITY social.closeNotificationItem.label "Not Now"> <!ENTITY customizeMode.tabTitle "Customize &brandShortName;"> <!ENTITY customizeMode.menuAndToolbars.label "Menu and toolbars"> <!ENTITY customizeMode.menuAndToolbars.header "More Tools to Add to the Menu and Toolbar"> +<!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?"> +<!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons"> <!ENTITY customizeMode.restoreDefaults "Restore Defaults"> <!ENTITY customizeMode.toolbars "Show / Hide Toolbars"> <!ENTITY social.chatBar.commandkey "c"> <!ENTITY social.chatBar.label "Focus chats"> <!ENTITY social.chatBar.accesskey "c"> <!ENTITY social.markpageMenu.accesskey "P">
--- a/browser/metro/base/content/Util.js +++ b/browser/metro/base/content/Util.js @@ -78,40 +78,54 @@ let Util = { }, isTextInput: function isTextInput(aElement) { return ((aElement instanceof Ci.nsIDOMHTMLInputElement && aElement.mozIsTextField(false)) || aElement instanceof Ci.nsIDOMHTMLTextAreaElement); }, + /** + * Checks whether aElement's content can be edited either if it(or any of its + * parents) has "contenteditable" attribute set to "true" or aElement's + * ownerDocument is in design mode. + */ isEditableContent: function isEditableContent(aElement) { - if (!aElement) - return false; - if (aElement.isContentEditable || aElement.designMode == "on") - return true; - return false; + return !!aElement && (aElement.isContentEditable || + this.isOwnerDocumentInDesignMode(aElement)); + }, isEditable: function isEditable(aElement) { - if (!aElement) + if (!aElement) { return false; - if (this.isTextInput(aElement) || this.isEditableContent(aElement)) + } + + if (this.isTextInput(aElement) || this.isEditableContent(aElement)) { return true; + } // If a body element is editable and the body is the child of an // iframe or div we can assume this is an advanced HTML editor if ((aElement instanceof Ci.nsIDOMHTMLIFrameElement || aElement instanceof Ci.nsIDOMHTMLDivElement) && aElement.contentDocument && this.isEditableContent(aElement.contentDocument.body)) { return true; } - return aElement.ownerDocument && aElement.ownerDocument.designMode == "on"; + return false; + }, + + /** + * Checks whether aElement's owner document has design mode turned on. + */ + isOwnerDocumentInDesignMode: function(aElement) { + return !!aElement && !!aElement.ownerDocument && + aElement.ownerDocument.designMode == "on"; }, isMultilineInput: function isMultilineInput(aElement) { return (aElement instanceof Ci.nsIDOMHTMLTextAreaElement); }, isLink: function isLink(aElement) { return ((aElement instanceof Ci.nsIDOMHTMLAnchorElement && aElement.href) ||
--- a/browser/metro/base/content/contenthandlers/ContextMenuHandler.js +++ b/browser/metro/base/content/contenthandlers/ContextMenuHandler.js @@ -100,33 +100,35 @@ var ContextMenuHandler = { /****************************************************** * ContextCommand handlers */ _onSelectAll: function _onSelectAll() { if (Util.isTextInput(this._target)) { // select all text in the input control this._target.select(); + } else if (Util.isEditableContent(this._target)) { + this._target.ownerDocument.execCommand("selectAll", false); } else { // select the entire document content.getSelection().selectAllChildren(content.document); } this.reset(); }, _onPaste: function _onPaste() { // paste text if this is an input control if (Util.isTextInput(this._target)) { let edit = this._target.QueryInterface(Ci.nsIDOMNSEditableElement); if (edit) { edit.editor.paste(Ci.nsIClipboard.kGlobalClipboard); } else { Util.dumpLn("error: target element does not support nsIDOMNSEditableElement"); } - } else if (this._target.isContentEditable) { + } else if (Util.isEditableContent(this._target)) { try { this._target.ownerDocument.execCommand("paste", false, Ci.nsIClipboard.kGlobalClipboard); } catch (ex) { dump("ContextMenuHandler: exception pasting into contentEditable: " + ex.message + "\n"); } } @@ -140,17 +142,17 @@ var ContextMenuHandler = { _onCut: function _onCut() { if (Util.isTextInput(this._target)) { let edit = this._target.QueryInterface(Ci.nsIDOMNSEditableElement); if (edit) { edit.editor.cut(); } else { Util.dumpLn("error: target element does not support nsIDOMNSEditableElement"); } - } else if (this._target.isContentEditable) { + } else if (Util.isEditableContent(this._target)) { try { this._target.ownerDocument.execCommand("cut", false); } catch (ex) { dump("ContextMenuHandler: exception cutting from contentEditable: " + ex.message + "\n"); } } this.reset(); }, @@ -254,17 +256,19 @@ var ContextMenuHandler = { linkUrl = state.linkURL; state.linkTitle = popupNode.textContent || popupNode.title; state.linkProtocol = this._getProtocol(this._getURI(state.linkURL)); // mark as text so we can pickup on selection below isText = true; break; } // is the target contentEditable (not just inheriting contentEditable) - else if (elem.contentEditable == "true") { + // or the entire document in designer mode. + else if (elem.contentEditable == "true" || + Util.isOwnerDocumentInDesignMode(elem)) { this._target = elem; isEditableText = true; isText = true; uniqueStateTypes.add("input-text"); if (elem.textContent.length) { uniqueStateTypes.add("selectable"); } else {
--- a/browser/metro/base/tests/mochitest/browser_context_menu_tests.js +++ b/browser/metro/base/tests/mochitest/browser_context_menu_tests.js @@ -704,12 +704,90 @@ gTests.push({ gTests.push({ desc: "bug 856264 - touch - context menu should reopen on other links", setUp: reopenSetUp, tearDown: reopenTearDown, run: getReopenTest(sendContextMenuClickToElement, sendTap) }); +gTests.push({ + desc: "Bug 947505 - Right-click in a designMode document should display a " + + "context menu", + run: function test() { + info(chromeRoot + "browser_context_menu_tests_02.html"); + yield addTab(chromeRoot + "browser_context_menu_tests_02.html"); + + purgeEventQueue(); + emptyClipboard(); + ContextUI.dismiss(); + + yield waitForCondition(() => !ContextUI.navbarVisible); + + let tabWindow = Browser.selectedTab.browser.contentWindow; + let testSpan = tabWindow.document.getElementById("text1"); + + // Case #1: Document isn't in design mode and nothing is selected. + tabWindow.document.designMode = "off"; + + // Simulate right mouse click to reproduce the same step as noted in the + // appropriate bug. It's valid for non-touch case only. + synthesizeNativeMouseRDown(Browser.selectedTab.browser, 10, 10); + synthesizeNativeMouseRUp(Browser.selectedTab.browser, 10, 10); + + yield waitForCondition(() => ContextUI.navbarVisible); + + ok(ContextUI.navbarVisible, "Navbar is visible on context menu action."); + ok(ContextUI.tabbarVisible, "Tabbar is visible on context menu action."); + + ContextUI.dismiss(); + yield waitForCondition(() => !ContextUI.navbarVisible); + + // Case #2: Document isn't in design mode and text is selected. + tabWindow.getSelection().selectAllChildren(testSpan); + + let promise = waitForEvent(tabWindow.document, "popupshown"); + sendContextMenuClickToSelection(tabWindow); + yield promise; + + checkContextUIMenuItemVisibility(["context-copy", "context-search"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + + // Case #3: Document is in design mode and nothing is selected. + tabWindow.document.designMode = "on"; + tabWindow.getSelection().removeAllRanges(); + + promise = waitForEvent(tabWindow.document, "popupshown"); + sendContextMenuClickToElement(tabWindow, testSpan); + yield promise; + + checkContextUIMenuItemVisibility(["context-select-all", "context-select"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + + // Case #4: Document is in design mode and text is selected. + tabWindow.getSelection().selectAllChildren(testSpan); + + promise = waitForEvent(tabWindow.document, "popupshown"); + sendContextMenuClickToSelection(tabWindow); + yield promise; + + checkContextUIMenuItemVisibility(["context-cut", "context-copy", + "context-select-all", "context-select", + "context-search"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + + Browser.closeTab(Browser.selectedTab, { forceClose: true }); + } +}); + function test() { setDevPixelEqualToPx(); runTests(); }
--- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -3955,17 +3955,17 @@ window > chatbox { border-bottom-left-radius: @toolbarbuttonCornerRadius@; border-bottom-right-radius: @toolbarbuttonCornerRadius@; } /* Customization mode */ %include ../shared/customizableui/customizeMode.inc.css -#main-window[customizing] #titlebar { +#main-window[customize-entered] #titlebar { padding-top: 0; } #main-window:-moz-any([customize-entering],[customize-entered]) #tab-view-deck { padding: 0 2em 2em; } #main-window[customize-entered] #tab-view-deck {
--- a/dom/camera/CameraControlImpl.cpp +++ b/dom/camera/CameraControlImpl.cpp @@ -4,16 +4,17 @@ #include "base/basictypes.h" #include "mozilla/Assertions.h" #include "DOMCameraPreview.h" #include "CameraRecorderProfiles.h" #include "CameraControlImpl.h" #include "CameraCommon.h" #include "nsGlobalWindow.h" +#include "DeviceStorageFileDescriptor.h" using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::idl; CameraControlImpl::CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread, uint64_t aWindowId) : mCameraId(aCameraId) , mCameraThread(aCameraThread) @@ -445,22 +446,19 @@ CameraControlImpl::TakePicture(const Cam cancel = true; } nsCOMPtr<nsIRunnable> takePictureTask = new TakePictureTask(this, cancel, aSize, aRotation, aFileFormat, aPosition, aDateTime, onSuccess, onError); return mCameraThread->Dispatch(takePictureTask, NS_DISPATCH_NORMAL); } nsresult -CameraControlImpl::StartRecording(CameraStartRecordingOptions* aOptions, nsIFile* aFolder, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) +CameraControlImpl::StartRecording(CameraStartRecordingOptions* aOptions, DeviceStorageFileDescriptor* aFileDescriptor, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) { - nsCOMPtr<nsIFile> clone; - aFolder->Clone(getter_AddRefs(clone)); - - nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, *aOptions, clone, aFilename, onSuccess, onError, mWindowId); + nsCOMPtr<nsIRunnable> startRecordingTask = new StartRecordingTask(this, *aOptions, aFileDescriptor, onSuccess, onError, mWindowId); return mCameraThread->Dispatch(startRecordingTask, NS_DISPATCH_NORMAL); } nsresult CameraControlImpl::StopRecording() { nsCOMPtr<nsIRunnable> stopRecordingTask = new StopRecordingTask(this); return mCameraThread->Dispatch(stopRecordingTask, NS_DISPATCH_NORMAL);
--- a/dom/camera/CameraControlImpl.h +++ b/dom/camera/CameraControlImpl.h @@ -9,16 +9,20 @@ #include "nsDOMFile.h" #include "nsProxyRelease.h" #include "DictionaryHelpers.h" #include "nsIDOMDeviceStorage.h" #include "DOMCameraManager.h" #include "DOMCameraPreview.h" #include "ICameraControl.h" #include "CameraCommon.h" +#include "DeviceStorage.h" +#include "DeviceStorageFileDescriptor.h" + +class DeviceStorageFileDescriptor; namespace mozilla { class GetPreviewStreamTask; class StartPreviewTask; class StopPreviewTask; class AutoFocusTask; class TakePictureTask; @@ -49,17 +53,17 @@ class CameraControlImpl : public ICamera public: CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread, uint64_t aWindowId); nsresult GetPreviewStream(idl::CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError); nsresult StartPreview(DOMCameraPreview* aDOMPreview); void StopPreview(); nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError); nsresult TakePicture(const idl::CameraSize& aSize, int32_t aRotation, const nsAString& aFileFormat, idl::CameraPosition aPosition, uint64_t aDateTime, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError); - nsresult StartRecording(idl::CameraStartRecordingOptions* aOptions, nsIFile* aFolder, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError); + nsresult StartRecording(idl::CameraStartRecordingOptions* aOptions, DeviceStorageFileDescriptor *aDSFileDescriptor, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError); nsresult StopRecording(); nsresult GetPreviewStreamVideoMode(idl::CameraRecorderOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError); nsresult ReleaseHardware(nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError); nsresult Set(uint32_t aKey, const nsAString& aValue); nsresult Get(uint32_t aKey, nsAString& aValue); nsresult Set(uint32_t aKey, double aValue); nsresult Get(uint32_t aKey, double* aValue); @@ -447,21 +451,25 @@ protected: nsMainThreadPtrHandle<nsICameraStartRecordingCallback> mOnSuccessCb; uint64_t mWindowId; }; // Start video recording. class StartRecordingTask : public nsRunnable { public: - StartRecordingTask(CameraControlImpl* aCameraControl, idl::CameraStartRecordingOptions aOptions, nsIFile* aFolder, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId) + StartRecordingTask(CameraControlImpl* aCameraControl, + idl::CameraStartRecordingOptions aOptions, + DeviceStorageFileDescriptor *aDSFileDescriptor, + nsICameraStartRecordingCallback* onSuccess, + nsICameraErrorCallback* onError, + uint64_t aWindowId) : mCameraControl(aCameraControl) , mOptions(aOptions) - , mFolder(aFolder) - , mFilename(aFilename) + , mDSFileDescriptor(aDSFileDescriptor) , mOnSuccessCb(new nsMainThreadPtrHolder<nsICameraStartRecordingCallback>(onSuccess)) , mOnErrorCb(new nsMainThreadPtrHolder<nsICameraErrorCallback>(onError)) , mWindowId(aWindowId) { DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); } virtual ~StartRecordingTask() @@ -486,18 +494,17 @@ public: if (NS_FAILED(rv)) { DOM_CAMERA_LOGE("Failed to dispatch start recording result to main thread (%d)!", rv); } return rv; } nsRefPtr<CameraControlImpl> mCameraControl; idl::CameraStartRecordingOptions mOptions; - nsCOMPtr<nsIFile> mFolder; - nsString mFilename; + nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; nsMainThreadPtrHandle<nsICameraStartRecordingCallback> mOnSuccessCb; nsMainThreadPtrHandle<nsICameraErrorCallback> mOnErrorCb; uint64_t mWindowId; }; // Stop video recording. class StopRecordingTask : public nsRunnable {
--- a/dom/camera/DOMCameraControl.cpp +++ b/dom/camera/DOMCameraControl.cpp @@ -3,16 +3,17 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "base/basictypes.h" #include "nsCOMPtr.h" #include "nsDOMClassInfo.h" #include "nsHashPropertyBag.h" #include "nsThread.h" #include "DeviceStorage.h" +#include "DeviceStorageFileDescriptor.h" #include "mozilla/dom/CameraControlBinding.h" #include "mozilla/dom/TabChild.h" #include "mozilla/MediaManager.h" #include "mozilla/Services.h" #include "mozilla/unused.h" #include "nsIAppsService.h" #include "nsIObserverService.h" #include "nsIDOMDeviceStorage.h" @@ -344,23 +345,22 @@ nsDOMCameraControl::StartRecording(JSCon JS::Handle<JS::Value> aOptions, nsDOMDeviceStorage& storageArea, const nsAString& filename, nsICameraStartRecordingCallback* onSuccess, const Optional<nsICameraErrorCallback*>& onError, ErrorResult& aRv) { MOZ_ASSERT(onSuccess, "no onSuccess handler passed"); - mozilla::idl::CameraStartRecordingOptions options; // Default values, until the dictionary parser can handle them. - options.rotation = 0; - options.maxFileSizeBytes = 0; - options.maxVideoLengthMs = 0; - aRv = options.Init(aCx, aOptions.address()); + mOptions.rotation = 0; + mOptions.maxFileSizeBytes = 0; + mOptions.maxVideoLengthMs = 0; + aRv = mOptions.Init(aCx, aOptions.address()); if (aRv.Failed()) { return; } aRv = NotifyRecordingStatusChange(NS_LITERAL_STRING("starting")); #ifdef MOZ_B2G if (!mAudioChannelAgent) { @@ -370,23 +370,63 @@ nsDOMCameraControl::StartRecording(JSCon mAudioChannelAgent->Init(AUDIO_CHANNEL_CONTENT, nullptr); // Video recording doesn't output any sound, so it's not necessary to check canPlay. int32_t canPlay; mAudioChannelAgent->StartPlaying(&canPlay); } } #endif - nsCOMPtr<nsIFile> folder; - aRv = storageArea.GetRootDirectoryForFile(filename, getter_AddRefs(folder)); + nsCOMPtr<nsIDOMDOMRequest> request; + mDSFileDescriptor = new DeviceStorageFileDescriptor(); + aRv = storageArea.CreateFileDescriptor(filename, mDSFileDescriptor.get(), + getter_AddRefs(request)); if (aRv.Failed()) { return; } - aRv = mCameraControl->StartRecording(&options, folder, filename, onSuccess, - onError.WasPassed() ? onError.Value() : nullptr); + + mOnSuccessCb = onSuccess; + mOnErrorCb = onError.WasPassed() ? onError.Value() : nullptr; + + request->AddEventListener(NS_LITERAL_STRING("success"), this, false); + request->AddEventListener(NS_LITERAL_STRING("error"), this, false); +} + +NS_IMETHODIMP +nsDOMCameraControl::HandleEvent(nsIDOMEvent* aEvent) +{ + nsString eventType; + aEvent->GetType(eventType); + ErrorResult rv; + + if ((eventType.EqualsLiteral("success")) && + mDSFileDescriptor->mFileDescriptor.IsValid()) { + + rv = mCameraControl->StartRecording(&mOptions, + mDSFileDescriptor.get(), + mOnSuccessCb.get(), + mOnErrorCb.get()); + if (!rv.Failed()) { + return rv.ErrorCode(); + } + + // An error happened. Fall through and call the error callback. + } + + // We're already be on the main thread, so go ahead and call the + // error callback directly. + + MOZ_ASSERT(NS_IsMainThread()); + + if (mOnErrorCb && + nsDOMCameraManager::IsWindowStillActive(mWindow->WindowID())) { + mOnErrorCb->HandleEvent(NS_LITERAL_STRING("FAILURE")); + } + + return NS_OK; } void nsDOMCameraControl::StopRecording(ErrorResult& aRv) { aRv = NotifyRecordingStatusChange(NS_LITERAL_STRING("shutdown")); #ifdef MOZ_B2G
--- a/dom/camera/DOMCameraControl.h +++ b/dom/camera/DOMCameraControl.h @@ -3,41 +3,44 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef DOM_CAMERA_DOMCAMERACONTROL_H #define DOM_CAMERA_DOMCAMERACONTROL_H #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" +#include "nsIDOMEventListener.h" #include "DictionaryHelpers.h" #include "ICameraControl.h" #include "DOMCameraPreview.h" #include "nsIDOMCameraManager.h" #include "CameraCommon.h" #include "AudioChannelAgent.h" #include "nsProxyRelease.h" #include "nsHashPropertyBag.h" +#include "DeviceStorage.h" class nsDOMDeviceStorage; class nsPIDOMWindow; namespace mozilla { namespace dom { class CameraPictureOptions; template<typename T> class Optional; } class ErrorResult; // Main camera control. -class nsDOMCameraControl MOZ_FINAL : public nsISupports, +class nsDOMCameraControl MOZ_FINAL : public nsIDOMEventListener, public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_NSIDOMEVENTLISTENER NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCameraControl) nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsPIDOMWindow* aWindow); nsresult Result(nsresult aResult, const nsMainThreadPtrHandle<nsICameraGetCameraCallback>& onSuccess, const nsMainThreadPtrHandle<nsICameraErrorCallback>& onError, @@ -102,16 +105,21 @@ protected: private: nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE; nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE; nsresult NotifyRecordingStatusChange(const nsString& aMsg); + mozilla::idl::CameraStartRecordingOptions mOptions; + nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; + nsCOMPtr<nsICameraStartRecordingCallback> mOnSuccessCb; + nsCOMPtr<nsICameraErrorCallback> mOnErrorCb; + protected: /* additional members */ nsRefPtr<ICameraControl> mCameraControl; // non-DOM camera control nsCOMPtr<nsICameraCapabilities> mDOMCapabilities; // An agent used to join audio channel service. nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent; nsCOMPtr<nsPIDOMWindow> mWindow; };
--- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -37,16 +37,17 @@ #include "nsIVolumeService.h" #include "DOMCameraManager.h" #include "GonkCameraHwMgr.h" #include "DOMCameraCapabilities.h" #include "DOMCameraControl.h" #include "GonkRecorderProfiles.h" #include "GonkCameraControl.h" #include "CameraCommon.h" +#include "DeviceStorageFileDescriptor.h" using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::layers; using namespace android; using mozilla::gfx::IntSize; /** @@ -1018,17 +1019,17 @@ nsGonkCameraControl::TakePictureImpl(Tak SetParameter(CameraParameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aTakePicture->mPosition.timestamp).get()); } // Add the non-GPS timestamp. The EXIF date/time field is formatted as // "YYYY:MM:DD HH:MM:SS", without room for a time-zone; as such, the time // is meant to be stored as a local time. Since we are given seconds from // Epoch GMT, we use localtime_r() to handle the conversion. time_t time = aTakePicture->mDateTime; - if (time != aTakePicture->mDateTime) { + if ((uint64_t)time != aTakePicture->mDateTime) { DOM_CAMERA_LOGE("picture date/time '%llu' is too far in the future\n", aTakePicture->mDateTime); } else { struct tm t; if (localtime_r(&time, &t)) { char dateTime[20]; if (strftime(dateTime, sizeof(dateTime), "%Y:%m:%d %T", &t)) { DOM_CAMERA_LOGI("setting picture date/time to %s\n", dateTime); // Not every platform defines a CameraParameters::KEY_EXIF_DATETIME; @@ -1092,52 +1093,34 @@ nsGonkCameraControl::StartRecordingImpl( /** * Get the base path from device storage and append the app-specified * filename to it. The filename may include a relative subpath * (e.g.) "DCIM/IMG_0001.jpg". * * The camera app needs to provide the file extension '.3gp' for now. * See bug 795202. */ - nsCOMPtr<nsIFile> filename = aStartRecording->mFolder; - filename->AppendRelativePath(aStartRecording->mFilename); - - nsString fullpath; - filename->GetPath(fullpath); - - nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); - NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE); - - nsCOMPtr<nsIVolume> vol; - nsresult rv = vs->GetVolumeByPath(fullpath, getter_AddRefs(vol)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG); - - nsString volName; - vol->GetName(volName); - - mVideoFile = new DeviceStorageFile(NS_LITERAL_STRING("videos"), - volName, - aStartRecording->mFilename); - - nsAutoCString nativeFilename; - filename->GetNativePath(nativeFilename); - DOM_CAMERA_LOGI("Video filename is '%s'\n", nativeFilename.get()); + nsRefPtr<DeviceStorageFileDescriptor> dsfd = aStartRecording->mDSFileDescriptor; + NS_ENSURE_TRUE(dsfd, NS_ERROR_FAILURE); + nsAutoString fullPath; + mVideoFile = dsfd->mDSFile; + mVideoFile->GetFullPath(fullPath); + DOM_CAMERA_LOGI("Video filename is '%s'\n", + NS_LossyConvertUTF16toASCII(fullPath).get()); if (!mVideoFile->IsSafePath()) { DOM_CAMERA_LOGE("Invalid video file name\n"); return NS_ERROR_INVALID_ARG; } - ScopedClose fd(open(nativeFilename.get(), O_RDWR | O_CREAT, 0644)); - if (fd < 0) { - DOM_CAMERA_LOGE("Couldn't create file '%s': (%d) %s\n", nativeFilename.get(), errno, strerror(errno)); - return NS_ERROR_FAILURE; - } - - rv = SetupRecording(fd, aStartRecording->mOptions.rotation, aStartRecording->mOptions.maxFileSizeBytes, aStartRecording->mOptions.maxVideoLengthMs); + nsresult rv; + rv = SetupRecording(dsfd->mFileDescriptor.PlatformHandle(), + aStartRecording->mOptions.rotation, + aStartRecording->mOptions.maxFileSizeBytes, + aStartRecording->mOptions.maxVideoLengthMs); NS_ENSURE_SUCCESS(rv, rv); if (mRecorder->start() != OK) { DOM_CAMERA_LOGE("mRecorder->start() failed\n"); // important: we MUST destroy the recorder if start() fails! mRecorder = nullptr; return NS_ERROR_FAILURE; }
--- a/dom/camera/ICameraControl.h +++ b/dom/camera/ICameraControl.h @@ -5,32 +5,34 @@ #ifndef DOM_CAMERA_ICAMERACONTROL_H #define DOM_CAMERA_ICAMERACONTROL_H #include "nsIFile.h" #include "nsIDOMCameraManager.h" #include "DictionaryHelpers.h" #include "CameraCommon.h" +class DeviceStorageFileDescriptor; + namespace mozilla { class DOMCameraPreview; class RecorderProfileManager; class ICameraControl { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ICameraControl) virtual nsresult GetPreviewStream(idl::CameraSize aSize, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0; virtual nsresult StartPreview(DOMCameraPreview* aDOMPreview) = 0; virtual void StopPreview() = 0; virtual nsresult AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError) = 0; virtual nsresult TakePicture(const idl::CameraSize& aSize, int32_t aRotation, const nsAString& aFileFormat, idl::CameraPosition aPosition, uint64_t aDateTime, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError) = 0; - virtual nsresult StartRecording(idl::CameraStartRecordingOptions* aOptions, nsIFile* aFolder, const nsAString& aFilename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) = 0; + virtual nsresult StartRecording(idl::CameraStartRecordingOptions* aOptions, DeviceStorageFileDescriptor *aFileDescriptor, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError) = 0; virtual nsresult StopRecording() = 0; virtual nsresult GetPreviewStreamVideoMode(idl::CameraRecorderOptions* aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError) = 0; virtual nsresult ReleaseHardware(nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError) = 0; virtual nsresult Set(uint32_t aKey, const nsAString& aValue) = 0; virtual nsresult Get(uint32_t aKey, nsAString& aValue) = 0; virtual nsresult Set(uint32_t aKey, double aValue) = 0; virtual nsresult Get(uint32_t aKey, double* aValue) = 0;
--- a/dom/devicestorage/DeviceStorage.h +++ b/dom/devicestorage/DeviceStorage.h @@ -9,33 +9,37 @@ #include "nsIDOMDeviceStorage.h" #include "nsIFile.h" #include "nsIPrincipal.h" #include "nsIObserver.h" #include "nsDOMEventTargetHelper.h" #include "mozilla/RefPtr.h" #include "mozilla/StaticPtr.h" -#include "DOMRequest.h" +#include "mozilla/dom/DOMRequest.h" #define DEVICESTORAGE_PICTURES "pictures" #define DEVICESTORAGE_VIDEOS "videos" #define DEVICESTORAGE_MUSIC "music" #define DEVICESTORAGE_APPS "apps" #define DEVICESTORAGE_SDCARD "sdcard" #define DEVICESTORAGE_CRASHES "crashes" +class DeviceStorageFile; class nsIInputStream; namespace mozilla { namespace dom { class DeviceStorageEnumerationParameters; class DOMCursor; class DOMRequest; } // namespace dom +namespace ipc { +class FileDescriptor; +} } // namespace mozilla class DeviceStorageFile MOZ_FINAL : public nsISupports { public: nsCOMPtr<nsIFile> mFile; nsString mStorageType; nsString mStorageName; @@ -97,16 +101,17 @@ public: void GetStatus(nsAString& aStatus); void DoFormat(nsAString& aStatus); static void GetRootDirectoryForType(const nsAString& aStorageType, const nsAString& aStorageName, nsIFile** aFile); nsresult CalculateSizeAndModifiedDate(); nsresult CalculateMimeType(); + nsresult CreateFileDescriptor(mozilla::ipc::FileDescriptor& aFileDescriptor); private: void Init(); void NormalizeFilePath(); void AppendRelativePath(const nsAString& aPath); void AccumDirectoryUsage(nsIFile* aFile, uint64_t* aPicturesSoFar, uint64_t* aVideosSoFar,
new file mode 100644 --- /dev/null +++ b/dom/devicestorage/DeviceStorageFileDescriptor.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DeviceStorageFileDescriptor_h +#define DeviceStorageFileDescriptor_h + +#include "mozilla/ipc/FileDescriptor.h" + +class DeviceStorageFileDescriptor MOZ_FINAL + : public mozilla::RefCounted<DeviceStorageFileDescriptor> +{ +public: + nsRefPtr<DeviceStorageFile> mDSFile; + mozilla::ipc::FileDescriptor mFileDescriptor; +}; + +#endif
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp +++ b/dom/devicestorage/DeviceStorageRequestChild.cpp @@ -1,35 +1,52 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DeviceStorageRequestChild.h" +#include "DeviceStorageFileDescriptor.h" #include "nsDeviceStorage.h" #include "nsDOMFile.h" #include "mozilla/dom/ipc/Blob.h" namespace mozilla { namespace dom { namespace devicestorage { DeviceStorageRequestChild::DeviceStorageRequestChild() : mCallback(nullptr) { MOZ_COUNT_CTOR(DeviceStorageRequestChild); } DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest, - DeviceStorageFile* aFile) + DeviceStorageFile* aDSFile) : mRequest(aRequest) - , mFile(aFile) + , mDSFile(aDSFile) , mCallback(nullptr) { + MOZ_ASSERT(aRequest); + MOZ_ASSERT(aDSFile); + MOZ_COUNT_CTOR(DeviceStorageRequestChild); +} + +DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest, + DeviceStorageFile* aDSFile, + DeviceStorageFileDescriptor* aDSFileDescriptor) + : mRequest(aRequest) + , mDSFile(aDSFile) + , mDSFileDescriptor(aDSFileDescriptor) + , mCallback(nullptr) +{ + MOZ_ASSERT(aRequest); + MOZ_ASSERT(aDSFile); + MOZ_ASSERT(aDSFileDescriptor); MOZ_COUNT_CTOR(DeviceStorageRequestChild); } DeviceStorageRequestChild::~DeviceStorageRequestChild() { MOZ_COUNT_DTOR(DeviceStorageRequestChild); } bool @@ -48,24 +65,40 @@ DeviceStorageRequestChild:: ErrorResponse r = aValue; mRequest->FireError(r.error()); break; } case DeviceStorageResponseValue::TSuccessResponse: { nsString fullPath; - mFile->GetFullPath(fullPath); + mDSFile->GetFullPath(fullPath); AutoJSContext cx; JS::Rooted<JS::Value> result(cx, StringToJsval(mRequest->GetOwner(), fullPath)); mRequest->FireSuccess(result); break; } + case DeviceStorageResponseValue::TFileDescriptorResponse: + { + FileDescriptorResponse r = aValue; + + nsString fullPath; + mDSFile->GetFullPath(fullPath); + AutoJSContext cx; + JS::Rooted<JS::Value> result(cx, + StringToJsval(mRequest->GetOwner(), fullPath)); + + mDSFileDescriptor->mDSFile = mDSFile; + mDSFileDescriptor->mFileDescriptor = r.fileDescriptor(); + mRequest->FireSuccess(result); + break; + } + case DeviceStorageResponseValue::TBlobResponse: { BlobResponse r = aValue; BlobChild* actor = static_cast<BlobChild*>(r.blobChild()); nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob(); nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob); AutoJSContext cx;
--- a/dom/devicestorage/DeviceStorageRequestChild.h +++ b/dom/devicestorage/DeviceStorageRequestChild.h @@ -2,44 +2,50 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_devicestorage_DeviceStorageRequestChild_h #define mozilla_dom_devicestorage_DeviceStorageRequestChild_h #include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h" -#include "DOMRequest.h" class DeviceStorageFile; +class DeviceStorageFileDescriptor; namespace mozilla { namespace dom { + +class DOMRequest; + namespace devicestorage { class DeviceStorageRequestChildCallback { public: virtual void RequestComplete() = 0; }; class DeviceStorageRequestChild : public PDeviceStorageRequestChild { public: DeviceStorageRequestChild(); DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile); + DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile, + DeviceStorageFileDescriptor* aFileDescrptor); ~DeviceStorageRequestChild(); void SetCallback(class DeviceStorageRequestChildCallback *aCallback); virtual bool Recv__delete__(const DeviceStorageResponseValue& value); private: nsRefPtr<DOMRequest> mRequest; - nsRefPtr<DeviceStorageFile> mFile; + nsRefPtr<DeviceStorageFile> mDSFile; + nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; DeviceStorageRequestChildCallback* mCallback; }; } // namespace devicestorage } // namespace dom } // namespace mozilla
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp +++ b/dom/devicestorage/DeviceStorageRequestParent.cpp @@ -24,17 +24,17 @@ DeviceStorageRequestParent::DeviceStorag : mParams(aParams) , mMutex("DeviceStorageRequestParent::mMutex") , mActorDestoryed(false) { MOZ_COUNT_CTOR(DeviceStorageRequestParent); DebugOnly<DeviceStorageUsedSpaceCache*> usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet(); - NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null"); + MOZ_ASSERT(usedSpaceCache); } void DeviceStorageRequestParent::Dispatch() { switch (mParams.type()) { case DeviceStorageParams::TDeviceStorageAddParams: { @@ -48,71 +48,87 @@ DeviceStorageRequestParent::Dispatch() nsCOMPtr<nsIInputStream> stream; blob->GetInternalStream(getter_AddRefs(stream)); nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream); nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - NS_ASSERTION(target, "Must have stream transport service"); + MOZ_ASSERT(target); + target->Dispatch(r, NS_DISPATCH_NORMAL); + break; + } + + case DeviceStorageParams::TDeviceStorageCreateFdParams: + { + DeviceStorageCreateFdParams p = mParams; + + nsRefPtr<DeviceStorageFile> dsf = + new DeviceStorageFile(p.type(), p.storageName(), p.relpath()); + + nsRefPtr<CancelableRunnable> r = new CreateFdEvent(this, dsf); + + nsCOMPtr<nsIEventTarget> target + = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + MOZ_ASSERT(target); target->Dispatch(r, NS_DISPATCH_NORMAL); break; } case DeviceStorageParams::TDeviceStorageGetParams: { DeviceStorageGetParams p = mParams; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(p.type(), p.storageName(), p.rootDir(), p.relpath()); nsRefPtr<CancelableRunnable> r = new ReadFileEvent(this, dsf); nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - NS_ASSERTION(target, "Must have stream transport service"); + MOZ_ASSERT(target); target->Dispatch(r, NS_DISPATCH_NORMAL); break; } case DeviceStorageParams::TDeviceStorageDeleteParams: { DeviceStorageDeleteParams p = mParams; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(p.type(), p.storageName(), p.relpath()); nsRefPtr<CancelableRunnable> r = new DeleteFileEvent(this, dsf); nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - NS_ASSERTION(target, "Must have stream transport service"); + MOZ_ASSERT(target); target->Dispatch(r, NS_DISPATCH_NORMAL); break; } case DeviceStorageParams::TDeviceStorageFreeSpaceParams: { DeviceStorageFreeSpaceParams p = mParams; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(p.type(), p.storageName()); nsRefPtr<FreeSpaceFileEvent> r = new FreeSpaceFileEvent(this, dsf); nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - NS_ASSERTION(target, "Must have stream transport service"); + MOZ_ASSERT(target); target->Dispatch(r, NS_DISPATCH_NORMAL); break; } case DeviceStorageParams::TDeviceStorageUsedSpaceParams: { DeviceStorageUsedSpaceCache* usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet(); - NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null"); + MOZ_ASSERT(usedSpaceCache); DeviceStorageUsedSpaceParams p = mParams; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(p.type(), p.storageName()); nsRefPtr<UsedSpaceFileEvent> r = new UsedSpaceFileEvent(this, dsf); usedSpaceCache->Dispatch(r); @@ -122,44 +138,46 @@ DeviceStorageRequestParent::Dispatch() case DeviceStorageParams::TDeviceStorageAvailableParams: { DeviceStorageAvailableParams p = mParams; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(p.type(), p.storageName()); nsRefPtr<PostAvailableResultEvent> r = new PostAvailableResultEvent(this, dsf); - NS_DispatchToMainThread(r); + DebugOnly<nsresult> rv = NS_DispatchToMainThread(r); + MOZ_ASSERT(NS_SUCCEEDED(rv)); break; } case DeviceStorageParams::TDeviceStorageFormatParams: { DeviceStorageFormatParams p = mParams; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(p.type(), p.storageName()); nsRefPtr<PostFormatResultEvent> r = new PostFormatResultEvent(this, dsf); - NS_DispatchToMainThread(r); + DebugOnly<nsresult> rv = NS_DispatchToMainThread(r); + MOZ_ASSERT(NS_SUCCEEDED(rv)); break; } case DeviceStorageParams::TDeviceStorageEnumerationParams: { DeviceStorageEnumerationParams p = mParams; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(p.type(), p.storageName(), p.rootdir(), NS_LITERAL_STRING("")); nsRefPtr<CancelableRunnable> r = new EnumerateFileEvent(this, dsf, p.since()); nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - NS_ASSERTION(target, "Must have stream transport service"); + MOZ_ASSERT(target); target->Dispatch(r, NS_DISPATCH_NORMAL); break; } default: { NS_RUNTIMEABORT("not reached"); break; } @@ -182,16 +200,24 @@ DeviceStorageRequestParent::EnsureRequir case DeviceStorageParams::TDeviceStorageAddParams: { DeviceStorageAddParams p = mParams; type = p.type(); requestType = DEVICE_STORAGE_REQUEST_CREATE; break; } + case DeviceStorageParams::TDeviceStorageCreateFdParams: + { + DeviceStorageCreateFdParams p = mParams; + type = p.type(); + requestType = DEVICE_STORAGE_REQUEST_CREATEFD; + break; + } + case DeviceStorageParams::TDeviceStorageGetParams: { DeviceStorageGetParams p = mParams; type = p.type(); requestType = DEVICE_STORAGE_REQUEST_READ; break; } @@ -307,17 +333,17 @@ DeviceStorageRequestParent::PostFreeSpac { } DeviceStorageRequestParent::PostFreeSpaceResultEvent:: ~PostFreeSpaceResultEvent() {} nsresult DeviceStorageRequestParent::PostFreeSpaceResultEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); FreeSpaceStorageResponse response(mFreeSpace); unused << mParent->Send__delete__(mParent, response); return NS_OK; } DeviceStorageRequestParent::PostUsedSpaceResultEvent:: PostUsedSpaceResultEvent(DeviceStorageRequestParent* aParent, @@ -329,17 +355,17 @@ DeviceStorageRequestParent::PostUsedSpac { } DeviceStorageRequestParent::PostUsedSpaceResultEvent:: ~PostUsedSpaceResultEvent() {} nsresult DeviceStorageRequestParent::PostUsedSpaceResultEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); UsedSpaceStorageResponse response(mUsedSpace); unused << mParent->Send__delete__(mParent, response); return NS_OK; } DeviceStorageRequestParent::PostErrorEvent:: PostErrorEvent(DeviceStorageRequestParent* aParent, const char* aError) @@ -347,34 +373,34 @@ DeviceStorageRequestParent::PostErrorEve { CopyASCIItoUTF16(aError, mError); } DeviceStorageRequestParent::PostErrorEvent::~PostErrorEvent() {} nsresult DeviceStorageRequestParent::PostErrorEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); ErrorResponse response(mError); unused << mParent->Send__delete__(mParent, response); return NS_OK; } DeviceStorageRequestParent::PostSuccessEvent:: PostSuccessEvent(DeviceStorageRequestParent* aParent) : CancelableRunnable(aParent) { } DeviceStorageRequestParent::PostSuccessEvent::~PostSuccessEvent() {} nsresult DeviceStorageRequestParent::PostSuccessEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); SuccessResponse response; unused << mParent->Send__delete__(mParent, response); return NS_OK; } DeviceStorageRequestParent::PostBlobSuccessEvent:: PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, @@ -389,17 +415,17 @@ DeviceStorageRequestParent::PostBlobSucc , mMimeType(aMimeType) { } DeviceStorageRequestParent::PostBlobSuccessEvent::~PostBlobSuccessEvent() {} nsresult DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); nsString mime; CopyASCIItoUTF16(mMimeType, mime); nsString fullPath; mFile->GetFullPath(fullPath); nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(fullPath, mime, mLength, mFile->mFile, @@ -432,23 +458,64 @@ DeviceStorageRequestParent::PostEnumerat { } DeviceStorageRequestParent::PostEnumerationSuccessEvent:: ~PostEnumerationSuccessEvent() {} nsresult DeviceStorageRequestParent::PostEnumerationSuccessEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); EnumerationResponse response(mStorageType, mRelPath, mPaths); unused << mParent->Send__delete__(mParent, response); return NS_OK; } +DeviceStorageRequestParent::CreateFdEvent:: + CreateFdEvent(DeviceStorageRequestParent* aParent, + DeviceStorageFile* aFile) + : CancelableRunnable(aParent) + , mFile(aFile) +{ +} + +DeviceStorageRequestParent::CreateFdEvent::~CreateFdEvent() +{ +} + +nsresult +DeviceStorageRequestParent::CreateFdEvent::CancelableRun() +{ + MOZ_ASSERT(!NS_IsMainThread()); + + nsRefPtr<nsRunnable> r; + + bool check = false; + mFile->mFile->Exists(&check); + if (check) { + nsCOMPtr<PostErrorEvent> event + = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS); + return NS_DispatchToMainThread(event); + } + + FileDescriptor fileDescriptor; + nsresult rv = mFile->CreateFileDescriptor(fileDescriptor); + if (NS_FAILED(rv)) { + NS_WARNING("CreateFileDescriptor failed"); + mFile->Dump("CreateFileDescriptor failed"); + r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN); + } + else { + r = new PostFileDescriptorResultEvent(mParent, fileDescriptor); + } + + return NS_DispatchToMainThread(r); +} + DeviceStorageRequestParent::WriteFileEvent:: WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, nsIInputStream* aInputStream) : CancelableRunnable(aParent) , mFile(aFile) , mInputStream(aInputStream) { @@ -456,80 +523,75 @@ DeviceStorageRequestParent::WriteFileEve DeviceStorageRequestParent::WriteFileEvent::~WriteFileEvent() { } nsresult DeviceStorageRequestParent::WriteFileEvent::CancelableRun() { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!NS_IsMainThread()); nsRefPtr<nsRunnable> r; if (!mInputStream) { r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } bool check = false; mFile->mFile->Exists(&check); if (check) { nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS); - NS_DispatchToMainThread(event); - return NS_OK; + return NS_DispatchToMainThread(event); } nsresult rv = mFile->Write(mInputStream); if (NS_FAILED(rv)) { r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN); } else { r = new PostPathResultEvent(mParent, mFile->mPath); } - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } - DeviceStorageRequestParent::DeleteFileEvent:: DeleteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile) : CancelableRunnable(aParent) , mFile(aFile) { } DeviceStorageRequestParent::DeleteFileEvent::~DeleteFileEvent() { } nsresult DeviceStorageRequestParent::DeleteFileEvent::CancelableRun() { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!NS_IsMainThread()); mFile->Remove(); nsRefPtr<nsRunnable> r; bool check = false; mFile->mFile->Exists(&check); if (check) { r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN); } else { r = new PostPathResultEvent(mParent, mFile->mPath); } - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } DeviceStorageRequestParent::FreeSpaceFileEvent:: FreeSpaceFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile) : CancelableRunnable(aParent) , mFile(aFile) { @@ -537,27 +599,26 @@ DeviceStorageRequestParent::FreeSpaceFil DeviceStorageRequestParent::FreeSpaceFileEvent::~FreeSpaceFileEvent() { } nsresult DeviceStorageRequestParent::FreeSpaceFileEvent::CancelableRun() { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!NS_IsMainThread()); int64_t freeSpace = 0; if (mFile) { mFile->GetDiskFreeSpace(&freeSpace); } nsCOMPtr<nsIRunnable> r; r = new PostFreeSpaceResultEvent(mParent, static_cast<uint64_t>(freeSpace)); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } DeviceStorageRequestParent::UsedSpaceFileEvent:: UsedSpaceFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile) : CancelableRunnable(aParent) , mFile(aFile) { @@ -565,17 +626,17 @@ DeviceStorageRequestParent::UsedSpaceFil DeviceStorageRequestParent::UsedSpaceFileEvent::~UsedSpaceFileEvent() { } nsresult DeviceStorageRequestParent::UsedSpaceFileEvent::CancelableRun() { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!NS_IsMainThread()); uint64_t picturesUsage = 0, videosUsage = 0, musicUsage = 0, totalUsage = 0; mFile->AccumDiskUsage(&picturesUsage, &videosUsage, &musicUsage, &totalUsage); nsCOMPtr<nsIRunnable> r; if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, picturesUsage); @@ -583,18 +644,17 @@ DeviceStorageRequestParent::UsedSpaceFil else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, videosUsage); } else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, musicUsage); } else { r = new PostUsedSpaceResultEvent(mParent, mFile->mStorageType, totalUsage); } - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } DeviceStorageRequestParent::ReadFileEvent:: ReadFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile) : CancelableRunnable(aParent) , mFile(aFile) { nsCOMPtr<nsIMIMEService> mimeService @@ -609,48 +669,44 @@ DeviceStorageRequestParent::ReadFileEven DeviceStorageRequestParent::ReadFileEvent::~ReadFileEvent() { } nsresult DeviceStorageRequestParent::ReadFileEvent::CancelableRun() { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsIRunnable> r; bool check = false; mFile->mFile->Exists(&check); if (!check) { r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } int64_t fileSize; nsresult rv = mFile->mFile->GetFileSize(&fileSize); if (NS_FAILED(rv)) { r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } PRTime modDate; rv = mFile->mFile->GetLastModifiedTime(&modDate); if (NS_FAILED(rv)) { r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } r = new PostBlobSuccessEvent(mParent, mFile, static_cast<uint64_t>(fileSize), mMimeType, modDate); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } DeviceStorageRequestParent::EnumerateFileEvent:: EnumerateFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, uint64_t aSince) : CancelableRunnable(aParent) , mFile(aFile) @@ -660,44 +716,42 @@ DeviceStorageRequestParent::EnumerateFil DeviceStorageRequestParent::EnumerateFileEvent::~EnumerateFileEvent() { } nsresult DeviceStorageRequestParent::EnumerateFileEvent::CancelableRun() { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsIRunnable> r; if (mFile->mFile) { bool check = false; mFile->mFile->Exists(&check); if (!check) { r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } } nsTArray<nsRefPtr<DeviceStorageFile> > files; mFile->CollectFiles(files, mSince); InfallibleTArray<DeviceStorageFileValue> values; uint32_t count = files.Length(); for (uint32_t i = 0; i < count; i++) { DeviceStorageFileValue dsvf(files[i]->mStorageName, files[i]->mPath); values.AppendElement(dsvf); } r = new PostEnumerationSuccessEvent(mParent, mFile->mStorageType, mFile->mRootDir, values); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } DeviceStorageRequestParent::PostPathResultEvent:: PostPathResultEvent(DeviceStorageRequestParent* aParent, const nsAString& aPath) : CancelableRunnable(aParent) , mPath(aPath) @@ -706,40 +760,63 @@ DeviceStorageRequestParent::PostPathResu DeviceStorageRequestParent::PostPathResultEvent::~PostPathResultEvent() { } nsresult DeviceStorageRequestParent::PostPathResultEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); SuccessResponse response; unused << mParent->Send__delete__(mParent, response); return NS_OK; } +DeviceStorageRequestParent::PostFileDescriptorResultEvent:: + PostFileDescriptorResultEvent(DeviceStorageRequestParent* aParent, + const FileDescriptor& aFileDescriptor) + : CancelableRunnable(aParent) + , mFileDescriptor(aFileDescriptor) +{ +} + +DeviceStorageRequestParent::PostFileDescriptorResultEvent:: + ~PostFileDescriptorResultEvent() +{ +} + +nsresult +DeviceStorageRequestParent::PostFileDescriptorResultEvent::CancelableRun() +{ + MOZ_ASSERT(NS_IsMainThread()); + + FileDescriptorResponse response(mFileDescriptor); + unused << mParent->Send__delete__(mParent, response); + return NS_OK; +} + DeviceStorageRequestParent::PostAvailableResultEvent:: PostAvailableResultEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile) : CancelableRunnable(aParent) , mFile(aFile) { } DeviceStorageRequestParent::PostAvailableResultEvent:: ~PostAvailableResultEvent() { } nsresult DeviceStorageRequestParent::PostAvailableResultEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); nsString state = NS_LITERAL_STRING("unavailable"); if (mFile) { mFile->GetStatus(state); } AvailableStorageResponse response(state); unused << mParent->Send__delete__(mParent, response); @@ -757,17 +834,17 @@ DeviceStorageRequestParent::PostFormatRe DeviceStorageRequestParent::PostFormatResultEvent:: ~PostFormatResultEvent() { } nsresult DeviceStorageRequestParent::PostFormatResultEvent::CancelableRun() { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(NS_IsMainThread()); nsString state = NS_LITERAL_STRING("unavailable"); if (mFile) { mFile->DoFormat(state); } FormatStorageResponse response(state); unused << mParent->Send__delete__(mParent, response);
--- a/dom/devicestorage/DeviceStorageRequestParent.h +++ b/dom/devicestorage/DeviceStorageRequestParent.h @@ -114,16 +114,26 @@ private: virtual ~PostEnumerationSuccessEvent(); virtual nsresult CancelableRun(); private: const nsString mStorageType; const nsString mRelPath; InfallibleTArray<DeviceStorageFileValue> mPaths; }; + class CreateFdEvent : public CancelableRunnable + { + public: + CreateFdEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile); + virtual ~CreateFdEvent(); + virtual nsresult CancelableRun(); + private: + nsRefPtr<DeviceStorageFile> mFile; + }; + class WriteFileEvent : public CancelableRunnable { public: WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, nsIInputStream* aInputStream); virtual ~WriteFileEvent(); virtual nsresult CancelableRun(); private: nsRefPtr<DeviceStorageFile> mFile; @@ -188,16 +198,28 @@ private: PostPathResultEvent(DeviceStorageRequestParent* aParent, const nsAString& aPath); virtual ~PostPathResultEvent(); virtual nsresult CancelableRun(); private: nsRefPtr<DeviceStorageFile> mFile; nsString mPath; }; + class PostFileDescriptorResultEvent : public CancelableRunnable + { + public: + PostFileDescriptorResultEvent(DeviceStorageRequestParent* aParent, + const FileDescriptor& aFileDescriptor); + virtual ~PostFileDescriptorResultEvent(); + virtual nsresult CancelableRun(); + private: + nsRefPtr<DeviceStorageFile> mFile; + FileDescriptor mFileDescriptor; + }; + class PostFreeSpaceResultEvent : public CancelableRunnable { public: PostFreeSpaceResultEvent(DeviceStorageRequestParent* aParent, uint64_t aFreeSpace); virtual ~PostFreeSpaceResultEvent(); virtual nsresult CancelableRun(); private:
--- a/dom/devicestorage/PDeviceStorageRequest.ipdl +++ b/dom/devicestorage/PDeviceStorageRequest.ipdl @@ -15,16 +15,21 @@ struct ErrorResponse { nsString error; }; struct SuccessResponse { }; +struct FileDescriptorResponse +{ + FileDescriptor fileDescriptor; +}; + struct BlobResponse { PBlob blob; }; struct DeviceStorageFileValue { nsString storageName; @@ -57,16 +62,17 @@ struct FormatStorageResponse { nsString mountState; }; union DeviceStorageResponseValue { ErrorResponse; SuccessResponse; + FileDescriptorResponse; BlobResponse; EnumerationResponse; FreeSpaceStorageResponse; UsedSpaceStorageResponse; AvailableStorageResponse; FormatStorageResponse; };
--- a/dom/devicestorage/moz.build +++ b/dom/devicestorage/moz.build @@ -3,16 +3,17 @@ # 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/. TEST_DIRS += ['test', 'ipc'] EXPORTS += [ 'DeviceStorage.h', + 'DeviceStorageFileDescriptor.h', 'nsDeviceStorage.h', ] EXPORTS.mozilla.dom.devicestorage += [ 'DeviceStorageRequestChild.h', 'DeviceStorageRequestParent.h', ]
--- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -33,27 +33,29 @@ #include "nsCycleCollectionParticipant.h" #include "nsIPrincipal.h" #include "nsJSUtils.h" #include "DictionaryHelpers.h" #include "nsContentUtils.h" #include "nsCxPusher.h" #include "nsXULAppAPI.h" #include "TabChild.h" +#include "DeviceStorageFileDescriptor.h" #include "DeviceStorageRequestChild.h" #include "nsIDOMDeviceStorageChangeEvent.h" #include "nsCRT.h" #include "nsIObserverService.h" #include "GeneratedEvents.h" #include "nsIMIMEService.h" #include "nsCExternalHandlerService.h" #include "nsIPermissionManager.h" #include "nsIStringBundle.h" #include "nsIDocument.h" #include <algorithm> +#include "private/pprio.h" #include "mozilla/dom/DeviceStorageBinding.h" // Microsoft's API Name hackery sucks #undef CreateEvent #ifdef MOZ_WIDGET_GONK #include "nsIVolume.h" @@ -62,16 +64,17 @@ #define DEVICESTORAGE_PROPERTIES \ "chrome://global/content/devicestorage.properties" #define DEFAULT_THREAD_TIMEOUT_MS 30000 using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::devicestorage; +using namespace mozilla::ipc; #include "nsDirectoryServiceDefs.h" StaticAutoPtr<DeviceStorageUsedSpaceCache> DeviceStorageUsedSpaceCache::sDeviceStorageUsedSpaceCache; DeviceStorageUsedSpaceCache::DeviceStorageUsedSpaceCache() { @@ -244,17 +247,17 @@ DeviceStorageTypeChecker::InitFromBundle NS_ConvertASCIItoUTF16(DEVICESTORAGE_VIDEOS).get(), getter_Copies(mVideosExtensions)); } bool DeviceStorageTypeChecker::Check(const nsAString& aType, nsIDOMBlob* aBlob) { - NS_ASSERTION(aBlob, "Calling Check without a blob"); + MOZ_ASSERT(aBlob); nsString mimeType; if (NS_FAILED(aBlob->GetType(mimeType))) { return false; } if (aType.EqualsLiteral(DEVICESTORAGE_PICTURES)) { return StringBeginsWith(mimeType, NS_LITERAL_STRING("image/")); @@ -276,17 +279,17 @@ DeviceStorageTypeChecker::Check(const ns } return false; } bool DeviceStorageTypeChecker::Check(const nsAString& aType, nsIFile* aFile) { - NS_ASSERTION(aFile, "Calling Check without a file"); + MOZ_ASSERT(aFile); if (aType.EqualsLiteral(DEVICESTORAGE_APPS) || aType.EqualsLiteral(DEVICESTORAGE_SDCARD) || aType.EqualsLiteral(DEVICESTORAGE_CRASHES)) { // Apps, crashes and sdcard have no restrictions on what file extensions used. return true; } @@ -316,17 +319,17 @@ DeviceStorageTypeChecker::Check(const ns } return false; } void DeviceStorageTypeChecker::GetTypeFromFile(nsIFile* aFile, nsAString& aType) { - NS_ASSERTION(aFile, "Calling Check without a file"); + MOZ_ASSERT(aFile); nsString path; aFile->GetPath(path); GetTypeFromFileName(path, aType); } void @@ -389,16 +392,17 @@ DeviceStorageTypeChecker::GetAccessForRe aAccessResult.AssignLiteral("read"); break; case DEVICE_STORAGE_REQUEST_WRITE: case DEVICE_STORAGE_REQUEST_DELETE: case DEVICE_STORAGE_REQUEST_FORMAT: aAccessResult.AssignLiteral("write"); break; case DEVICE_STORAGE_REQUEST_CREATE: + case DEVICE_STORAGE_REQUEST_CREATEFD: aAccessResult.AssignLiteral("create"); break; default: aAccessResult.AssignLiteral("undefined"); } return NS_OK; } @@ -478,17 +482,17 @@ public: nsString data; CopyASCIItoUTF16(mType, data); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); obs->NotifyObservers(mFile, "file-watcher-notify", data.get()); DeviceStorageUsedSpaceCache* usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet(); - NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null"); + MOZ_ASSERT(usedSpaceCache); usedSpaceCache->Invalidate(mFile->mStorageName); return NS_OK; } private: nsRefPtr<DeviceStorageFile> mFile; nsCString mType; }; @@ -569,17 +573,17 @@ void DeviceStorageFile::Init() { DeviceStorageFile::GetRootDirectoryForType(mStorageType, mStorageName, getter_AddRefs(mFile)); DebugOnly<DeviceStorageTypeChecker*> typeChecker = DeviceStorageTypeChecker::CreateOrGet(); - NS_ASSERTION(typeChecker, "DeviceStorageTypeChecker is null"); + MOZ_ASSERT(typeChecker); } // Directories which don't depend on a volume should be calculated once // here. Directories which depend on the root directory of a volume // should be calculated in DeviceStorageFile::GetRootDirectoryForType. static void InitDirs() { @@ -587,17 +591,17 @@ InitDirs() return; } MOZ_ASSERT(NS_IsMainThread()); sDirs = new GlobalDirs; ClearOnShutdown(&sDirs); nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); - NS_ASSERTION(dirService, "Must have directory service"); + MOZ_ASSERT(dirService); #if !defined(MOZ_WIDGET_GONK) #if defined (MOZ_WIDGET_COCOA) dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(sDirs->pictures)); dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, @@ -784,17 +788,17 @@ DeviceStorageFile::GetRootDirectoryForTy //static already_AddRefed<DeviceStorageFile> DeviceStorageFile::CreateUnique(nsAString& aFileName, uint32_t aFileType, uint32_t aFileAttributes) { DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet(); - NS_ASSERTION(typeChecker, "DeviceStorageTypeChecker is null"); + MOZ_ASSERT(typeChecker); nsString storageType; typeChecker->GetTypeFromFileName(aFileName, storageType); nsString storageName; nsString storagePath; if (!nsDOMDeviceStorage::ParseFullPath(aFileName, storageName, storagePath)) { return nullptr; @@ -919,29 +923,46 @@ DeviceStorageFile::AppendRelativePath(co } mFile->AppendRelativePath(temp); #else mFile->AppendRelativePath(aPath); #endif } nsresult +DeviceStorageFile::CreateFileDescriptor(FileDescriptor& aFileDescriptor) +{ + PRFileDesc* fd; + nsresult rv = mFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, + 0660, &fd); + NS_ENSURE_SUCCESS(rv, rv); + + aFileDescriptor = + FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(fd)); + + return NS_OK; +} + +nsresult DeviceStorageFile::Write(nsIInputStream* aInputStream) { if (!aInputStream || !mFile) { return NS_ERROR_FAILURE; } nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600); - if (NS_FAILED(rv)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsCOMPtr<IOEventComplete> iocomplete = new IOEventComplete(this, "created"); - NS_DispatchToMainThread(iocomplete); + rv = NS_DispatchToMainThread(iocomplete); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } uint64_t bufSize = 0; aInputStream->Available(&bufSize); nsCOMPtr<nsIOutputStream> outputStream; NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile); if (!outputStream) { @@ -962,54 +983,63 @@ DeviceStorageFile::Write(nsIInputStream* &wrote); if (NS_FAILED(rv)) { break; } bufSize -= wrote; } iocomplete = new IOEventComplete(this, "modified"); - NS_DispatchToMainThread(iocomplete); + rv = NS_DispatchToMainThread(iocomplete); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } bufferedOutputStream->Close(); outputStream->Close(); - if (NS_FAILED(rv)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } nsresult DeviceStorageFile::Write(InfallibleTArray<uint8_t>& aBits) { if (!mFile) { return NS_ERROR_FAILURE; } nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600); - if (NS_FAILED(rv)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsCOMPtr<IOEventComplete> iocomplete = new IOEventComplete(this, "created"); - NS_DispatchToMainThread(iocomplete); + rv = NS_DispatchToMainThread(iocomplete); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } nsCOMPtr<nsIOutputStream> outputStream; NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile); if (!outputStream) { return NS_ERROR_FAILURE; } uint32_t wrote; outputStream->Write((char*) aBits.Elements(), aBits.Length(), &wrote); outputStream->Close(); iocomplete = new IOEventComplete(this, "modified"); - NS_DispatchToMainThread(iocomplete); + rv = NS_DispatchToMainThread(iocomplete); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } if (aBits.Length() != wrote) { return NS_ERROR_FAILURE; } return NS_OK; } nsresult @@ -1027,23 +1057,22 @@ DeviceStorageFile::Remove() return rv; } if (!check) { return NS_OK; } rv = mFile->Remove(true); - if (NS_FAILED(rv)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsCOMPtr<IOEventComplete> iocomplete = new IOEventComplete(this, "deleted"); - NS_DispatchToMainThread(iocomplete); - return NS_OK; + return NS_DispatchToMainThread(iocomplete); } nsresult DeviceStorageFile::CalculateMimeType() { MOZ_ASSERT(NS_IsMainThread()); nsAutoCString mimeType; @@ -1111,17 +1140,17 @@ DeviceStorageFile::collectFilesInternal( while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) { PRTime msecs; f->GetLastModifiedTime(&msecs); if (msecs < aSince) { continue; - } + } bool isDir; f->IsDirectory(&isDir); bool isFile; f->IsFile(&isFile); nsString fullpath; @@ -1160,17 +1189,17 @@ DeviceStorageFile::AccumDiskUsage(uint64 return; } uint64_t pictureUsage = 0, videoUsage = 0, musicUsage = 0, totalUsage = 0; if (DeviceStorageTypeChecker::IsVolumeBased(mStorageType)) { DeviceStorageUsedSpaceCache* usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet(); - NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null"); + MOZ_ASSERT(usedSpaceCache); nsresult rv = usedSpaceCache->AccumUsedSizes(mStorageName, aPicturesSoFar, aVideosSoFar, aMusicSoFar, aTotalSoFar); if (NS_SUCCEEDED(rv)) { return; } AccumDirectoryUsage(mFile, &pictureUsage, &videoUsage, &musicUsage, &totalUsage); @@ -1202,18 +1231,17 @@ DeviceStorageFile::AccumDirectoryUsage(n nsCOMPtr<nsISimpleEnumerator> e; rv = aFile->GetDirectoryEntries(getter_AddRefs(e)); if (NS_FAILED(rv) || !e) { return; } nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e); - NS_ASSERTION(files, - "GetDirectoryEntries must return a nsIDirectoryEnumerator"); + MOZ_ASSERT(files); nsCOMPtr<nsIFile> f; while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(f))) && f) { bool isDir; rv = f->IsDirectory(&isDir); if (NS_FAILED(rv)) { continue; } @@ -1240,17 +1268,17 @@ DeviceStorageFile::AccumDirectoryUsage(n int64_t size; rv = f->GetFileSize(&size); if (NS_FAILED(rv)) { continue; } DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet(); - NS_ASSERTION(typeChecker, "DeviceStorageTypeChecker is null"); + MOZ_ASSERT(typeChecker); nsString type; typeChecker->GetTypeFromFile(f, type); if (type.EqualsLiteral(DEVICESTORAGE_PICTURES)) { *aPicturesSoFar += size; } else if (type.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { *aVideosSoFar += size; @@ -1436,47 +1464,46 @@ InterfaceToJsval(nsPIDOMWindow* aWindow, return someJsVal; } JS::Value nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile) { MOZ_ASSERT(NS_IsMainThread()); - NS_ASSERTION(aWindow, "Null Window"); + MOZ_ASSERT(aWindow); if (!aFile) { return JSVAL_NULL; } if (aFile->mEditable) { // TODO - needs janv's file handle support. return JSVAL_NULL; } nsString fullPath; aFile->GetFullPath(fullPath); // This check is useful to know if somewhere the DeviceStorageFile // has not been properly set. Mimetype is not checked because it can be // empty. - NS_ASSERTION(aFile->mLength != UINT64_MAX, "Size not set"); - NS_ASSERTION(aFile->mLastModifiedDate != UINT64_MAX, - "LastModifiedDate not set"); + MOZ_ASSERT(aFile->mLength != UINT64_MAX); + MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX); nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(fullPath, aFile->mMimeType, aFile->mLength, aFile->mFile, aFile->mLastModifiedDate); return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob)); } JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString) { MOZ_ASSERT(NS_IsMainThread()); - NS_ASSERTION(aWindow, "Null Window"); + MOZ_ASSERT(aWindow); nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow); if (!sgo) { return JSVAL_NULL; } nsIScriptContext *scriptContext = sgo->GetScriptContext(); if (!scriptContext) { @@ -1615,25 +1642,27 @@ ContinueCursorEvent::GetNextFile() } ContinueCursorEvent::~ContinueCursorEvent() {} void ContinueCursorEvent::Continue() { if (XRE_GetProcessType() == GeckoProcessType_Default) { - NS_DispatchToMainThread(this); + DebugOnly<nsresult> rv = NS_DispatchToMainThread(this); + MOZ_ASSERT(NS_SUCCEEDED(rv)); return; } nsRefPtr<DeviceStorageFile> file = GetNextFile(); if (!file) { // done with enumeration. - NS_DispatchToMainThread(this); + DebugOnly<nsresult> rv = NS_DispatchToMainThread(this); + MOZ_ASSERT(NS_SUCCEEDED(rv)); return; } nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); nsString cursorStorageType; cursor->GetStorageType(cursorStorageType); @@ -1686,18 +1715,17 @@ public: if (mFile->mFile) { bool check; mFile->mFile->IsDirectory(&check); if (!check) { nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_NOT_ENUMERABLE); - NS_DispatchToMainThread(event); - return NS_OK; + return NS_DispatchToMainThread(event); } } nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get()); mFile->CollectFiles(cursor->mFiles, cursor->mSince); nsCOMPtr<ContinueCursorEvent> event @@ -1777,45 +1805,43 @@ nsDOMDeviceStorageCursor::GetElement(nsI return NS_OK; } NS_IMETHODIMP nsDOMDeviceStorageCursor::Cancel() { nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED); - NS_DispatchToMainThread(event); - return NS_OK; + return NS_DispatchToMainThread(event); } NS_IMETHODIMP nsDOMDeviceStorageCursor::Allow() { if (!mFile->IsSafePath()) { nsCOMPtr<nsIRunnable> r = new PostErrorEvent(this, POST_ERROR_EVENT_PERMISSION_DENIED); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } if (XRE_GetProcessType() != GeckoProcessType_Default) { PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(this, mFile); DeviceStorageEnumerationParams params(mFile->mStorageType, mFile->mStorageName, mFile->mRootDir, mSince); ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params); return NS_OK; } nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - NS_ASSERTION(target, "Must have stream transport service"); + MOZ_ASSERT(target); nsCOMPtr<InitCursorEvent> event = new InitCursorEvent(this, mFile); target->Dispatch(event, NS_DISPATCH_NORMAL); return NS_OK; } void nsDOMDeviceStorageCursor::Continue(ErrorResult& aRv) @@ -1854,27 +1880,28 @@ void nsDOMDeviceStorageCursor::IPDLRelease() { Release(); } void nsDOMDeviceStorageCursor::RequestComplete() { - NS_ASSERTION(!mOkToCallContinue, "mOkToCallContinue must be false"); + MOZ_ASSERT(!mOkToCallContinue); mOkToCallContinue = true; } class PostAvailableResultEvent : public nsRunnable { public: PostAvailableResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) : mFile(aFile) , mRequest(aRequest) { + MOZ_ASSERT(mRequest); } ~PostAvailableResultEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(NS_IsMainThread()); @@ -1898,16 +1925,17 @@ private: class PostFormatResultEvent : public nsRunnable { public: PostFormatResultEvent(DeviceStorageFile *aFile, DOMRequest* aRequest) : mFile(aFile) , mRequest(aRequest) { + MOZ_ASSERT(mRequest); } ~PostFormatResultEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(NS_IsMainThread()); @@ -1931,29 +1959,35 @@ private: class PostResultEvent : public nsRunnable { public: PostResultEvent(already_AddRefed<DOMRequest> aRequest, DeviceStorageFile* aFile) : mFile(aFile) , mRequest(aRequest) - {} + { + MOZ_ASSERT(mRequest); + } PostResultEvent(already_AddRefed<DOMRequest> aRequest, const nsAString & aPath) : mPath(aPath) , mRequest(aRequest) - {} + { + MOZ_ASSERT(mRequest); + } PostResultEvent(already_AddRefed<DOMRequest> aRequest, const uint64_t aValue) : mValue(aValue) , mRequest(aRequest) - {} + { + MOZ_ASSERT(mRequest); + } ~PostResultEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(NS_IsMainThread()); AutoJSContext cx; @@ -1976,78 +2010,131 @@ public: private: nsRefPtr<DeviceStorageFile> mFile; nsString mPath; uint64_t mValue; nsRefPtr<DOMRequest> mRequest; }; +class CreateFdEvent : public nsRunnable +{ +public: + CreateFdEvent(DeviceStorageFileDescriptor* aDSFileDescriptor, + already_AddRefed<DOMRequest> aRequest) + : mDSFileDescriptor(aDSFileDescriptor) + , mRequest(aRequest) + { + MOZ_ASSERT(mDSFileDescriptor); + MOZ_ASSERT(mRequest); + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(!NS_IsMainThread()); + + DeviceStorageFile* dsFile = mDSFileDescriptor->mDSFile; + MOZ_ASSERT(dsFile); + + nsString fullPath; + dsFile->GetFullPath(fullPath); + MOZ_ASSERT(!fullPath.IsEmpty()); + + bool check = false; + dsFile->mFile->Exists(&check); + if (check) { + nsCOMPtr<PostErrorEvent> event = + new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS); + return NS_DispatchToMainThread(event); + } + + nsresult rv = dsFile->CreateFileDescriptor(mDSFileDescriptor->mFileDescriptor); + + if (NS_FAILED(rv)) { + dsFile->mFile->Remove(false); + + nsCOMPtr<PostErrorEvent> event = + new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); + return NS_DispatchToMainThread(event); + } + + nsCOMPtr<PostResultEvent> event = + new PostResultEvent(mRequest.forget(), fullPath); + return NS_DispatchToMainThread(event); + } + +private: + nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; + nsRefPtr<DOMRequest> mRequest; +}; + class WriteFileEvent : public nsRunnable { public: WriteFileEvent(nsIDOMBlob* aBlob, DeviceStorageFile *aFile, already_AddRefed<DOMRequest> aRequest) : mBlob(aBlob) , mFile(aFile) , mRequest(aRequest) - {} + { + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); + } ~WriteFileEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsIInputStream> stream; mBlob->GetInternalStream(getter_AddRefs(stream)); bool check = false; mFile->mFile->Exists(&check); if (check) { nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS); - NS_DispatchToMainThread(event); - return NS_OK; + return NS_DispatchToMainThread(event); } nsresult rv = mFile->Write(stream); if (NS_FAILED(rv)) { mFile->mFile->Remove(false); nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); - NS_DispatchToMainThread(event); - return NS_OK; + return NS_DispatchToMainThread(event); } nsString fullPath; mFile->GetFullPath(fullPath); nsCOMPtr<PostResultEvent> event = new PostResultEvent(mRequest.forget(), fullPath); - NS_DispatchToMainThread(event); - return NS_OK; + return NS_DispatchToMainThread(event); } private: nsCOMPtr<nsIDOMBlob> mBlob; nsRefPtr<DeviceStorageFile> mFile; nsRefPtr<DOMRequest> mRequest; }; class ReadFileEvent : public nsRunnable { public: ReadFileEvent(DeviceStorageFile* aFile, already_AddRefed<DOMRequest> aRequest) : mFile(aFile) , mRequest(aRequest) { + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); mFile->CalculateMimeType(); } ~ReadFileEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); @@ -2067,33 +2154,35 @@ public: if (NS_FAILED(rv)) { r = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN); } } if (!r) { r = new PostResultEvent(mRequest.forget(), mFile); } - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } private: nsRefPtr<DeviceStorageFile> mFile; nsRefPtr<DOMRequest> mRequest; }; class DeleteFileEvent : public nsRunnable { public: DeleteFileEvent(DeviceStorageFile* aFile, already_AddRefed<DOMRequest> aRequest) : mFile(aFile) , mRequest(aRequest) - {} + { + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); + } ~DeleteFileEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); mFile->Remove(); @@ -2104,33 +2193,35 @@ public: r = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_DOES_NOT_EXIST); } else { nsString fullPath; mFile->GetFullPath(fullPath); r = new PostResultEvent(mRequest.forget(), fullPath); } - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } private: nsRefPtr<DeviceStorageFile> mFile; nsRefPtr<DOMRequest> mRequest; }; class UsedSpaceFileEvent : public nsRunnable { public: UsedSpaceFileEvent(DeviceStorageFile* aFile, already_AddRefed<DOMRequest> aRequest) : mFile(aFile) , mRequest(aRequest) - {} + { + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); + } ~UsedSpaceFileEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); uint64_t picturesUsage = 0, videosUsage = 0, musicUsage = 0, totalUsage = 0; @@ -2143,90 +2234,124 @@ public: else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_VIDEOS)) { r = new PostResultEvent(mRequest.forget(), videosUsage); } else if (mFile->mStorageType.EqualsLiteral(DEVICESTORAGE_MUSIC)) { r = new PostResultEvent(mRequest.forget(), musicUsage); } else { r = new PostResultEvent(mRequest.forget(), totalUsage); } - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } private: nsRefPtr<DeviceStorageFile> mFile; nsRefPtr<DOMRequest> mRequest; }; class FreeSpaceFileEvent : public nsRunnable { public: FreeSpaceFileEvent(DeviceStorageFile* aFile, already_AddRefed<DOMRequest> aRequest) : mFile(aFile) , mRequest(aRequest) - {} + { + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); + } ~FreeSpaceFileEvent() {} NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); int64_t freeSpace = 0; if (mFile) { mFile->GetDiskFreeSpace(&freeSpace); } nsCOMPtr<nsIRunnable> r; r = new PostResultEvent(mRequest.forget(), static_cast<uint64_t>(freeSpace)); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToMainThread(r); } private: nsRefPtr<DeviceStorageFile> mFile; nsRefPtr<DOMRequest> mRequest; }; class DeviceStorageRequest MOZ_FINAL : public nsIContentPermissionRequest , public nsIRunnable , public PCOMContentPermissionRequestChild { public: - DeviceStorageRequest(const DeviceStorageRequestType aRequestType, - nsPIDOMWindow *aWindow, - nsIPrincipal *aPrincipal, - DeviceStorageFile *aFile, - DOMRequest* aRequest, - nsDOMDeviceStorage *aDeviceStorage) - : mRequestType(aRequestType) - , mWindow(aWindow) - , mPrincipal(aPrincipal) - , mFile(aFile) - , mRequest(aRequest) - , mDeviceStorage(aDeviceStorage) - {} - - DeviceStorageRequest(const DeviceStorageRequestType aRequestType, - nsPIDOMWindow *aWindow, - nsIPrincipal *aPrincipal, - DeviceStorageFile *aFile, - DOMRequest* aRequest, - nsIDOMBlob *aBlob = nullptr) - : mRequestType(aRequestType) - , mWindow(aWindow) - , mPrincipal(aPrincipal) - , mFile(aFile) - , mRequest(aRequest) - , mBlob(aBlob) {} + DeviceStorageRequest(const DeviceStorageRequestType aRequestType, + nsPIDOMWindow* aWindow, + nsIPrincipal* aPrincipal, + DeviceStorageFile* aFile, + DOMRequest* aRequest, + nsDOMDeviceStorage* aDeviceStorage) + : mRequestType(aRequestType) + , mWindow(aWindow) + , mPrincipal(aPrincipal) + , mFile(aFile) + , mRequest(aRequest) + , mDeviceStorage(aDeviceStorage) + { + MOZ_ASSERT(mWindow); + MOZ_ASSERT(mPrincipal); + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); + MOZ_ASSERT(mDeviceStorage); + } + + DeviceStorageRequest(const DeviceStorageRequestType aRequestType, + nsPIDOMWindow* aWindow, + nsIPrincipal* aPrincipal, + DeviceStorageFile* aFile, + DOMRequest* aRequest, + nsIDOMBlob* aBlob = nullptr) + : mRequestType(aRequestType) + , mWindow(aWindow) + , mPrincipal(aPrincipal) + , mFile(aFile) + , mRequest(aRequest) + , mBlob(aBlob) + { + MOZ_ASSERT(mWindow); + MOZ_ASSERT(mPrincipal); + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); + } + + DeviceStorageRequest(const DeviceStorageRequestType aRequestType, + nsPIDOMWindow* aWindow, + nsIPrincipal* aPrincipal, + DeviceStorageFile* aFile, + DOMRequest* aRequest, + DeviceStorageFileDescriptor* aDSFileDescriptor) + : mRequestType(aRequestType) + , mWindow(aWindow) + , mPrincipal(aPrincipal) + , mFile(aFile) + , mRequest(aRequest) + , mDSFileDescriptor(aDSFileDescriptor) + { + MOZ_ASSERT(mRequestType == DEVICE_STORAGE_REQUEST_CREATEFD); + MOZ_ASSERT(mWindow); + MOZ_ASSERT(mPrincipal); + MOZ_ASSERT(mFile); + MOZ_ASSERT(mRequest); + MOZ_ASSERT(mDSFileDescriptor); + } NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest, nsIContentPermissionRequest) NS_IMETHOD Run() { MOZ_ASSERT(NS_IsMainThread()); @@ -2316,51 +2441,89 @@ public: return NS_OK; } NS_IMETHOD Cancel() { nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_PERMISSION_DENIED); - NS_DispatchToMainThread(event); - return NS_OK; + return NS_DispatchToMainThread(event); } NS_IMETHOD Allow() { - nsCOMPtr<nsIRunnable> r; + MOZ_ASSERT(NS_IsMainThread()); if (!mRequest) { return NS_ERROR_FAILURE; } + nsCOMPtr<nsIRunnable> r; + switch(mRequestType) { + case DEVICE_STORAGE_REQUEST_CREATEFD: + { + if (!mFile->mFile) { + return NS_ERROR_FAILURE; + } + + DeviceStorageTypeChecker* typeChecker + = DeviceStorageTypeChecker::CreateOrGet(); + if (!typeChecker) { + return NS_OK; + } + + if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { + r = new PostErrorEvent(mRequest.forget(), + POST_ERROR_EVENT_ILLEGAL_TYPE); + return NS_DispatchToCurrentThread(r); + } + + if (XRE_GetProcessType() != GeckoProcessType_Default) { + + DeviceStorageCreateFdParams params; + params.type() = mFile->mStorageType; + params.storageName() = mFile->mStorageName; + params.relpath() = mFile->mPath; + + mFile->Dump("DeviceStorageCreateFdParams"); + + PDeviceStorageRequestChild* child + = new DeviceStorageRequestChild(mRequest, mFile, + mDSFileDescriptor.get()); + ContentChild::GetSingleton() + ->SendPDeviceStorageRequestConstructor(child, params); + return NS_OK; + } + mDSFileDescriptor->mDSFile = mFile; + r = new CreateFdEvent(mDSFileDescriptor.get(), mRequest.forget()); + break; + } + case DEVICE_STORAGE_REQUEST_CREATE: { if (!mBlob || !mFile->mFile) { return NS_ERROR_FAILURE; } DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet(); if (!typeChecker) { return NS_OK; } if (!typeChecker->Check(mFile->mStorageType, mFile->mFile) || !typeChecker->Check(mFile->mStorageType, mBlob)) { r = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_ILLEGAL_TYPE); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToCurrentThread(r); } if (XRE_GetProcessType() != GeckoProcessType_Default) { - BlobChild* actor = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob); if (!actor) { return NS_ERROR_FAILURE; } DeviceStorageAddParams params; params.blobChild() = actor; @@ -2389,18 +2552,17 @@ public: = DeviceStorageTypeChecker::CreateOrGet(); if (!typeChecker) { return NS_OK; } if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { r = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_ILLEGAL_TYPE); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToCurrentThread(r); } if (XRE_GetProcessType() != GeckoProcessType_Default) { PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile); DeviceStorageGetParams params(mFile->mStorageType, mFile->mStorageName, mFile->mRootDir, @@ -2424,18 +2586,17 @@ public: = DeviceStorageTypeChecker::CreateOrGet(); if (!typeChecker) { return NS_OK; } if (!typeChecker->Check(mFile->mStorageType, mFile->mFile)) { r = new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_ILLEGAL_TYPE); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToCurrentThread(r); } if (XRE_GetProcessType() != GeckoProcessType_Default) { PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile); DeviceStorageDeleteParams params(mFile->mStorageType, mFile->mStorageName, mFile->mPath); @@ -2472,17 +2633,17 @@ public: ContentChild::GetSingleton() ->SendPDeviceStorageRequestConstructor(child, params); return NS_OK; } // this needs to be dispatched to only one (1) // thread or we will do more work than required. DeviceStorageUsedSpaceCache* usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet(); - NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null"); + MOZ_ASSERT(usedSpaceCache); r = new UsedSpaceFileEvent(mFile, mRequest.forget()); usedSpaceCache->Dispatch(r); return NS_OK; } case DEVICE_STORAGE_REQUEST_AVAILABLE: { if (XRE_GetProcessType() != GeckoProcessType_Default) { @@ -2490,18 +2651,17 @@ public: = new DeviceStorageRequestChild(mRequest, mFile); DeviceStorageAvailableParams params(mFile->mStorageType, mFile->mStorageName); ContentChild::GetSingleton() ->SendPDeviceStorageRequestConstructor(child, params); return NS_OK; } r = new PostAvailableResultEvent(mFile, mRequest); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToCurrentThread(r); } case DEVICE_STORAGE_REQUEST_WATCH: { mDeviceStorage->mAllowedToWatchFile = true; return NS_OK; } @@ -2512,26 +2672,25 @@ public: = new DeviceStorageRequestChild(mRequest, mFile); DeviceStorageFormatParams params(mFile->mStorageType, mFile->mStorageName); ContentChild::GetSingleton() ->SendPDeviceStorageRequestConstructor(child, params); return NS_OK; } r = new PostFormatResultEvent(mFile, mRequest); - NS_DispatchToMainThread(r); - return NS_OK; + return NS_DispatchToCurrentThread(r); } } if (r) { nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - NS_ASSERTION(target, "Must have stream transport service"); + MOZ_ASSERT(target); target->Dispatch(r, NS_DISPATCH_NORMAL); } return NS_OK; } bool Recv__delete__(const bool& allow) { @@ -2553,16 +2712,17 @@ private: int32_t mRequestType; nsCOMPtr<nsPIDOMWindow> mWindow; nsCOMPtr<nsIPrincipal> mPrincipal; nsRefPtr<DeviceStorageFile> mFile; nsRefPtr<DOMRequest> mRequest; nsCOMPtr<nsIDOMBlob> mBlob; nsRefPtr<nsDOMDeviceStorage> mDeviceStorage; + nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor; }; NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest) NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) NS_INTERFACE_MAP_ENTRY(nsIRunnable) NS_INTERFACE_MAP_END @@ -2598,19 +2758,19 @@ nsDOMDeviceStorage::WrapObject(JSContext } nsresult nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType, const nsAString &aVolName) { DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton(); - NS_ASSERTION(observer, "FileUpdateDispatcher is null"); - - NS_ASSERTION(aWindow, "Must have a content dom"); + MOZ_ASSERT(observer); + + MOZ_ASSERT(aWindow); SetRootDirectoryForType(aType, aVolName); if (!mRootDirectory) { return NS_ERROR_NOT_AVAILABLE; } if (!mStorageName.IsEmpty()) { RegisterForSDCardChanges(this); } @@ -2794,16 +2954,18 @@ nsDOMDeviceStorage::GetStorage(const nsA ds = GetStorageByName(storageName); } return ds.forget(); } already_AddRefed<nsDOMDeviceStorage> nsDOMDeviceStorage::GetStorageByName(const nsAString& aStorageName) { + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr<nsDOMDeviceStorage> ds; if (mStorageName.Equals(aStorageName)) { ds = this; return ds.forget(); } VolumeNameArray volNames; GetOrderedVolumeNames(volNames); @@ -2909,16 +3071,18 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob request.forget(_retval); return rv.ErrorCode(); } already_AddRefed<DOMRequest> nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + // if the blob is null here, bail if (!aBlob) { return nullptr; } nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); @@ -2928,24 +3092,28 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob* DeviceStorageTypeChecker* typeChecker = DeviceStorageTypeChecker::CreateOrGet(); if (!typeChecker) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsCOMPtr<nsIRunnable> r; + nsresult rv; if (IsFullPath(aPath)) { nsString storagePath; nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); if (!ds) { nsRefPtr<DOMRequest> request = new DOMRequest(win); r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); - NS_DispatchToMainThread(r); + rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } return ds->AddNamed(aBlob, storagePath, aRv); } nsRefPtr<DOMRequest> request = new DOMRequest(win); nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, @@ -2956,17 +3124,20 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob* } else if (!typeChecker->Check(mStorageType, dsf->mFile) || !typeChecker->Check(mStorageType, aBlob)) { r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE); } else { r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATE, win, mPrincipal, dsf, request, aBlob); } - NS_DispatchToMainThread(r); + rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } NS_IMETHODIMP nsDOMDeviceStorage::Get(const nsAString& aPath, nsIDOMDOMRequest** aRetval) { ErrorResult rv; nsRefPtr<DOMRequest> request = Get(aPath, rv); @@ -2983,243 +3154,322 @@ nsDOMDeviceStorage::GetEditable(const ns request.forget(aRetval); return rv.ErrorCode(); } already_AddRefed<DOMRequest> nsDOMDeviceStorage::GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } nsRefPtr<DOMRequest> request = new DOMRequest(win); if (IsFullPath(aPath)) { nsString storagePath; nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); if (!ds) { nsCOMPtr<nsIRunnable> r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } ds->GetInternal(win, storagePath, request, aEditable); return request.forget(); } GetInternal(win, aPath, request, aEditable); return request.forget(); } void nsDOMDeviceStorage::GetInternal(nsPIDOMWindow *aWin, const nsAString& aPath, DOMRequest* aRequest, bool aEditable) { + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName, aPath); dsf->SetEditable(aEditable); nsCOMPtr<nsIRunnable> r; if (!dsf->IsSafePath()) { r = new PostErrorEvent(aRequest, POST_ERROR_EVENT_PERMISSION_DENIED); } else { r = new DeviceStorageRequest(aEditable ? DEVICE_STORAGE_REQUEST_WRITE : DEVICE_STORAGE_REQUEST_READ, aWin, mPrincipal, dsf, aRequest); } - NS_DispatchToMainThread(r); + DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(r); + MOZ_ASSERT(NS_SUCCEEDED(rv)); } NS_IMETHODIMP nsDOMDeviceStorage::Delete(const nsAString& aPath, nsIDOMDOMRequest** aRetval) { ErrorResult rv; nsRefPtr<DOMRequest> request = Delete(aPath, rv); request.forget(aRetval); return rv.ErrorCode(); } already_AddRefed<DOMRequest> nsDOMDeviceStorage::Delete(const nsAString& aPath, ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } nsRefPtr<DOMRequest> request = new DOMRequest(win); if (IsFullPath(aPath)) { nsString storagePath; nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); if (!ds) { nsCOMPtr<nsIRunnable> r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } ds->DeleteInternal(win, storagePath, request); return request.forget(); } DeleteInternal(win, aPath, request); return request.forget(); } void nsDOMDeviceStorage::DeleteInternal(nsPIDOMWindow *aWin, const nsAString& aPath, DOMRequest* aRequest) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsIRunnable> r; nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName, aPath); if (!dsf->IsSafePath()) { r = new PostErrorEvent(aRequest, POST_ERROR_EVENT_PERMISSION_DENIED); } else { r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_DELETE, aWin, mPrincipal, dsf, aRequest); } - NS_DispatchToMainThread(r); + DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(r); + MOZ_ASSERT(NS_SUCCEEDED(rv)); } NS_IMETHODIMP nsDOMDeviceStorage::FreeSpace(nsIDOMDOMRequest** aRetval) { ErrorResult rv; nsRefPtr<DOMRequest> request = FreeSpace(rv); request.forget(aRetval); return rv.ErrorCode(); } already_AddRefed<DOMRequest> nsDOMDeviceStorage::FreeSpace(ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } nsRefPtr<DOMRequest> request = new DOMRequest(win); nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName); nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FREE_SPACE, win, mPrincipal, dsf, request); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } NS_IMETHODIMP nsDOMDeviceStorage::UsedSpace(nsIDOMDOMRequest** aRetval) { ErrorResult rv; nsRefPtr<DOMRequest> request = UsedSpace(rv); request.forget(aRetval); return rv.ErrorCode(); } already_AddRefed<DOMRequest> nsDOMDeviceStorage::UsedSpace(ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } DebugOnly<DeviceStorageUsedSpaceCache*> usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet(); - NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null"); + MOZ_ASSERT(usedSpaceCache); nsRefPtr<DOMRequest> request = new DOMRequest(win); nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName); nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_USED_SPACE, win, mPrincipal, dsf, request); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } NS_IMETHODIMP nsDOMDeviceStorage::Available(nsIDOMDOMRequest** aRetval) { ErrorResult rv; nsRefPtr<DOMRequest> request = Available(rv); request.forget(aRetval); return rv.ErrorCode(); } already_AddRefed<DOMRequest> nsDOMDeviceStorage::Available(ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } nsRefPtr<DOMRequest> request = new DOMRequest(win); nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName); nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_AVAILABLE, win, mPrincipal, dsf, request); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } already_AddRefed<DOMRequest> nsDOMDeviceStorage::Format(ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } nsRefPtr<DOMRequest> request = new DOMRequest(win); nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName); nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_FORMAT, win, mPrincipal, dsf, request); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } return request.forget(); } NS_IMETHODIMP -nsDOMDeviceStorage::GetRootDirectoryForFile(const nsAString& aName, - nsIFile** aRootDirectory) +nsDOMDeviceStorage::CreateFileDescriptor(const nsAString& aPath, + DeviceStorageFileDescriptor* aDSFileDescriptor, + nsIDOMDOMRequest** aRequest) { - nsRefPtr<nsDOMDeviceStorage> ds; - - if (IsFullPath(aName)) { - nsString storagePath; - ds = GetStorage(aName, storagePath); - } else { - ds = this; + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aDSFileDescriptor); + + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); + if (!win) { + return NS_ERROR_UNEXPECTED; } - if (!ds || !ds->mRootDirectory) { + + DeviceStorageTypeChecker* typeChecker + = DeviceStorageTypeChecker::CreateOrGet(); + if (!typeChecker) { return NS_ERROR_FAILURE; } - return ds->mRootDirectory->Clone(aRootDirectory); + + nsCOMPtr<nsIRunnable> r; + nsresult rv; + + if (IsFullPath(aPath)) { + nsString storagePath; + nsRefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath); + if (!ds) { + nsRefPtr<DOMRequest> request = new DOMRequest(win); + r = new PostErrorEvent(request, POST_ERROR_EVENT_UNKNOWN); + rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + return rv; + } + request.forget(aRequest); + return NS_OK; + } + return ds->CreateFileDescriptor(storagePath, aDSFileDescriptor, aRequest); + } + + nsRefPtr<DOMRequest> request = new DOMRequest(win); + + nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, + mStorageName, + aPath); + if (!dsf->IsSafePath()) { + r = new PostErrorEvent(request, POST_ERROR_EVENT_PERMISSION_DENIED); + } else if (!typeChecker->Check(mStorageType, dsf->mFile)) { + r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE); + } else { + r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATEFD, + win, mPrincipal, dsf, request, + aDSFileDescriptor); + } + + rv = NS_DispatchToCurrentThread(r); + if (NS_FAILED(rv)) { + return rv; + } + request.forget(aRequest); + return NS_OK; } bool nsDOMDeviceStorage::Default() { nsString defaultStorageName; GetDefaultStorageName(mStorageType, defaultStorageName); return mStorageName.Equals(defaultStorageName); @@ -3389,17 +3639,17 @@ nsDOMDeviceStorage::Observe(nsISupports if (!vol) { return NS_OK; } nsString volName; vol->GetName(volName); DeviceStorageUsedSpaceCache* usedSpaceCache = DeviceStorageUsedSpaceCache::CreateOrGet(); - NS_ASSERTION(usedSpaceCache, "DeviceStorageUsedSpaceCache is null"); + MOZ_ASSERT(usedSpaceCache); usedSpaceCache->Invalidate(volName); if (!volName.Equals(mStorageName)) { // Not our volume - we can ignore. return NS_OK; } DeviceStorageFile dsf(mStorageType, mStorageName); @@ -3448,52 +3698,63 @@ nsDOMDeviceStorage::Notify(const char* a NS_IMETHODIMP nsDOMDeviceStorage::AddEventListener(const nsAString & aType, nsIDOMEventListener *aListener, bool aUseCapture, bool aWantsUntrusted, uint8_t aArgc) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { return NS_ERROR_UNEXPECTED; } nsRefPtr<DOMRequest> request = new DOMRequest(win); nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName); nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH, win, mPrincipal, dsf, request, this); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, aArgc); } void nsDOMDeviceStorage::AddEventListener(const nsAString & aType, EventListener *aListener, bool aUseCapture, const Nullable<bool>& aWantsUntrusted, ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } nsRefPtr<DOMRequest> request = new DOMRequest(win); nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mStorageName); nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH, win, mPrincipal, dsf, request, this); - NS_DispatchToMainThread(r); + nsresult rv = NS_DispatchToCurrentThread(r); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, aRv); } NS_IMETHODIMP nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType, nsIDOMEventListener *aListener, bool aUseCapture,
--- a/dom/devicestorage/nsDeviceStorage.h +++ b/dom/devicestorage/nsDeviceStorage.h @@ -47,17 +47,18 @@ enum DeviceStorageRequestType { DEVICE_STORAGE_REQUEST_READ, DEVICE_STORAGE_REQUEST_WRITE, DEVICE_STORAGE_REQUEST_CREATE, DEVICE_STORAGE_REQUEST_DELETE, DEVICE_STORAGE_REQUEST_WATCH, DEVICE_STORAGE_REQUEST_FREE_SPACE, DEVICE_STORAGE_REQUEST_USED_SPACE, DEVICE_STORAGE_REQUEST_AVAILABLE, - DEVICE_STORAGE_REQUEST_FORMAT + DEVICE_STORAGE_REQUEST_FORMAT, + DEVICE_STORAGE_REQUEST_CREATEFD }; class DeviceStorageUsedSpaceCache MOZ_FINAL { public: static DeviceStorageUsedSpaceCache* CreateOrGet(); DeviceStorageUsedSpaceCache(); @@ -85,27 +86,27 @@ public: } private: DeviceStorageUsedSpaceCache* mCache; nsString mStorageName; }; void Invalidate(const nsAString& aStorageName) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(mIOThread, "Null mIOThread!"); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mIOThread); nsRefPtr<InvalidateRunnable> r = new InvalidateRunnable(this, aStorageName); mIOThread->Dispatch(r, NS_DISPATCH_NORMAL); } void Dispatch(nsIRunnable* aRunnable) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(mIOThread, "Null mIOThread!"); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mIOThread); mIOThread->Dispatch(aRunnable, NS_DISPATCH_NORMAL); } nsresult AccumUsedSizes(const nsAString& aStorageName, uint64_t* aPictureSize, uint64_t* aVideosSize, uint64_t* aMusicSize, uint64_t* aTotalSize);
--- a/dom/interfaces/devicestorage/nsIDOMDeviceStorage.idl +++ b/dom/interfaces/devicestorage/nsIDOMDeviceStorage.idl @@ -6,17 +6,22 @@ #include "nsIDOMEventTarget.idl" interface nsIDOMBlob; interface nsIDOMDOMRequest; interface nsIDOMDOMCursor; interface nsIDOMDeviceStorageChangeEvent; interface nsIDOMEventListener; interface nsIFile; -[scriptable, uuid(7c1b2305-0f14-4c07-8a8a-359eeb850068), builtinclass] +%{C++ +class DeviceStorageFileDescriptor; +%} +[ptr] native DeviceStorageFdPtr(DeviceStorageFileDescriptor); + +[scriptable, uuid(8b724547-3c78-4244-969a-f00a1f4ae0c3), builtinclass] interface nsIDOMDeviceStorage : nsIDOMEventTarget { [implicit_jscontext] attribute jsval onchange; nsIDOMDOMRequest add(in nsIDOMBlob aBlob); nsIDOMDOMRequest addNamed(in nsIDOMBlob aBlob, in DOMString aName); nsIDOMDOMRequest get([Null(Stringify)] in DOMString aName); nsIDOMDOMRequest getEditable([Null(Stringify)] in DOMString aName); @@ -29,10 +34,13 @@ interface nsIDOMDeviceStorage : nsIDOMEv // Note that the storageName is just a name (like sdcard), and doesn't // include any path information. readonly attribute DOMString storageName; // Determines if this storage area is the one which will be used by default // for storing new files. readonly attribute bool default; - [noscript] nsIFile getRootDirectoryForFile(in DOMString aName); + // Note: aFileDescriptor is reference counted, which is why we're using + // a pointer rather than a reference. + [noscript] nsIDOMDOMRequest createFileDescriptor(in DOMString aName, + in DeviceStorageFdPtr aFileDescriptor); };
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -89,16 +89,23 @@ struct DeviceStorageFormatParams struct DeviceStorageAddParams { nsString type; nsString storageName; nsString relpath; PBlob blob; }; +struct DeviceStorageCreateFdParams +{ + nsString type; + nsString storageName; + nsString relpath; +}; + struct DeviceStorageGetParams { nsString type; nsString storageName; nsString rootDir; nsString relpath; }; @@ -115,16 +122,17 @@ struct DeviceStorageEnumerationParams nsString storageName; nsString rootdir; uint64_t since; }; union DeviceStorageParams { DeviceStorageAddParams; + DeviceStorageCreateFdParams; DeviceStorageGetParams; DeviceStorageDeleteParams; DeviceStorageEnumerationParams; DeviceStorageFreeSpaceParams; DeviceStorageUsedSpaceParams; DeviceStorageAvailableParams; DeviceStorageFormatParams; };
--- a/mobile/android/base/FormAssistPopup.java +++ b/mobile/android/base/FormAssistPopup.java @@ -46,17 +46,22 @@ public class FormAssistPopup extends Rel private TextView mValidationMessageText; private ImageView mValidationMessageArrow; private ImageView mValidationMessageArrowInverted; private double mX; private double mY; private double mW; private double mH; - private boolean mIsAutoComplete = true; + + private enum PopupType { + AUTOCOMPLETE, + VALIDATIONMESSAGE; + } + private PopupType mPopupType; private static int sAutoCompleteMinWidth = 0; private static int sAutoCompleteRowHeight = 0; private static int sValidationMessageHeight = 0; private static int sValidationTextMarginTop = 0; private static RelativeLayout.LayoutParams sValidationTextLayoutNormal; private static RelativeLayout.LayoutParams sValidationTextLayoutInverted; @@ -203,17 +208,18 @@ public class FormAssistPopup extends Rel mW = rect.getDouble("w"); mH = rect.getDouble("h"); } catch (JSONException e) { // Bail if we can't get the correct dimensions for the popup. Log.e(LOGTAG, "Error getting FormAssistPopup dimensions", e); return false; } - mIsAutoComplete = isAutoComplete; + mPopupType = (isAutoComplete ? + PopupType.AUTOCOMPLETE : PopupType.VALIDATIONMESSAGE); return true; } private void positionAndShowPopup() { positionAndShowPopup(GeckoAppShell.getLayerView().getViewportMetrics()); } private void positionAndShowPopup(ImmutableViewportMetrics aMetrics) { @@ -222,19 +228,19 @@ public class FormAssistPopup extends Rel // Don't show the form assist popup when using fullscreen VKB InputMethodManager imm = (InputMethodManager) GeckoAppShell.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); if (imm.isFullscreenMode()) return; // Hide/show the appropriate popup contents if (mAutoCompleteList != null) - mAutoCompleteList.setVisibility(mIsAutoComplete ? VISIBLE : GONE); + mAutoCompleteList.setVisibility((mPopupType == PopupType.AUTOCOMPLETE) ? VISIBLE : GONE); if (mValidationMessage != null) - mValidationMessage.setVisibility(mIsAutoComplete ? GONE : VISIBLE); + mValidationMessage.setVisibility((mPopupType == PopupType.AUTOCOMPLETE) ? GONE : VISIBLE); if (sAutoCompleteMinWidth == 0) { Resources res = mContext.getResources(); sAutoCompleteMinWidth = (int) (res.getDimension(R.dimen.autocomplete_min_width)); sAutoCompleteRowHeight = (int) (res.getDimension(R.dimen.autocomplete_row_height)); sValidationMessageHeight = (int) (res.getDimension(R.dimen.validation_message_height)); } @@ -250,38 +256,38 @@ public class FormAssistPopup extends Rel int popupWidth = RelativeLayout.LayoutParams.FILL_PARENT; int popupLeft = left < 0 ? 0 : left; FloatSize viewport = aMetrics.getSize(); // For autocomplete suggestions, if the input is smaller than the screen-width, // shrink the popup's width. Otherwise, keep it as FILL_PARENT. - if (mIsAutoComplete && (left + width) < viewport.width) { + if ((mPopupType == PopupType.AUTOCOMPLETE) && (left + width) < viewport.width) { popupWidth = left < 0 ? left + width : width; // Ensure the popup has a minimum width. if (popupWidth < sAutoCompleteMinWidth) { popupWidth = sAutoCompleteMinWidth; // Move the popup to the left if there isn't enough room for it. if ((popupLeft + popupWidth) > viewport.width) popupLeft = (int) (viewport.width - popupWidth); } } int popupHeight; - if (mIsAutoComplete) + if (mPopupType == PopupType.AUTOCOMPLETE) popupHeight = sAutoCompleteRowHeight * mAutoCompleteList.getAdapter().getCount(); else popupHeight = sValidationMessageHeight; int popupTop = top + height; - if (!mIsAutoComplete) { + if (mPopupType == PopupType.VALIDATIONMESSAGE) { mValidationMessageText.setLayoutParams(sValidationTextLayoutNormal); mValidationMessageArrow.setVisibility(VISIBLE); mValidationMessageArrowInverted.setVisibility(GONE); } // If the popup doesn't fit below the input box, shrink its height, or // see if we can place it above the input instead. if ((popupTop + popupHeight) > viewport.height) { @@ -294,17 +300,17 @@ public class FormAssistPopup extends Rel // No shrinking needed to fit on top. popupTop = (top - popupHeight); } else { // Shrink to available space on top. popupTop = 0; popupHeight = top; } - if (!mIsAutoComplete) { + if (mPopupType == PopupType.VALIDATIONMESSAGE) { mValidationMessageText.setLayoutParams(sValidationTextLayoutInverted); mValidationMessageArrow.setVisibility(GONE); mValidationMessageArrowInverted.setVisibility(VISIBLE); } } } RelativeLayout.LayoutParams layoutParams =
--- a/security/sandbox/linux/seccomp_filter.h +++ b/security/sandbox/linux/seccomp_filter.h @@ -153,17 +153,16 @@ ALLOW_SYSCALL(lstat), \ ALLOW_SYSCALL(mmap), \ ALLOW_SYSCALL(openat), \ ALLOW_SYSCALL(fcntl), \ ALLOW_SYSCALL(fstat), \ ALLOW_SYSCALL(readlink), \ ALLOW_SYSCALL(getsockname), \ ALLOW_SYSCALL(recvmsg), \ - ALLOW_SYSCALL(uname), \ /* duplicate rt_sigaction in SECCOMP_WHITELIST_PROFILING */ \ ALLOW_SYSCALL(rt_sigaction), \ ALLOW_SYSCALL(getuid), \ ALLOW_SYSCALL(geteuid), \ ALLOW_SYSCALL(mkdir), \ ALLOW_SYSCALL(getcwd), \ ALLOW_SYSCALL(readahead), \ ALLOW_SYSCALL(pread64), \ @@ -263,11 +262,14 @@ SECCOMP_WHITELIST_B2G_LOW \ /* Always last and always OK calls */ \ SECCOMP_WHITELIST_ARCH_LAST \ /* restart_syscall is called internally, generally when debugging */ \ ALLOW_SYSCALL(restart_syscall), \ /* linux desktop is not as performance critical as B2G */ \ /* we can place desktop syscalls at the end */ \ SECCOMP_WHITELIST_DESKTOP_LINUX \ + /* nsSystemInfo uses uname (and we cache an instance, so */ \ + /* the info remains present even if we block the syscall) */ \ + ALLOW_SYSCALL(uname), \ ALLOW_SYSCALL(exit_group), \ ALLOW_SYSCALL(exit)