зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
444ee13e14
|
@ -175,8 +175,7 @@ CustomizeMode.prototype = {
|
|||
|
||||
async _updateThemeButtonIcon() {
|
||||
let lwthemeButton = this.$("customization-lwtheme-button");
|
||||
let lwthemeIcon = this.document.getAnonymousElementByAttribute(lwthemeButton,
|
||||
"class", "button-icon");
|
||||
let lwthemeIcon = lwthemeButton.icon;
|
||||
let theme = (await AddonManager.getAddonsByTypes(["theme"])).find(addon => addon.isActive);
|
||||
lwthemeIcon.style.backgroundImage = theme ? "url(" + theme.iconURL + ")" : "";
|
||||
},
|
||||
|
|
|
@ -15,8 +15,7 @@ add_task(async function() {
|
|||
"Reset button should start out disabled");
|
||||
|
||||
let themesButton = document.getElementById("customization-lwtheme-button");
|
||||
let themesButtonIcon = document.getAnonymousElementByAttribute(themesButton,
|
||||
"class", "button-icon");
|
||||
let themesButtonIcon = themesButton.icon;
|
||||
let iconURL = themesButtonIcon.style.backgroundImage;
|
||||
// If we've run other tests before, we might have set the image to the
|
||||
// default theme's icon explicitly, otherwise it might be empty, in which
|
||||
|
|
|
@ -27,7 +27,10 @@
|
|||
</vbox>
|
||||
<vbox>
|
||||
<hbox flex="1">
|
||||
<button id="containersAdd" oncommand="gContainersPane.onAddButtonCommand();" data-l10n-id="containers-add-button"/>
|
||||
<button id="containersAdd"
|
||||
is="highlightable-button"
|
||||
oncommand="gContainersPane.onAddButtonCommand();"
|
||||
data-l10n-id="containers-add-button"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
|
|
|
@ -5,6 +5,20 @@
|
|||
/* import-globals-from extensionControlled.js */
|
||||
/* import-globals-from preferences.js */
|
||||
|
||||
// A tweak to the standard <button> CE to use textContent on the <label>
|
||||
// inside the button, which allows the text to be highlighted when the user
|
||||
// is searching.
|
||||
|
||||
const MozButton = customElements.get("button");
|
||||
class HighlightableButton extends MozButton {
|
||||
static get inheritedAttributes() {
|
||||
return Object.assign({}, super.inheritedAttributes, {
|
||||
".button-text": "text=label,accesskey,crop",
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define("highlightable-button", HighlightableButton, {extends: "button"});
|
||||
|
||||
var gSearchResultsPane = {
|
||||
listSearchTooltips: new Set(),
|
||||
listSearchMenuitemIndicators: new Set(),
|
||||
|
@ -332,6 +346,7 @@ var gSearchResultsPane = {
|
|||
async searchWithinNode(nodeObject, searchPhrase) {
|
||||
let matchesFound = false;
|
||||
if (nodeObject.childElementCount == 0 ||
|
||||
nodeObject.tagName == "button" ||
|
||||
nodeObject.tagName == "label" ||
|
||||
nodeObject.tagName == "description" ||
|
||||
nodeObject.tagName == "menulist") {
|
||||
|
@ -404,8 +419,7 @@ var gSearchResultsPane = {
|
|||
this.listSearchMenuitemIndicators.add(menulist);
|
||||
}
|
||||
|
||||
if ((nodeObject.tagName == "button" ||
|
||||
nodeObject.tagName == "menulist" ||
|
||||
if ((nodeObject.tagName == "menulist" ||
|
||||
nodeObject.tagName == "menuitem") &&
|
||||
(labelResult || valueResult || keywordsResult)) {
|
||||
nodeObject.setAttribute("highlightable", "true");
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
data-category="paneHome">
|
||||
<html:h1 style="-moz-box-flex: 1;" data-l10n-id="pane-home-title"/>
|
||||
<button id="restoreDefaultHomePageBtn"
|
||||
is="highlightable-button"
|
||||
class="homepage-button check-home-page-controlled"
|
||||
data-preference-related="browser.startup.homepage"
|
||||
data-l10n-id="home-restore-defaults"
|
||||
|
@ -51,6 +52,7 @@
|
|||
autocompletesearch="unifiedcomplete" />
|
||||
<hbox class="homepage-buttons">
|
||||
<button id="useCurrentBtn"
|
||||
is="highlightable-button"
|
||||
flex="1"
|
||||
class="homepage-button check-home-page-controlled"
|
||||
data-l10n-id="use-current-pages"
|
||||
|
@ -58,6 +60,7 @@
|
|||
disabled="true"
|
||||
preference="pref.browser.homepage.disable_button.current_page"/>
|
||||
<button id="useBookmarkBtn"
|
||||
is="highlightable-button"
|
||||
flex="1"
|
||||
class="homepage-button check-home-page-controlled"
|
||||
data-l10n-id="choose-bookmark"
|
||||
|
@ -86,6 +89,7 @@
|
|||
align="center" hidden="true" class="extension-controlled">
|
||||
<description control="disableHomePageExtension" flex="1" />
|
||||
<button id="disableHomePageExtension"
|
||||
is="highlightable-button"
|
||||
class="extension-controlled-button accessory-button"
|
||||
data-l10n-id="disable-extension" />
|
||||
</hbox>
|
||||
|
@ -93,6 +97,7 @@
|
|||
align="center" hidden="true" class="extension-controlled">
|
||||
<description control="disableNewTabExtension" flex="1" />
|
||||
<button id="disableNewTabExtension"
|
||||
is="highlightable-button"
|
||||
class="extension-controlled-button accessory-button"
|
||||
data-l10n-id="disable-extension" />
|
||||
</hbox>
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
<image class="face-sad"/>
|
||||
<label id="isNotDefaultLabel" flex="1" data-l10n-id="is-not-default"/>
|
||||
<button id="setDefaultButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="set-as-my-default-browser"
|
||||
preference="pref.general.disable_button.default_browser"/>
|
||||
|
@ -95,6 +96,7 @@
|
|||
align="center" class="extension-controlled">
|
||||
<description control="disableContainersExtension" flex="1" />
|
||||
<button id="disableContainersExtension"
|
||||
is="highlightable-button"
|
||||
class="extension-controlled-button accessory-button"
|
||||
data-l10n-id="disable-extension" />
|
||||
</hbox>
|
||||
|
@ -109,6 +111,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="browserContainersSettings"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="browser-containers-settings"
|
||||
search-l10n-ids="containers-add-button.label,
|
||||
|
@ -176,6 +179,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="advancedFonts"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
icon="select-font"
|
||||
data-l10n-id="advanced-fonts"
|
||||
|
@ -248,6 +252,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="colors"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
icon="select-color"
|
||||
data-l10n-id="colors-settings"
|
||||
|
@ -280,6 +285,7 @@
|
|||
<menupopup/>
|
||||
</menulist>
|
||||
<button id="manageBrowserLanguagesButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="manage-browser-languages-button"
|
||||
oncommand="gMainPane.showBrowserLanguages({search: false})"/>
|
||||
|
@ -295,6 +301,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="chooseLanguage"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="choose-button"
|
||||
search-l10n-ids="
|
||||
|
@ -324,6 +331,7 @@
|
|||
</hbox>
|
||||
</hbox>
|
||||
<button id="translateButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="translate-exceptions"/>
|
||||
</hbox>
|
||||
|
@ -357,6 +365,7 @@
|
|||
readonly="true"
|
||||
aria-labelledby="saveTo"/>
|
||||
<button id="chooseFolder"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="download-choose-folder"/>
|
||||
</hbox>
|
||||
|
@ -431,6 +440,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<vbox>
|
||||
<button id="showUpdateHistory"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="update-history"
|
||||
preference="app.update.disable_button.showUpdateHistory"
|
||||
|
@ -447,18 +457,21 @@
|
|||
<hbox id="checkForUpdates" align="start">
|
||||
<spacer flex="1"/>
|
||||
<button id="checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="update-checkForUpdatesButton"
|
||||
oncommand="gAppUpdater.checkForUpdates();"/>
|
||||
</hbox>
|
||||
<hbox id="downloadAndInstall" align="start">
|
||||
<spacer flex="1"/>
|
||||
<button id="downloadAndInstallButton"
|
||||
is="highlightable-button"
|
||||
oncommand="gAppUpdater.startDownload();"/>
|
||||
<!-- label and accesskey will be filled by JS -->
|
||||
</hbox>
|
||||
<hbox id="apply" align="start">
|
||||
<spacer flex="1"/>
|
||||
<button id="updateButton"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="update-updateButton"
|
||||
oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
|
||||
</hbox>
|
||||
|
@ -467,6 +480,7 @@
|
|||
<label data-l10n-id="update-checkingForUpdates"></label>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="downloading" align="start" data-l10n-id="update-downloading">
|
||||
|
@ -483,12 +497,14 @@
|
|||
</label>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
oncommand="gAppUpdater.checkForUpdates();"/>
|
||||
</hbox>
|
||||
<hbox id="policyDisabled" align="start">
|
||||
<label data-l10n-id="update-adminDisabled"></label>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="noUpdatesFound" align="start">
|
||||
|
@ -496,12 +512,14 @@
|
|||
<label data-l10n-id="update-noUpdatesFound"></label>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
oncommand="gAppUpdater.checkForUpdates();"/>
|
||||
</hbox>
|
||||
<hbox id="otherInstanceHandlingUpdates" align="start">
|
||||
<label data-l10n-id="update-otherInstanceHandlingUpdates"></label>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="manualUpdate" align="start">
|
||||
|
@ -511,6 +529,7 @@
|
|||
</description>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="unsupportedSystem" align="start">
|
||||
|
@ -519,12 +538,14 @@
|
|||
</description>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-checkForUpdatesButton"
|
||||
is="highlightable-button"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
<hbox id="restarting" align="start">
|
||||
<image class="update-throbber"/><label data-l10n-id="update-restarting"></label>
|
||||
<spacer flex="1"/>
|
||||
<button data-l10n-id="update-updateButton"
|
||||
is="highlightable-button"
|
||||
disabled="true"/>
|
||||
</hbox>
|
||||
</deck>
|
||||
|
@ -673,6 +694,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="connectionSettings"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
icon="network"
|
||||
data-l10n-id="network-proxy-connection-settings"
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="trackingProtectionExceptions"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
flex="1"
|
||||
data-l10n-id="tracking-manage-exceptions"
|
||||
|
@ -57,6 +58,7 @@
|
|||
data-l10n-id="content-blocking-setting-standard"
|
||||
flex="1"/>
|
||||
<button id="standardArrow"
|
||||
is="highlightable-button"
|
||||
class="arrowhead default-content-blocking-ui"
|
||||
data-l10n-id="content-blocking-expand-section"
|
||||
aria-expanded="false"/>
|
||||
|
@ -116,6 +118,7 @@
|
|||
<vbox>
|
||||
<spacer flex="1"/>
|
||||
<button class="accessory-button reload-tabs-button"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="content-blocking-reload-tabs-button"/>
|
||||
<spacer flex="1"/>
|
||||
</vbox>
|
||||
|
@ -131,6 +134,7 @@
|
|||
data-l10n-id="content-blocking-setting-strict"
|
||||
flex="1"/>
|
||||
<button id="strictArrow"
|
||||
is="highlightable-button"
|
||||
class="arrowhead"
|
||||
data-l10n-id="content-blocking-expand-section"
|
||||
aria-expanded="false"/>
|
||||
|
@ -190,6 +194,7 @@
|
|||
<vbox>
|
||||
<spacer flex="1"/>
|
||||
<button class="accessory-button reload-tabs-button"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="content-blocking-reload-tabs-button"/>
|
||||
<spacer flex="1"/>
|
||||
</vbox>
|
||||
|
@ -217,6 +222,7 @@
|
|||
data-l10n-id="content-blocking-setting-custom"
|
||||
flex="1"/>
|
||||
<button id="customArrow"
|
||||
is="highlightable-button"
|
||||
class="arrowhead"
|
||||
data-l10n-id="content-blocking-expand-section"
|
||||
aria-expanded="false"/>
|
||||
|
@ -228,6 +234,7 @@
|
|||
align="center" hidden="true" class="extension-controlled">
|
||||
<description control="contentBlockingDisableTrackingProtectionExtension" flex="1"/>
|
||||
<button id="contentBlockingDisableTrackingProtectionExtension"
|
||||
is="highlightable-button"
|
||||
class="extension-controlled-button accessory-button"
|
||||
data-l10n-id="disable-extension" hidden="true"/>
|
||||
</hbox>
|
||||
|
@ -306,6 +313,7 @@
|
|||
<vbox>
|
||||
<spacer flex="1"/>
|
||||
<button class="accessory-button reload-tabs-button"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="content-blocking-reload-tabs-button"/>
|
||||
<spacer flex="1"/>
|
||||
</vbox>
|
||||
|
@ -368,6 +376,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="clearSiteDataButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
icon="clear"
|
||||
search-l10n-ids="clear-site-data-cookies-empty.label, clear-site-data-cache-empty.label"
|
||||
|
@ -375,6 +384,7 @@
|
|||
</hbox>
|
||||
<hbox>
|
||||
<button id="siteDataSettings"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="sitedata-settings"
|
||||
search-l10n-ids="
|
||||
|
@ -388,6 +398,7 @@
|
|||
</hbox>
|
||||
<hbox>
|
||||
<button id="cookieExceptions"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="sitedata-cookies-permissions"
|
||||
preference="pref.privacy.disable_button.cookie_exceptions"
|
||||
|
@ -420,6 +431,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="passwordExceptions"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="forms-exceptions"
|
||||
preference="pref.privacy.disable_button.view_passwords_exceptions"
|
||||
|
@ -434,6 +446,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="showPasswords"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="forms-saved-logins"
|
||||
search-l10n-ids="forms-saved-logins.label"
|
||||
|
@ -448,6 +461,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="changeMasterPassword"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="forms-master-pw-change"/>
|
||||
</hbox>
|
||||
|
@ -537,12 +551,14 @@
|
|||
</deck>
|
||||
<vbox id="historyButtons" align="end">
|
||||
<button id="clearHistoryButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
icon="clear"
|
||||
data-l10n-id="history-clear-button"/>
|
||||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="clearDataSettings"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="history-clear-on-close-settings"
|
||||
search-l10n-ids="
|
||||
|
@ -599,6 +615,7 @@
|
|||
</description>
|
||||
<hbox pack="end">
|
||||
<button id="locationSettingsButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-location-settings"
|
||||
search-l10n-ids="
|
||||
|
@ -622,6 +639,7 @@
|
|||
</description>
|
||||
<hbox pack="end">
|
||||
<button id="cameraSettingsButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-camera-settings"
|
||||
search-l10n-ids="
|
||||
|
@ -645,6 +663,7 @@
|
|||
</description>
|
||||
<hbox pack="end">
|
||||
<button id="microphoneSettingsButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-microphone-settings"
|
||||
search-l10n-ids="
|
||||
|
@ -674,6 +693,7 @@
|
|||
</description>
|
||||
<hbox pack="end">
|
||||
<button id="notificationSettingsButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-notification-settings"
|
||||
search-l10n-ids="
|
||||
|
@ -703,6 +723,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="autoplayMediaPolicyButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-block-autoplay-media-exceptions"
|
||||
search-l10n-ids="permissions-address,
|
||||
|
@ -723,6 +744,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="popupPolicyButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-block-popups-exceptions"
|
||||
search-l10n-ids="
|
||||
|
@ -744,6 +766,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="addonExceptions"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="permissions-addon-exceptions"
|
||||
search-l10n-ids="
|
||||
|
@ -895,6 +918,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox pack="end">
|
||||
<button id="viewCertificatesButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="certs-view"
|
||||
preference="security.disable_button.openCertManager"
|
||||
|
@ -917,6 +941,7 @@
|
|||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox pack="end">
|
||||
<button id="viewSecurityDevicesButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="certs-devices"
|
||||
preference="security.disable_button.openDeviceManager"
|
||||
|
|
|
@ -67,10 +67,12 @@
|
|||
|
||||
<hbox>
|
||||
<button id="restoreDefaultSearchEngines"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="search-restore-default"
|
||||
/>
|
||||
<spacer flex="1"/>
|
||||
<button id="removeEngineButton"
|
||||
is="highlightable-button"
|
||||
class="searchEngineAction"
|
||||
data-l10n-id="search-remove-engine"
|
||||
disabled="true"
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<label id="signedOutAccountBoxTitle"><html:h2 data-l10n-id="sync-signedout-account-title"/></label>
|
||||
</hbox>
|
||||
<button id="noFxaSignIn"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="sync-signedout-account-signin"/>
|
||||
</hbox>
|
||||
|
@ -87,6 +88,7 @@
|
|||
</label>
|
||||
<label id="fxaEmailAddress" flex="1" crop="end"/>
|
||||
<button id="fxaUnlinkButton"
|
||||
is="highlightable-button"
|
||||
class="accessory-button"
|
||||
data-l10n-id="sync-disconnect"/>
|
||||
</hbox>
|
||||
|
@ -112,8 +114,12 @@
|
|||
data-l10n-args='{"email": ""}'/>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="verifyFxaAccount" data-l10n-id="sync-resend-verification"/>
|
||||
<button id="unverifiedUnlinkFxaAccount" data-l10n-id="sync-remove-account"/>
|
||||
<button id="verifyFxaAccount"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="sync-resend-verification"/>
|
||||
<button id="unverifiedUnlinkFxaAccount"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="sync-remove-account"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -132,8 +138,12 @@
|
|||
data-l10n-args='{"email": ""}'/>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="rejectReSignIn" data-l10n-id="sync-sign-in"/>
|
||||
<button id="rejectUnlinkFxaAccount" data-l10n-id="sync-remove-account"/>
|
||||
<button id="rejectReSignIn"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="sync-sign-in"/>
|
||||
<button id="rejectUnlinkFxaAccount"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="sync-remove-account"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -174,11 +184,14 @@
|
|||
<hbox id="fxaDeviceName">
|
||||
<textbox id="fxaSyncComputerName" flex="1" disabled="true"/>
|
||||
<button id="fxaChangeDeviceName"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="sync-device-name-change"/>
|
||||
<button id="fxaCancelChangeDeviceName"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="sync-device-name-cancel"
|
||||
hidden="true"/>
|
||||
<button id="fxaSaveChangeDeviceName"
|
||||
is="highlightable-button"
|
||||
data-l10n-id="sync-device-name-save"
|
||||
hidden="true"/>
|
||||
</hbox>
|
||||
|
|
|
@ -49,10 +49,12 @@
|
|||
<spacer flex="1"/>
|
||||
<hbox class="actionButtons" align="right" flex="1">
|
||||
<button id="butCancel"
|
||||
is="highlightable-button"
|
||||
oncommand="close(event);"
|
||||
class="syncDisconnectButton"
|
||||
data-l10n-id="sync-disconnect-cancel"/>
|
||||
<button id="butDisconnect"
|
||||
is="highlightable-button"
|
||||
oncommand="gSyncDisconnectDialog.accept(event);"
|
||||
class="syncDisconnectButton"
|
||||
data-l10n-id="sync-disconnect-confirm-disconnect"/>
|
||||
|
|
|
@ -79,7 +79,7 @@ FormAutofillPreferences.prototype = {
|
|||
let addressAutofillCheckboxGroup = document.createXULElement("hbox");
|
||||
let addressAutofillCheckbox = document.createXULElement("checkbox");
|
||||
let addressAutofillLearnMore = document.createXULElement("label", {is: "text-link"});
|
||||
let savedAddressesBtn = document.createXULElement("button");
|
||||
let savedAddressesBtn = document.createXULElement("button", {is: "highlightable-button"});
|
||||
// Wrappers are used to properly compute the search tooltip positions
|
||||
let savedAddressesBtnWrapper = document.createXULElement("hbox");
|
||||
let savedCreditCardsBtnWrapper = document.createXULElement("hbox");
|
||||
|
@ -138,7 +138,7 @@ FormAutofillPreferences.prototype = {
|
|||
let creditCardAutofillCheckboxGroup = document.createXULElement("hbox");
|
||||
let creditCardAutofillCheckbox = document.createXULElement("checkbox");
|
||||
let creditCardAutofillLearnMore = document.createXULElement("label", {is: "text-link"});
|
||||
let savedCreditCardsBtn = document.createXULElement("button");
|
||||
let savedCreditCardsBtn = document.createXULElement("button", {is: "highlightable-button"});
|
||||
savedCreditCardsBtn.className = "accessory-button";
|
||||
creditCardAutofillCheckbox.className = "tail-with-learn-more";
|
||||
creditCardAutofillLearnMore.className = "learnMore";
|
||||
|
|
|
@ -7,7 +7,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=683852
|
|||
<window title="Mozilla Bug 683852"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<button value="testbutton" id="testbutton"/>
|
||||
<xbl:bindings xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gaktekeeper/there.is.only.xul">
|
||||
<xbl:binding id="test">
|
||||
<xbl:content><xul:box anonid="xbl-anon">Anonymous</xul:box></xbl:content>
|
||||
</xbl:binding>
|
||||
</xbl:bindings>
|
||||
<box id="xbl-host" style="-moz-binding: url(#test)"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=683852"
|
||||
|
@ -25,14 +32,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=683852
|
|||
function startTest() {
|
||||
is(document.contains(document), true, "Document should contain itself!");
|
||||
|
||||
var tb = document.getElementById("testbutton");
|
||||
is(document.contains(tb), true, "Document should contain element in it!");
|
||||
is(tb.contains(tb), true, "Element should contain itself.")
|
||||
var anon = document.getAnonymousElementByAttribute(tb, "anonid", "button-box");
|
||||
let box = document.getElementById("xbl-host");
|
||||
is(document.contains(box), true, "Document should contain element in it!");
|
||||
is(box.contains(box), true, "Element should contain itself.")
|
||||
let anon = document.getAnonymousElementByAttribute(box, "anonid", "xbl-anon");
|
||||
is(document.contains(anon), false, "Document should not contain anonymous element in it!");
|
||||
is(tb.contains(anon), false, "Element should not contain anonymous element in it!");
|
||||
is(box.contains(anon), false, "Element should not contain anonymous element in it!");
|
||||
is(anon.contains(anon), true, "Anonymous element should contain itself.")
|
||||
is(document.documentElement.contains(tb), true, "Element should contain element in it!");
|
||||
is(document.documentElement.contains(box), true, "Element should contain element in it!");
|
||||
is(document.contains(document.createElement("foo")), false, "Document shouldn't contain element which is't in the document");
|
||||
is(document.contains(document.createTextNode("foo")), false, "Document shouldn't contain text node which is't in the document");
|
||||
|
||||
|
|
Двоичные данные
dom/localstorage/test/unit/corruptedDatabase_profile.zip
Двоичные данные
dom/localstorage/test/unit/corruptedDatabase_profile.zip
Двоичный файл не отображается.
|
@ -223,6 +223,8 @@ enum AppId {
|
|||
#define LS_ARCHIVE_FILE_NAME "ls-archive.sqlite"
|
||||
#define LS_ARCHIVE_TMP_FILE_NAME "ls-archive-tmp.sqlite"
|
||||
|
||||
const uint32_t kLocalStorageArchiveVersion = 1;
|
||||
|
||||
const char kProfileDoChangeTopic[] = "profile-do-change";
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -325,6 +327,158 @@ nsresult CreateWebAppsStoreConnection(nsIFile* aWebAppsStoreFile,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult GetLocalStorageArchiveFile(const nsAString& aDirectoryPath,
|
||||
nsIFile** aLsArchiveFile) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(!aDirectoryPath.IsEmpty());
|
||||
MOZ_ASSERT(aLsArchiveFile);
|
||||
|
||||
nsCOMPtr<nsIFile> lsArchiveFile;
|
||||
nsresult rv =
|
||||
NS_NewLocalFile(aDirectoryPath, false, getter_AddRefs(lsArchiveFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
lsArchiveFile.forget(aLsArchiveFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult GetLocalStorageArchiveTmpFile(const nsAString& aDirectoryPath,
|
||||
nsIFile** aLsArchiveTmpFile) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(!aDirectoryPath.IsEmpty());
|
||||
MOZ_ASSERT(aLsArchiveTmpFile);
|
||||
|
||||
nsCOMPtr<nsIFile> lsArchiveTmpFile;
|
||||
nsresult rv =
|
||||
NS_NewLocalFile(aDirectoryPath, false, getter_AddRefs(lsArchiveTmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveTmpFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_TMP_FILE_NAME));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
lsArchiveTmpFile.forget(aLsArchiveTmpFile);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult InitializeLocalStorageArchive(mozIStorageConnection* aConnection,
|
||||
uint32_t aVersion) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE database(version INTEGER NOT NULL DEFAULT 0);"));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = aConnection->CreateStatement(
|
||||
NS_LITERAL_CSTRING("INSERT INTO database (version) VALUES (:version)"),
|
||||
getter_AddRefs(stmt));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("version"), aVersion);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult IsLocalStorageArchiveInitialized(mozIStorageConnection* aConnection,
|
||||
bool& aInitialized) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
bool exists;
|
||||
nsresult rv =
|
||||
aConnection->TableExists(NS_LITERAL_CSTRING("database"), &exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aInitialized = exists;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult LoadLocalStorageArchiveVersion(mozIStorageConnection* aConnection,
|
||||
uint32_t& aVersion) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = aConnection->CreateStatement(
|
||||
NS_LITERAL_CSTRING("SELECT version FROM database"), getter_AddRefs(stmt));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool hasResult;
|
||||
rv = stmt->ExecuteStep(&hasResult);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!hasResult)) {
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
int32_t version;
|
||||
rv = stmt->GetInt32(0, &version);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aVersion = version;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
nsresult SaveLocalStorageArchiveVersion(mozIStorageConnection* aConnection,
|
||||
uint32_t aVersion) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = aConnection->CreateStatement(
|
||||
NS_LITERAL_CSTRING("UPDATE database SET version = :version;"),
|
||||
getter_AddRefs(stmt));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("version"), aVersion);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = stmt->Execute();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* Quota manager class declarations
|
||||
******************************************************************************/
|
||||
|
@ -4553,13 +4707,8 @@ nsresult QuotaManager::MaybeRemoveLocalStorageData() {
|
|||
|
||||
// Cleanup the tmp file first, if there's any.
|
||||
nsCOMPtr<nsIFile> lsArchiveTmpFile;
|
||||
nsresult rv =
|
||||
NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveTmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveTmpFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_TMP_FILE_NAME));
|
||||
nsresult rv = GetLocalStorageArchiveTmpFile(mStoragePath,
|
||||
getter_AddRefs(lsArchiveTmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -4579,12 +4728,7 @@ nsresult QuotaManager::MaybeRemoveLocalStorageData() {
|
|||
|
||||
// Now check the real archive file.
|
||||
nsCOMPtr<nsIFile> lsArchiveFile;
|
||||
rv = NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_FILE_NAME));
|
||||
rv = GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -4740,33 +4884,27 @@ nsresult QuotaManager::MaybeRemoveLocalStorageDirectories() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult QuotaManager::MaybeCreateLocalStorageArchive() {
|
||||
nsresult QuotaManager::CreateLocalStorageArchiveConnectionFromWebAppsStore(
|
||||
mozIStorageConnection** aConnection) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
// Check if the archive was already successfully created.
|
||||
nsCOMPtr<nsIFile> lsArchiveFile;
|
||||
nsresult rv =
|
||||
NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_FILE_NAME));
|
||||
GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool exists;
|
||||
rv = lsArchiveFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
// ls-archive.sqlite already exists, nothing to create.
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(!exists);
|
||||
#endif
|
||||
|
||||
// Get the storage service first, we will need it at multiple places.
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
|
@ -4856,12 +4994,8 @@ nsresult QuotaManager::MaybeCreateLocalStorageArchive() {
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIFile> lsArchiveTmpFile;
|
||||
rv = NS_NewLocalFile(mStoragePath, false, getter_AddRefs(lsArchiveTmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveTmpFile->Append(NS_LITERAL_STRING(LS_ARCHIVE_TMP_FILE_NAME));
|
||||
rv = GetLocalStorageArchiveTmpFile(mStoragePath,
|
||||
getter_AddRefs(lsArchiveTmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -4895,6 +5029,15 @@ nsresult QuotaManager::MaybeCreateLocalStorageArchive() {
|
|||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> lsArchiveConnection;
|
||||
rv = ss->OpenUnsharedDatabase(lsArchiveFile,
|
||||
getter_AddRefs(lsArchiveConnection));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
lsArchiveConnection.forget(aConnection);
|
||||
} else {
|
||||
// If webappsstore database is not useable, just create an empty archive.
|
||||
|
||||
|
@ -4923,11 +5066,227 @@ nsresult QuotaManager::MaybeCreateLocalStorageArchive() {
|
|||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
lsArchiveConnection.forget(aConnection);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult QuotaManager::CreateLocalStorageArchiveConnection(
|
||||
mozIStorageConnection** aConnection, bool& aNewlyCreated) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
|
||||
MOZ_ASSERT(aConnection);
|
||||
|
||||
nsCOMPtr<nsIFile> lsArchiveTmpFile;
|
||||
nsresult rv = GetLocalStorageArchiveTmpFile(mStoragePath,
|
||||
getter_AddRefs(lsArchiveTmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool exists;
|
||||
rv = lsArchiveTmpFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
rv = lsArchiveTmpFile->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the archive was already successfully created.
|
||||
nsCOMPtr<nsIFile> lsArchiveFile;
|
||||
rv = GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
bool removed = false;
|
||||
|
||||
bool isDirectory;
|
||||
rv = lsArchiveFile->IsDirectory(&isDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (isDirectory) {
|
||||
rv = lsArchiveFile->Remove(true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
removed = true;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = ss->OpenUnsharedDatabase(lsArchiveFile, getter_AddRefs(connection));
|
||||
if (!removed && rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
rv = lsArchiveFile->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
removed = true;
|
||||
|
||||
rv = ss->OpenUnsharedDatabase(lsArchiveFile, getter_AddRefs(connection));
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = StorageDBUpdater::Update(connection);
|
||||
if (!removed && NS_FAILED(rv)) {
|
||||
rv = connection->Close();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = lsArchiveFile->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
removed = true;
|
||||
|
||||
rv = ss->OpenUnsharedDatabase(lsArchiveFile, getter_AddRefs(connection));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = StorageDBUpdater::Update(connection);
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
connection.forget(aConnection);
|
||||
aNewlyCreated = removed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
rv = CreateLocalStorageArchiveConnectionFromWebAppsStore(
|
||||
getter_AddRefs(connection));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
connection.forget(aConnection);
|
||||
aNewlyCreated = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult QuotaManager::RecreateLocalStorageArchive(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
|
||||
|
||||
// Close local storage archive connection. We are going to remove underlying
|
||||
// file.
|
||||
nsresult rv = aConnection->Close();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = MaybeRemoveLocalStorageDirectories();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> lsArchiveFile;
|
||||
rv = GetLocalStorageArchiveFile(mStoragePath, getter_AddRefs(lsArchiveFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool exists;
|
||||
rv = lsArchiveFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
MOZ_ASSERT(exists);
|
||||
#endif
|
||||
|
||||
rv = lsArchiveFile->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = CreateLocalStorageArchiveConnectionFromWebAppsStore(
|
||||
getter_AddRefs(aConnection));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult QuotaManager::DowngradeLocalStorageArchive(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
|
||||
|
||||
nsresult rv = RecreateLocalStorageArchive(aConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = InitializeLocalStorageArchive(aConnection, kLocalStorageArchiveVersion);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult QuotaManager::UpgradeLocalStorageArchiveFrom0To1(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection) {
|
||||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(CachedNextGenLocalStorageEnabled());
|
||||
|
||||
nsresult rv = RecreateLocalStorageArchive(aConnection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = InitializeLocalStorageArchive(aConnection, 1);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
nsresult QuotaManager::UpgradeLocalStorageArchiveFrom1To2(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection) {
|
||||
nsresult rv = SaveLocalStorageArchiveVersion(aConnection, 2);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void QuotaManager::AssertStorageIsInitialized() const {
|
||||
|
@ -5103,12 +5462,87 @@ nsresult QuotaManager::EnsureStorageIsInitialized() {
|
|||
}
|
||||
|
||||
if (CachedNextGenLocalStorageEnabled()) {
|
||||
rv = MaybeCreateLocalStorageArchive();
|
||||
nsCOMPtr<mozIStorageConnection> connection;
|
||||
bool newlyCreated;
|
||||
rv = CreateLocalStorageArchiveConnection(getter_AddRefs(connection),
|
||||
newlyCreated);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t version = 0;
|
||||
|
||||
if (!newlyCreated) {
|
||||
bool initialized;
|
||||
rv = IsLocalStorageArchiveInitialized(connection, initialized);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
rv = LoadLocalStorageArchiveVersion(connection, version);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (version > kLocalStorageArchiveVersion) {
|
||||
rv = DowngradeLocalStorageArchive(connection);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = LoadLocalStorageArchiveVersion(connection, version);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(version == kLocalStorageArchiveVersion);
|
||||
} else if (version != kLocalStorageArchiveVersion) {
|
||||
if (newlyCreated) {
|
||||
MOZ_ASSERT(version == 0);
|
||||
|
||||
rv = InitializeLocalStorageArchive(connection,
|
||||
kLocalStorageArchiveVersion);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
static_assert(kLocalStorageArchiveVersion == 1,
|
||||
"Upgrade function needed due to LocalStorage archive "
|
||||
"version increase.");
|
||||
|
||||
while (version != kLocalStorageArchiveVersion) {
|
||||
if (version == 0) {
|
||||
rv = UpgradeLocalStorageArchiveFrom0To1(connection);
|
||||
} /* else if (version == 1) {
|
||||
rv = UpgradeLocalStorageArchiveFrom1To2(connection);
|
||||
} */ else {
|
||||
QM_WARNING(
|
||||
"Unable to initialize LocalStorage archive, no upgrade path is "
|
||||
"available!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = LoadLocalStorageArchiveVersion(connection, version);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(version == kLocalStorageArchiveVersion);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rv = MaybeRemoveLocalStorageData();
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
mStorageInitialized = true;
|
||||
|
|
|
@ -425,7 +425,25 @@ class QuotaManager final : public BackgroundThreadObject {
|
|||
|
||||
nsresult MaybeRemoveLocalStorageDirectories();
|
||||
|
||||
nsresult MaybeCreateLocalStorageArchive();
|
||||
nsresult CreateLocalStorageArchiveConnectionFromWebAppsStore(
|
||||
mozIStorageConnection** aConnection);
|
||||
|
||||
nsresult CreateLocalStorageArchiveConnection(
|
||||
mozIStorageConnection** aConnection, bool& aNewlyCreated);
|
||||
|
||||
nsresult RecreateLocalStorageArchive(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
|
||||
nsresult DowngradeLocalStorageArchive(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
|
||||
nsresult UpgradeLocalStorageArchiveFrom0To1(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
|
||||
/*
|
||||
nsresult UpgradeLocalStorageArchiveFrom1To2(
|
||||
nsCOMPtr<mozIStorageConnection>& aConnection);
|
||||
*/
|
||||
|
||||
nsresult InitializeRepository(PersistenceType aPersistenceType);
|
||||
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This test is mainly to verify that local storage directories are removed
|
||||
* during local storage archive upgrade from version 0 to version 1.
|
||||
* See bug 1546305.
|
||||
*/
|
||||
|
||||
async function testSteps() {
|
||||
const lsDirs = [
|
||||
"storage/default/http+++example.com/ls",
|
||||
"storage/default/http+++localhost/ls",
|
||||
"storage/default/http+++www.mozilla.org/ls",
|
||||
];
|
||||
|
||||
info("Clearing");
|
||||
|
||||
let request = clear();
|
||||
await requestFinished(request);
|
||||
|
||||
info("Installing package");
|
||||
|
||||
// The profile contains three initialized origin directories with local
|
||||
// storage data, local storage archive, a script for origin initialization,
|
||||
// the storage database and the web apps store database:
|
||||
// - storage/default/https+++example.com
|
||||
// - storage/default/https+++localhost
|
||||
// - storage/default/https+++www.mozilla.org
|
||||
// - storage/ls-archive.sqlite
|
||||
// - create_db.js
|
||||
// - storage.sqlite
|
||||
// - webappsstore.sqlite
|
||||
// The file create_db.js in the package was run locally (with a build that
|
||||
// doesn't support local storage archive upgrades), specifically it was
|
||||
// temporarily added to xpcshell.ini and then executed:
|
||||
// mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
|
||||
// Note: to make it become the profile in the test, additional manual steps
|
||||
// are needed.
|
||||
// 1. Remove the folder "storage/temporary".
|
||||
installPackage("localStorageArchive1upgrade_profile");
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(exists, "ls directory does exist");
|
||||
}
|
||||
|
||||
request = init();
|
||||
request = await requestFinished(request);
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(!exists, "ls directory doesn't exist");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This test is mainly to verify that local storage directories are removed
|
||||
* during local storage archive downgrade from any future version to current
|
||||
* version. See bug 1546305.
|
||||
*/
|
||||
|
||||
async function testSteps() {
|
||||
const lsDirs = [
|
||||
"storage/default/http+++example.com/ls",
|
||||
"storage/default/http+++localhost/ls",
|
||||
"storage/default/http+++www.mozilla.org/ls",
|
||||
];
|
||||
|
||||
info("Clearing");
|
||||
|
||||
let request = clear();
|
||||
await requestFinished(request);
|
||||
|
||||
info("Installing package");
|
||||
|
||||
// The profile contains three initialized origin directories with local
|
||||
// storage data, local storage archive, a script for origin initialization,
|
||||
// the storage database and the web apps store database:
|
||||
// - storage/default/https+++example.com
|
||||
// - storage/default/https+++localhost
|
||||
// - storage/default/https+++www.mozilla.org
|
||||
// - storage/ls-archive.sqlite
|
||||
// - create_db.js
|
||||
// - storage.sqlite
|
||||
// - webappsstore.sqlite
|
||||
// The file create_db.js in the package was run locally (with a build that
|
||||
// supports local storage archive upgrades and local storage archive version
|
||||
// set to max integer), specifically it was temporarily added to xpcshell.ini
|
||||
// and then executed:
|
||||
// mach xpcshell-test --interactive dom/localstorage/test/unit/create_db.js
|
||||
// Note: to make it become the profile in the test, additional manual steps
|
||||
// are needed.
|
||||
// 1. Remove the folder "storage/temporary".
|
||||
installPackage("localStorageArchiveDowngrade_profile");
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(exists, "ls directory does exist");
|
||||
}
|
||||
|
||||
request = init();
|
||||
request = await requestFinished(request);
|
||||
|
||||
info("Checking ls dirs");
|
||||
|
||||
for (let lsDir of lsDirs) {
|
||||
let dir = getRelativeFile(lsDir);
|
||||
|
||||
exists = dir.exists();
|
||||
ok(!exists, "ls directory doesn't exist");
|
||||
}
|
||||
}
|
|
@ -13,6 +13,8 @@ support-files =
|
|||
groupMismatch_profile.zip
|
||||
idbSubdirUpgrade1_profile.zip
|
||||
idbSubdirUpgrade2_profile.zip
|
||||
localStorageArchive1upgrade_profile.zip
|
||||
localStorageArchiveDowngrade_profile.zip
|
||||
morgueCleanup_profile.zip
|
||||
obsoleteOriginAttributes_profile.zip
|
||||
originAttributesUpgrade_profile.zip
|
||||
|
@ -34,6 +36,8 @@ support-files =
|
|||
[test_idbSubdirUpgrade.js]
|
||||
[test_initTemporaryStorage.js]
|
||||
[test_listInitializedOrigins.js]
|
||||
[test_localStorageArchive1upgrade.js]
|
||||
[test_localStorageArchiveDowngrade.js]
|
||||
[test_morgueCleanup.js]
|
||||
[test_obsoleteOriginAttributesUpgrade.js]
|
||||
[test_obsoleteOrigins.js]
|
||||
|
|
|
@ -586,7 +586,7 @@ double SVGContentUtils::ComputeNormalizedHypotenuse(double aWidth,
|
|||
}
|
||||
|
||||
float SVGContentUtils::AngleBisect(float a1, float a2) {
|
||||
float delta = fmod(a2 - a1, static_cast<float>(2 * M_PI));
|
||||
float delta = std::fmod(a2 - a1, static_cast<float>(2 * M_PI));
|
||||
if (delta < 0) {
|
||||
delta += static_cast<float>(2 * M_PI);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ void SVGLineElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
|
|||
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
|
||||
float angle = atan2(y2 - y1, x2 - x1);
|
||||
float angle = std::atan2(y2 - y1, x2 - x1);
|
||||
|
||||
aMarks->AppendElement(SVGMark(x1, y1, angle, SVGMark::eStart));
|
||||
aMarks->AppendElement(SVGMark(x2, y2, angle, SVGMark::eEnd));
|
||||
|
|
|
@ -329,7 +329,7 @@ nsresult SVGMotionSMILType::ComputeDistance(const SMILValue& aFrom,
|
|||
const PathPointParams& toParams = to.mU.mPathPointParams;
|
||||
MOZ_ASSERT(fromParams.mPath == toParams.mPath,
|
||||
"Interpolation endpoints should be from same path");
|
||||
aDistance = fabs(toParams.mDistToPoint - fromParams.mDistToPoint);
|
||||
aDistance = std::fabs(toParams.mDistToPoint - fromParams.mDistToPoint);
|
||||
} else {
|
||||
const TranslationParams& fromParams = from.mU.mTranslationParams;
|
||||
const TranslationParams& toParams = to.mU.mTranslationParams;
|
||||
|
|
|
@ -195,7 +195,7 @@ static void TraverseLinetoHorizontalAbs(const float* aArgs,
|
|||
SVGPathTraversalState& aState) {
|
||||
Point to(aArgs[0], aState.pos.y);
|
||||
if (aState.ShouldUpdateLengthAndControlPoints()) {
|
||||
aState.length += fabs(to.x - aState.pos.x);
|
||||
aState.length += std::fabs(to.x - aState.pos.x);
|
||||
aState.cp1 = aState.cp2 = to;
|
||||
}
|
||||
aState.pos = to;
|
||||
|
@ -205,7 +205,7 @@ static void TraverseLinetoHorizontalRel(const float* aArgs,
|
|||
SVGPathTraversalState& aState) {
|
||||
aState.pos.x += aArgs[0];
|
||||
if (aState.ShouldUpdateLengthAndControlPoints()) {
|
||||
aState.length += fabs(aArgs[0]);
|
||||
aState.length += std::fabs(aArgs[0]);
|
||||
aState.cp1 = aState.cp2 = aState.pos;
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ static void TraverseLinetoVerticalAbs(const float* aArgs,
|
|||
SVGPathTraversalState& aState) {
|
||||
Point to(aState.pos.x, aArgs[0]);
|
||||
if (aState.ShouldUpdateLengthAndControlPoints()) {
|
||||
aState.length += fabs(to.y - aState.pos.y);
|
||||
aState.length += std::fabs(to.y - aState.pos.y);
|
||||
aState.cp1 = aState.cp2 = to;
|
||||
}
|
||||
aState.pos = to;
|
||||
|
@ -224,7 +224,7 @@ static void TraverseLinetoVerticalRel(const float* aArgs,
|
|||
SVGPathTraversalState& aState) {
|
||||
aState.pos.y += aArgs[0];
|
||||
if (aState.ShouldUpdateLengthAndControlPoints()) {
|
||||
aState.length += fabs(aArgs[0]);
|
||||
aState.length += std::fabs(aArgs[0]);
|
||||
aState.cp1 = aState.cp2 = aState.pos;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ void SVGPolyElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
|
|||
for (uint32_t i = 1; i < points.Length(); ++i) {
|
||||
float x = points[i].mX;
|
||||
float y = points[i].mY;
|
||||
float angle = atan2(y - py, x - px);
|
||||
float angle = std::atan2(y - py, x - px);
|
||||
|
||||
// Vertex marker.
|
||||
if (i == 1) {
|
||||
|
|
|
@ -46,7 +46,8 @@ void SVGPolygonElement::GetMarkPoints(nsTArray<SVGMark> *aMarks) {
|
|||
|
||||
SVGMark *endMark = &aMarks->LastElement();
|
||||
SVGMark *startMark = &aMarks->ElementAt(0);
|
||||
float angle = atan2(startMark->y - endMark->y, startMark->x - endMark->x);
|
||||
float angle =
|
||||
std::atan2(startMark->y - endMark->y, startMark->x - endMark->x);
|
||||
|
||||
endMark->type = SVGMark::eMid;
|
||||
endMark->angle = SVGContentUtils::AngleBisect(angle, endMark->angle);
|
||||
|
|
|
@ -207,7 +207,7 @@ nsresult SVGTransformListSMILType::ComputeDistance(const SMILValue& aFrom,
|
|||
case SVG_TRANSFORM_SKEWY: {
|
||||
const float& a = fromTransform.mParams[0];
|
||||
const float& b = toTransform.mParams[0];
|
||||
aDistance = fabs(a - b);
|
||||
aDistance = std::fabs(a - b);
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -87,8 +87,8 @@ nsresult SVGViewBoxSMILType::ComputeDistance(const SMILValue& aFrom,
|
|||
float dRight = (to->x + to->width) - (from->x + from->width);
|
||||
float dBottom = (to->y + to->height) - (from->y + from->height);
|
||||
|
||||
aDistance =
|
||||
sqrt(dLeft * dLeft + dTop * dTop + dRight * dRight + dBottom * dBottom);
|
||||
aDistance = std::sqrt(dLeft * dLeft + dTop * dTop + dRight * dRight +
|
||||
dBottom * dBottom);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,13 @@ function testElements(baseid, callback)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Ignore content inside a <button> This can be removed if/when
|
||||
// button switches to use shadow DOM.
|
||||
let buttonParent = element.closest("button");
|
||||
if (buttonParent && buttonParent !== element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
testElement(element);
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,9 @@ class MOZ_STACK_CLASS BytecodeCompiler {
|
|||
// This function lives here, not in SourceAwareCompiler, because it mostly
|
||||
// uses fields in *this* class.
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool assignSource(JS::SourceText<Unit>& sourceBuffer);
|
||||
MOZ_MUST_USE bool assignSource(JS::SourceText<Unit>& sourceBuffer) {
|
||||
return scriptSource->assignSource(cx, options, sourceBuffer);
|
||||
}
|
||||
|
||||
bool canLazilyParse() const;
|
||||
|
||||
|
|
|
@ -400,19 +400,6 @@ bool BytecodeCompiler::createScriptSource(
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
bool BytecodeCompiler::assignSource(SourceText<Unit>& sourceBuffer) {
|
||||
if (!cx->realm()->behaviors().discardSource()) {
|
||||
if (options.sourceIsLazy) {
|
||||
scriptSource->setSourceRetrievable();
|
||||
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BytecodeCompiler::canLazilyParse() const {
|
||||
return options.canLazilyParse &&
|
||||
!cx->realm()->behaviors().disableLazyParsing() &&
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "jit/ExecutableAllocator.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/JitSpewer.h"
|
||||
|
||||
// Spew formatting helpers.
|
||||
|
@ -193,6 +194,12 @@ class AssemblerBuffer {
|
|||
void oomDetected() {
|
||||
m_oom = true;
|
||||
m_buffer.clear();
|
||||
#ifdef DEBUG
|
||||
JitContext* context = MaybeGetJitContext();
|
||||
if (context) {
|
||||
context->setOOM();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::Vector<unsigned char, 256, AssemblerBufferAllocPolicy> m_buffer;
|
||||
|
|
|
@ -3659,9 +3659,8 @@ JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, HandleScript script) {
|
|||
if (fun) {
|
||||
return JS_DecompileFunction(cx, fun);
|
||||
}
|
||||
bool haveSource = script->scriptSource()->hasSourceText();
|
||||
if (!haveSource &&
|
||||
!JSScript::loadSource(cx, script->scriptSource(), &haveSource)) {
|
||||
bool haveSource;
|
||||
if (!ScriptSource::loadSource(cx, script->scriptSource(), &haveSource)) {
|
||||
return nullptr;
|
||||
}
|
||||
return haveSource ? JSScript::sourceData(cx, script)
|
||||
|
|
|
@ -8411,9 +8411,8 @@ class DebuggerSourceGetTextMatcher {
|
|||
|
||||
ReturnType match(HandleScriptSourceObject sourceObject) {
|
||||
ScriptSource* ss = sourceObject->source();
|
||||
bool hasSourceText = ss->hasSourceText();
|
||||
if (!ss->hasSourceText() &&
|
||||
!JSScript::loadSource(cx_, ss, &hasSourceText)) {
|
||||
bool hasSourceText;
|
||||
if (!ScriptSource::loadSource(cx_, ss, &hasSourceText)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!hasSourceText) {
|
||||
|
|
|
@ -869,9 +869,10 @@ JSString* js::FunctionToString(JSContext* cx, HandleFunction fun,
|
|||
bool addParentheses =
|
||||
haveSource && isToSource && (fun->isLambda() && !fun->isArrow());
|
||||
|
||||
if (haveSource && !script->scriptSource()->hasSourceText() &&
|
||||
!JSScript::loadSource(cx, script->scriptSource(), &haveSource)) {
|
||||
return nullptr;
|
||||
if (haveSource) {
|
||||
if (!ScriptSource::loadSource(cx, script->scriptSource(), &haveSource)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Fast path for the common case, to avoid StringBuffer overhead.
|
||||
|
|
|
@ -1652,30 +1652,67 @@ void ScriptSourceObject::setPrivate(JSRuntime* rt, const Value& value) {
|
|||
rt->addRefScriptPrivate(value);
|
||||
}
|
||||
|
||||
class ScriptSource::LoadSourceMatcher {
|
||||
JSContext* const cx_;
|
||||
ScriptSource* const ss_;
|
||||
bool* const loaded_;
|
||||
|
||||
public:
|
||||
explicit LoadSourceMatcher(JSContext* cx, ScriptSource* ss, bool* loaded)
|
||||
: cx_(cx), ss_(ss), loaded_(loaded) {}
|
||||
|
||||
template <typename Unit>
|
||||
bool operator()(const Compressed<Unit>&) const {
|
||||
return sourceAlreadyLoaded();
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
bool operator()(const Uncompressed<Unit>&) const {
|
||||
return sourceAlreadyLoaded();
|
||||
}
|
||||
|
||||
bool operator()(const Missing&) const { return tryLoadingSource(); }
|
||||
|
||||
bool operator()(const BinAST&) const { return tryLoadingSource(); }
|
||||
|
||||
private:
|
||||
bool sourceAlreadyLoaded() const {
|
||||
*loaded_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tryLoadingSource() const {
|
||||
// Establish the default outcome first.
|
||||
*loaded_ = false;
|
||||
|
||||
if (!cx_->runtime()->sourceHook.ref() || !ss_->sourceRetrievable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char16_t* src = nullptr;
|
||||
size_t length;
|
||||
if (!cx_->runtime()->sourceHook->load(cx_, ss_->filename(), &src,
|
||||
&length)) {
|
||||
return false;
|
||||
}
|
||||
if (!src) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// XXX On-demand source is currently only UTF-16. Perhaps it should be
|
||||
// changed to UTF-8, or UTF-8 be allowed in addition to UTF-16?
|
||||
if (!ss_->setRetrievedSource(cx_, EntryUnits<char16_t>(src), length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*loaded_ = true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* static */
|
||||
bool JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked) {
|
||||
MOZ_ASSERT(!ss->hasSourceText());
|
||||
*worked = false;
|
||||
if (!cx->runtime()->sourceHook.ref() || !ss->sourceRetrievable()) {
|
||||
return true;
|
||||
}
|
||||
char16_t* src = nullptr;
|
||||
size_t length;
|
||||
if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length)) {
|
||||
return false;
|
||||
}
|
||||
if (!src) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// XXX On-demand source is currently only UTF-16. Perhaps it should be
|
||||
// changed to UTF-8, or UTF-8 be allowed in addition to UTF-16?
|
||||
if (!ss->setSource(cx, EntryUnits<char16_t>(src), length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*worked = true;
|
||||
return true;
|
||||
bool ScriptSource::loadSource(JSContext* cx, ScriptSource* ss, bool* loaded) {
|
||||
return ss->data.match(LoadSourceMatcher(cx, ss, loaded));
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -2056,16 +2093,10 @@ JSFlatString* ScriptSource::functionBodyString(JSContext* cx) {
|
|||
}
|
||||
|
||||
template <typename Unit>
|
||||
void ScriptSource::setSource(
|
||||
typename SourceTypeTraits<Unit>::SharedImmutableString uncompressed) {
|
||||
MOZ_MUST_USE bool ScriptSource::setUncompressedSourceHelper(
|
||||
JSContext* cx, EntryUnits<Unit>&& source, size_t length) {
|
||||
MOZ_ASSERT(data.is<Missing>());
|
||||
data = SourceType(Uncompressed<Unit>(std::move(uncompressed)));
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool ScriptSource::setSource(JSContext* cx,
|
||||
EntryUnits<Unit>&& source,
|
||||
size_t length) {
|
||||
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
|
||||
|
||||
auto uniqueChars = SourceTypeTraits<Unit>::toCacheable(std::move(source));
|
||||
|
@ -2075,10 +2106,20 @@ MOZ_MUST_USE bool ScriptSource::setSource(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
setSource<Unit>(std::move(*deduped));
|
||||
data = SourceType(Uncompressed<Unit>(std::move(*deduped)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool ScriptSource::setRetrievedSource(JSContext* cx,
|
||||
EntryUnits<Unit>&& source,
|
||||
size_t length) {
|
||||
MOZ_ASSERT(sourceRetrievable_);
|
||||
MOZ_ASSERT(data.is<Missing>(),
|
||||
"retrievable source must be indicated as missing");
|
||||
return setUncompressedSourceHelper(cx, std::move(source), length);
|
||||
}
|
||||
|
||||
#if defined(JS_BUILD_BINAST)
|
||||
|
||||
MOZ_MUST_USE bool ScriptSource::setBinASTSourceCopy(JSContext* cx,
|
||||
|
@ -2161,26 +2202,29 @@ bool ScriptSource::tryCompressOffThread(JSContext* cx) {
|
|||
}
|
||||
|
||||
template <typename Unit>
|
||||
void ScriptSource::setCompressedSource(SharedImmutableString raw,
|
||||
size_t uncompressedLength) {
|
||||
MOZ_ASSERT(data.is<Missing>() || hasUncompressedSource());
|
||||
MOZ_ASSERT_IF(hasUncompressedSource(), length() == uncompressedLength);
|
||||
void ScriptSource::convertToCompressedSource(SharedImmutableString compressed,
|
||||
size_t uncompressedLength) {
|
||||
MOZ_ASSERT(data.is<Uncompressed<Unit>>(),
|
||||
"should only be converting uncompressed source to compressed "
|
||||
"source identically encoded");
|
||||
MOZ_ASSERT(length() == uncompressedLength);
|
||||
|
||||
if (pinnedUnitsStack_) {
|
||||
MOZ_ASSERT(pendingCompressed_.empty());
|
||||
pendingCompressed_.construct<Compressed<Unit>>(std::move(raw),
|
||||
pendingCompressed_.construct<Compressed<Unit>>(std::move(compressed),
|
||||
uncompressedLength);
|
||||
} else {
|
||||
data = SourceType(Compressed<Unit>(std::move(raw), uncompressedLength));
|
||||
data =
|
||||
SourceType(Compressed<Unit>(std::move(compressed), uncompressedLength));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool ScriptSource::setCompressedSource(JSContext* cx,
|
||||
UniqueChars&& compressed,
|
||||
size_t rawLength,
|
||||
size_t sourceLength) {
|
||||
MOZ_ASSERT(compressed);
|
||||
MOZ_MUST_USE bool ScriptSource::initializeWithCompressedSource(
|
||||
JSContext* cx, UniqueChars&& compressed, size_t rawLength,
|
||||
size_t sourceLength) {
|
||||
MOZ_ASSERT(data.is<Missing>(), "shouldn't be double-initializing");
|
||||
MOZ_ASSERT(compressed != nullptr);
|
||||
|
||||
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
|
||||
auto deduped = cache.getOrCreate(std::move(compressed), rawLength);
|
||||
|
@ -2189,13 +2233,30 @@ MOZ_MUST_USE bool ScriptSource::setCompressedSource(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
setCompressedSource<Unit>(std::move(*deduped), sourceLength);
|
||||
MOZ_ASSERT(pinnedUnitsStack_ == nullptr,
|
||||
"shouldn't be initializing a ScriptSource while its characters "
|
||||
"are pinned -- that only makes sense with a ScriptSource actively "
|
||||
"being inspected");
|
||||
data = SourceType(Compressed<Unit>(std::move(*deduped), sourceLength));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
bool ScriptSource::setSourceCopy(JSContext* cx, SourceText<Unit>& srcBuf) {
|
||||
MOZ_ASSERT(!hasSourceText());
|
||||
bool ScriptSource::assignSource(JSContext* cx,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
SourceText<Unit>& srcBuf) {
|
||||
MOZ_ASSERT(data.is<Missing>(),
|
||||
"source assignment should only occur on fresh ScriptSources");
|
||||
|
||||
if (cx->realm()->behaviors().discardSource()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (options.sourceIsLazy) {
|
||||
sourceRetrievable_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSRuntime* runtime = cx->zone()->runtimeFromAnyThread();
|
||||
auto& cache = runtime->sharedImmutableStrings();
|
||||
|
@ -2210,14 +2271,16 @@ bool ScriptSource::setSourceCopy(JSContext* cx, SourceText<Unit>& srcBuf) {
|
|||
return false;
|
||||
}
|
||||
|
||||
setSource<Unit>(std::move(*deduped));
|
||||
data = SourceType(Uncompressed<Unit>(std::move(*deduped)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool ScriptSource::setSourceCopy(JSContext* cx,
|
||||
SourceText<char16_t>& srcBuf);
|
||||
template bool ScriptSource::setSourceCopy(JSContext* cx,
|
||||
SourceText<Utf8Unit>& srcBuf);
|
||||
template bool ScriptSource::assignSource(JSContext* cx,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
SourceText<char16_t>& srcBuf);
|
||||
template bool ScriptSource::assignSource(JSContext* cx,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
SourceText<Utf8Unit>& srcBuf);
|
||||
|
||||
void ScriptSource::trace(JSTracer* trc) {
|
||||
#ifdef JS_BUILD_BINAST
|
||||
|
@ -2349,15 +2412,15 @@ void SourceCompressionTask::runTask() {
|
|||
source->performTaskWork(this);
|
||||
}
|
||||
|
||||
void ScriptSource::setCompressedSourceFromTask(
|
||||
void ScriptSource::convertToCompressedSourceFromTask(
|
||||
SharedImmutableString compressed) {
|
||||
data.match(SetCompressedSourceFromTask(this, compressed));
|
||||
data.match(ConvertToCompressedSourceFromTask(this, compressed));
|
||||
}
|
||||
|
||||
void SourceCompressionTask::complete() {
|
||||
if (!shouldCancel() && resultString_.isSome()) {
|
||||
ScriptSource* source = sourceHolder_.get();
|
||||
source->setCompressedSourceFromTask(std::move(*resultString_));
|
||||
source->convertToCompressedSourceFromTask(std::move(*resultString_));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2433,6 +2496,13 @@ bool ScriptSource::xdrFinalizeEncoder(JS::TranscodeBuffer& buffer) {
|
|||
return res.isOk();
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool ScriptSource::initializeUncompressedSource(
|
||||
JSContext* cx, EntryUnits<Unit>&& source, size_t length) {
|
||||
MOZ_ASSERT(data.is<Missing>(), "must be initializing a fresh ScriptSource");
|
||||
return setUncompressedSourceHelper(cx, std::move(source), length);
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
struct SourceDecoder {
|
||||
XDRState<XDR_DECODE>* const xdr_;
|
||||
|
@ -2455,8 +2525,8 @@ struct SourceDecoder {
|
|||
|
||||
MOZ_TRY(xdr_->codeChars(sourceUnits.get(), uncompressedLength_));
|
||||
|
||||
if (!scriptSource_->setSource(xdr_->cx(), std::move(sourceUnits),
|
||||
uncompressedLength_)) {
|
||||
if (!scriptSource_->initializeUncompressedSource(
|
||||
xdr_->cx(), std::move(sourceUnits), uncompressedLength_)) {
|
||||
return xdr_->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
|
||||
|
@ -2616,10 +2686,10 @@ XDRResult ScriptSource::XDR(XDRState<mode>* xdr,
|
|||
}
|
||||
MOZ_TRY(xdr->codeBytes(bytes.get(), compressedLength));
|
||||
|
||||
if (!(srcCharSize == 1 ? ss->setCompressedSource<Utf8Unit>(
|
||||
if (!(srcCharSize == 1 ? ss->initializeWithCompressedSource<Utf8Unit>(
|
||||
xdr->cx(), std::move(bytes),
|
||||
compressedLength, uncompressedLength)
|
||||
: ss->setCompressedSource<char16_t>(
|
||||
: ss->initializeWithCompressedSource<char16_t>(
|
||||
xdr->cx(), std::move(bytes),
|
||||
compressedLength, uncompressedLength))) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
|
|
|
@ -546,7 +546,7 @@ class ScriptSource {
|
|||
Uncompressed<char16_t>, Missing, BinAST>;
|
||||
SourceType data;
|
||||
|
||||
// If the GC attempts to call setCompressedSource with PinnedUnits
|
||||
// If the GC attempts to call convertToCompressedSource with PinnedUnits
|
||||
// present, the first PinnedUnits (that is, bottom of the stack) will set
|
||||
// the compressed chars upon destruction.
|
||||
PinnedUnitsBase* pinnedUnitsStack_;
|
||||
|
@ -691,10 +691,22 @@ class ScriptSource {
|
|||
*/
|
||||
static constexpr size_t MinimumCompressibleLength = 256;
|
||||
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool setSourceCopy(JSContext* cx, JS::SourceText<Unit>& srcBuf);
|
||||
private:
|
||||
class LoadSourceMatcher;
|
||||
|
||||
public:
|
||||
// Attempt to load usable source for |ss| -- source text on which substring
|
||||
// operations and the like can be performed. On success return true and set
|
||||
// |*loaded| to indicate whether usable source could be loaded; otherwise
|
||||
// return false.
|
||||
static bool loadSource(JSContext* cx, ScriptSource* ss, bool* loaded);
|
||||
|
||||
// Assign source data from |srcBuf| to this recently-created |ScriptSource|.
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool assignSource(JSContext* cx,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceText<Unit>& srcBuf);
|
||||
|
||||
void setSourceRetrievable() { sourceRetrievable_ = true; }
|
||||
bool sourceRetrievable() const { return sourceRetrievable_; }
|
||||
bool hasSourceText() const {
|
||||
return hasUncompressedSource() || hasCompressedSource();
|
||||
|
@ -946,25 +958,45 @@ class ScriptSource {
|
|||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
JS::ScriptSourceInfo* info) const;
|
||||
|
||||
private:
|
||||
// Overwrites |data| with the uncompressed data from |source|. (This function
|
||||
// currently asserts |data.is<Missing>()|, but callers should assert it as
|
||||
// well, because this function shortly will be used in other cases and the
|
||||
// assertion will have to be removed.)
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool setSource(JSContext* cx, EntryUnits<Unit>&& source,
|
||||
size_t length);
|
||||
MOZ_MUST_USE bool setUncompressedSourceHelper(JSContext* cx,
|
||||
EntryUnits<Unit>&& source,
|
||||
size_t length);
|
||||
|
||||
public:
|
||||
// Initialize a fresh |ScriptSource| with uncompressed source.
|
||||
template <typename Unit>
|
||||
void setSource(
|
||||
typename SourceTypeTraits<Unit>::SharedImmutableString uncompressed);
|
||||
MOZ_MUST_USE bool initializeUncompressedSource(JSContext* cx,
|
||||
EntryUnits<Unit>&& source,
|
||||
size_t length);
|
||||
|
||||
// Set the retrieved source for a |ScriptSource| whose source was recorded as
|
||||
// missing but retrievable.
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool setRetrievedSource(JSContext* cx, EntryUnits<Unit>&& source,
|
||||
size_t length);
|
||||
|
||||
MOZ_MUST_USE bool tryCompressOffThread(JSContext* cx);
|
||||
|
||||
// The Unit parameter determines which type of compressed source is
|
||||
// recorded, but raw compressed source is always single-byte.
|
||||
// Convert this ScriptSource from storing uncompressed source of the given
|
||||
// type, to storing compressed source. (Raw compressed source is always
|
||||
// single-byte; |Unit| just records the encoding of the uncompressed source.)
|
||||
template <typename Unit>
|
||||
void setCompressedSource(SharedImmutableString compressed,
|
||||
size_t sourceLength);
|
||||
void convertToCompressedSource(SharedImmutableString compressed,
|
||||
size_t sourceLength);
|
||||
|
||||
// Initialize a fresh ScriptSource as containing compressed source of the
|
||||
// indicated original encoding.
|
||||
template <typename Unit>
|
||||
MOZ_MUST_USE bool setCompressedSource(JSContext* cx, UniqueChars&& raw,
|
||||
size_t rawLength, size_t sourceLength);
|
||||
MOZ_MUST_USE bool initializeWithCompressedSource(JSContext* cx,
|
||||
UniqueChars&& raw,
|
||||
size_t rawLength,
|
||||
size_t sourceLength);
|
||||
|
||||
#if defined(JS_BUILD_BINAST)
|
||||
|
||||
|
@ -990,18 +1022,18 @@ class ScriptSource {
|
|||
private:
|
||||
void performTaskWork(SourceCompressionTask* task);
|
||||
|
||||
struct SetCompressedSourceFromTask {
|
||||
struct ConvertToCompressedSourceFromTask {
|
||||
ScriptSource* const source_;
|
||||
SharedImmutableString& compressed_;
|
||||
|
||||
SetCompressedSourceFromTask(ScriptSource* source,
|
||||
SharedImmutableString& compressed)
|
||||
ConvertToCompressedSourceFromTask(ScriptSource* source,
|
||||
SharedImmutableString& compressed)
|
||||
: source_(source), compressed_(compressed) {}
|
||||
|
||||
template <typename Unit>
|
||||
void operator()(const Uncompressed<Unit>&) {
|
||||
source_->setCompressedSource<Unit>(std::move(compressed_),
|
||||
source_->length());
|
||||
source_->convertToCompressedSource<Unit>(std::move(compressed_),
|
||||
source_->length());
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
|
@ -1026,7 +1058,7 @@ class ScriptSource {
|
|||
}
|
||||
};
|
||||
|
||||
void setCompressedSourceFromTask(SharedImmutableString compressed);
|
||||
void convertToCompressedSourceFromTask(SharedImmutableString compressed);
|
||||
|
||||
private:
|
||||
// It'd be better to make this function take <XDRMode, Unit>, as both
|
||||
|
@ -2494,8 +2526,6 @@ class JSScript : public js::gc::TenuredCell {
|
|||
MOZ_MUST_USE bool appendSourceDataForToString(JSContext* cx,
|
||||
js::StringBuffer& buf);
|
||||
|
||||
static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked);
|
||||
|
||||
void setSourceObject(js::ScriptSourceObject* object);
|
||||
js::ScriptSourceObject* sourceObject() const { return sourceObject_; }
|
||||
js::ScriptSource* scriptSource() const;
|
||||
|
|
|
@ -6886,8 +6886,8 @@ static bool HandleInstantiationFailure(JSContext* cx, CallArgs args,
|
|||
|
||||
// Source discarding is allowed to affect JS semantics because it is never
|
||||
// enabled for normal JS content.
|
||||
bool haveSource = source->hasSourceText();
|
||||
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
|
||||
bool haveSource;
|
||||
if (!ScriptSource::loadSource(cx, source, &haveSource)) {
|
||||
return false;
|
||||
}
|
||||
if (!haveSource) {
|
||||
|
@ -7218,8 +7218,8 @@ JSString* js::AsmJSModuleToString(JSContext* cx, HandleFunction fun,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool haveSource = source->hasSourceText();
|
||||
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
|
||||
bool haveSource;
|
||||
if (!ScriptSource::loadSource(cx, source, &haveSource)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -7269,8 +7269,8 @@ JSString* js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool haveSource = source->hasSourceText();
|
||||
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
|
||||
bool haveSource;
|
||||
if (!ScriptSource::loadSource(cx, source, &haveSource)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -577,13 +577,13 @@ already_AddRefed<gfxPattern> nsSVGRadialGradientFrame::CreateGradient() {
|
|||
// representation divided by 2 to ensure that we get different cairo
|
||||
// fractions
|
||||
double dMax = std::max(0.0, r - 1.0 / 128);
|
||||
float dx = fx - cx;
|
||||
float dy = fy - cy;
|
||||
double d = sqrt((dx * dx) + (dy * dy));
|
||||
double dx = fx - cx;
|
||||
double dy = fy - cy;
|
||||
double d = std::sqrt((dx * dx) + (dy * dy));
|
||||
if (d > dMax) {
|
||||
double angle = atan2(dy, dx);
|
||||
fx = (float)(dMax * cos(angle)) + cx;
|
||||
fy = (float)(dMax * sin(angle)) + cy;
|
||||
double angle = std::atan2(dy, dx);
|
||||
fx = float(dMax * std::cos(angle)) + cx;
|
||||
fy = float(dMax * std::sin(angle)) + cy;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,5 +19,5 @@ origin:
|
|||
license: "ISC"
|
||||
|
||||
# update.sh will update this value
|
||||
release: "3570749942a4fea2b7e372833cb8374ce42cf389 (2019-04-24 13:04:01 +1200)"
|
||||
release: "64aa80f330a3dc510b1e3ac0e92cc6bed129a9a6 (2019-04-25 17:32:33 +0200)"
|
||||
|
||||
|
|
|
@ -485,16 +485,12 @@ public:
|
|||
XASSERT(cubeb_context->output_collection_changed_callback ||
|
||||
cubeb_context->input_collection_changed_callback);
|
||||
LOG("collection: Audio device state changed, id = %S, state = %lu.", device_id, new_state);
|
||||
if (new_state == DEVICE_STATE_ACTIVE ||
|
||||
new_state == DEVICE_STATE_NOTPRESENT ||
|
||||
new_state == DEVICE_STATE_UNPLUGGED) {
|
||||
EDataFlow flow;
|
||||
HRESULT hr = GetDataFlow(device_id, &flow);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
monitor_notifications.notify(flow);
|
||||
EDataFlow flow;
|
||||
HRESULT hr = GetDataFlow(device_id, &flow);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
monitor_notifications.notify(flow);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -399,17 +399,32 @@ test! {
|
|||
// Start the timer now, the initial job creation may be delayed by BITS service startup.
|
||||
let start = Instant::now();
|
||||
|
||||
// First immediate report
|
||||
monitor.get_status(timeout).expect("should initially be ok").unwrap();
|
||||
// First report, immediate
|
||||
let report_1 = monitor.get_status(timeout);
|
||||
let elapsed_to_report_1 = start.elapsed();
|
||||
report_1.as_ref().expect("should initially be ok").as_ref().unwrap();
|
||||
|
||||
// Transferred notification should come when the job completes in ~250 ms, otherwise we
|
||||
// will be stuck until timeout.
|
||||
let status = monitor.get_status(timeout).expect("should get status update").unwrap();
|
||||
assert!(start.elapsed() < Duration::from_millis(9_000));
|
||||
assert_eq!(status.state, BitsJobState::Transferred);
|
||||
let report_2 = monitor.get_status(timeout).expect("should get status update").unwrap();
|
||||
let elapsed_to_report_2 = start.elapsed();
|
||||
assert!(elapsed_to_report_2 < Duration::from_millis(9_000));
|
||||
assert_eq!(report_2.state, BitsJobState::Transferred);
|
||||
|
||||
let short_timeout = 500;
|
||||
monitor.get_status(short_timeout).expect_err("should be disconnected");
|
||||
let report_3 = monitor.get_status(short_timeout);
|
||||
let elapsed_to_report_3 = start.elapsed();
|
||||
|
||||
if let Ok(report_3) = report_3 {
|
||||
panic!("should be disconnected\n\
|
||||
report_1 ({}.{:03}): {:?}\n\
|
||||
report_2 ({}.{:03}): {:?}\n\
|
||||
report_3 ({}.{:03}): {:?}",
|
||||
elapsed_to_report_1.as_secs(), elapsed_to_report_1.subsec_millis(), report_1,
|
||||
elapsed_to_report_2.as_secs(), elapsed_to_report_2.subsec_millis(), report_2,
|
||||
elapsed_to_report_3.as_secs(), elapsed_to_report_3.subsec_millis(), report_3,
|
||||
);
|
||||
}
|
||||
|
||||
server.shutdown();
|
||||
|
||||
|
|
|
@ -646,6 +646,7 @@ const isDummyDocument = document.documentURI == "chrome://extensions/content/dum
|
|||
if (!isDummyDocument) {
|
||||
for (let script of [
|
||||
"chrome://global/content/elements/general.js",
|
||||
"chrome://global/content/elements/button.js",
|
||||
"chrome://global/content/elements/checkbox.js",
|
||||
"chrome://global/content/elements/menu.js",
|
||||
"chrome://global/content/elements/menupopup.js",
|
||||
|
|
|
@ -83,6 +83,7 @@ toolkit.jar:
|
|||
content/global/elements/autocomplete-popup.js (widgets/autocomplete-popup.js)
|
||||
content/global/elements/autocomplete-richlistitem.js (widgets/autocomplete-richlistitem.js)
|
||||
content/global/elements/browser-custom-element.js (widgets/browser-custom-element.js)
|
||||
content/global/elements/button.js (widgets/button.js)
|
||||
content/global/elements/checkbox.js (widgets/checkbox.js)
|
||||
content/global/elements/datetimebox.js (widgets/datetimebox.js)
|
||||
content/global/elements/findbar.js (widgets/findbar.js)
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
/* 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";
|
||||
|
||||
// This is loaded into all XUL windows. Wrap in a block to prevent
|
||||
// leaking to window scope.
|
||||
{
|
||||
class MozButtonBase extends MozElements.BaseText {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* While it would seem we could do this by handling oncommand, we can't
|
||||
* because any external oncommand handlers might get called before ours,
|
||||
* and then they would see the incorrect value of checked. Additionally
|
||||
* a command attribute would redirect the command events anyway.
|
||||
*/
|
||||
this.addEventListener("click", (event) => {
|
||||
if (event.button != 0) {
|
||||
return;
|
||||
}
|
||||
this._handleClick();
|
||||
});
|
||||
|
||||
this.addEventListener("keypress", (event) => {
|
||||
if (event.key != " ") {
|
||||
return;
|
||||
}
|
||||
this._handleClick();
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
this.addEventListener("keypress", (event) => {
|
||||
if (this.hasMenu()) {
|
||||
if (this.open)
|
||||
return;
|
||||
} else {
|
||||
if (event.keyCode == KeyEvent.DOM_VK_UP ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_LEFT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "ltr") ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_RIGHT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "rtl")) {
|
||||
event.preventDefault();
|
||||
window.document.commandDispatcher.rewindFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.keyCode == KeyEvent.DOM_VK_DOWN ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_RIGHT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "ltr") ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_LEFT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "rtl")) {
|
||||
event.preventDefault();
|
||||
window.document.commandDispatcher.advanceFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.keyCode || event.charCode <= 32 || event.altKey ||
|
||||
event.ctrlKey || event.metaKey)
|
||||
return; // No printable char pressed, not a potential accesskey
|
||||
|
||||
// Possible accesskey pressed
|
||||
var charPressedLower = String.fromCharCode(event.charCode).toLowerCase();
|
||||
|
||||
// If the accesskey of the current button is pressed, just activate it
|
||||
if (this.accessKey.toLowerCase() == charPressedLower) {
|
||||
this.click();
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for accesskey in the list of buttons for this doc and each subdoc
|
||||
// Get the buttons for the main document and all sub-frames
|
||||
for (var frameCount = -1; frameCount < window.top.frames.length; frameCount++) {
|
||||
var doc = (frameCount == -1) ? window.top.document :
|
||||
window.top.frames[frameCount].document;
|
||||
if (this.fireAccessKeyButton(doc.documentElement, charPressedLower))
|
||||
return;
|
||||
}
|
||||
|
||||
// Test anonymous buttons
|
||||
var dlg = window.top.document;
|
||||
var buttonBox = dlg.getAnonymousElementByAttribute(dlg.documentElement,
|
||||
"anonid", "buttons");
|
||||
if (buttonBox)
|
||||
this.fireAccessKeyButton(buttonBox, charPressedLower);
|
||||
});
|
||||
}
|
||||
|
||||
set type(val) {
|
||||
this.setAttribute("type", val);
|
||||
return val;
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this.getAttribute("type");
|
||||
}
|
||||
|
||||
set disabled(val) {
|
||||
if (val) {
|
||||
this.setAttribute("disabled", "true");
|
||||
} else {
|
||||
this.removeAttribute("disabled");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
get disabled() {
|
||||
return (this.getAttribute("disabled") == "true");
|
||||
}
|
||||
|
||||
set dlgType(val) {
|
||||
this.setAttribute("dlgtype", val);
|
||||
return val;
|
||||
}
|
||||
|
||||
get dlgType() {
|
||||
return this.getAttribute("dlgtype");
|
||||
}
|
||||
|
||||
set group(val) {
|
||||
this.setAttribute("group", val);
|
||||
return val;
|
||||
}
|
||||
|
||||
get group() {
|
||||
return this.getAttribute("group");
|
||||
}
|
||||
|
||||
set open(val) {
|
||||
if (this.hasMenu()) {
|
||||
this.openMenu(val);
|
||||
} else if (val) {
|
||||
// Fall back to just setting the attribute
|
||||
this.setAttribute("open", "true");
|
||||
} else {
|
||||
this.removeAttribute("open");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
get open() {
|
||||
return this.hasAttribute("open");
|
||||
}
|
||||
|
||||
set checked(val) {
|
||||
if (this.type == "radio" && val) {
|
||||
var sibs = this.parentNode.getElementsByAttribute("group", this.group);
|
||||
for (var i = 0; i < sibs.length; ++i)
|
||||
sibs[i].removeAttribute("checked");
|
||||
}
|
||||
|
||||
if (val)
|
||||
this.setAttribute("checked", "true");
|
||||
else
|
||||
this.removeAttribute("checked");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
get checked() {
|
||||
return this.hasAttribute("checked");
|
||||
}
|
||||
|
||||
filterButtons(node) {
|
||||
// if the node isn't visible, don't descend into it.
|
||||
var cs = node.ownerGlobal.getComputedStyle(node);
|
||||
if (cs.visibility != "visible" || cs.display == "none") {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
// but it may be a popup element, in which case we look at "state"...
|
||||
if (cs.display == "-moz-popup" && node.state != "open") {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
// OK - the node seems visible, so it is a candidate.
|
||||
if (node.localName == "button" && node.accessKey && !node.disabled)
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
}
|
||||
|
||||
fireAccessKeyButton(aSubtree, aAccessKeyLower) {
|
||||
var iterator = aSubtree.ownerDocument.createTreeWalker(aSubtree,
|
||||
NodeFilter.SHOW_ELEMENT,
|
||||
this.filterButtons);
|
||||
while (iterator.nextNode()) {
|
||||
var test = iterator.currentNode;
|
||||
if (test.accessKey.toLowerCase() == aAccessKeyLower &&
|
||||
!test.disabled && !test.collapsed && !test.hidden) {
|
||||
test.focus();
|
||||
test.click();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_handleClick() {
|
||||
if (!this.disabled) {
|
||||
if (this.type == "checkbox") {
|
||||
this.checked = !this.checked;
|
||||
} else if (this.type == "radio") {
|
||||
this.checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MozXULElement.implementCustomInterface(MozButtonBase, [Ci.nsIDOMXULButtonElement]);
|
||||
|
||||
class MozButton extends MozButtonBase {
|
||||
constructor() {
|
||||
super();
|
||||
this.hasConnected = false;
|
||||
}
|
||||
|
||||
static get inheritedAttributes() {
|
||||
return {
|
||||
".box-inherit": "align,dir,pack,orient",
|
||||
".button-icon": "src=image",
|
||||
".button-text": "value=label,accesskey,crop",
|
||||
".button-menu-dropmarker": "open,disabled,label",
|
||||
};
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this.querySelector(".button-icon");
|
||||
}
|
||||
|
||||
static get buttonFragment() {
|
||||
let frag = document.importNode(MozXULElement.parseXULToFragment(`
|
||||
<hbox class="box-inherit button-box" align="center" pack="center" flex="1" anonid="button-box">
|
||||
<image class="button-icon"></image>
|
||||
<label class="button-text"></label>
|
||||
</hbox>`), true);
|
||||
Object.defineProperty(this, "buttonFragment", {value: frag});
|
||||
return frag;
|
||||
}
|
||||
|
||||
static get menuFragment() {
|
||||
let frag = document.importNode(MozXULElement.parseXULToFragment(`
|
||||
<hbox class="box-inherit button-box" align="center" pack="center" flex="1">
|
||||
<hbox class="box-inherit" align="center" pack="center" flex="1">
|
||||
<image class="button-icon"></image>
|
||||
<label class="button-text"></label>
|
||||
</hbox>
|
||||
<dropmarker class="button-menu-dropmarker"></dropmarker>
|
||||
</hbox>`), true);
|
||||
Object.defineProperty(this, "menuFragment", {value: frag});
|
||||
return frag;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.delayConnectedCallback() || this.hasConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hasConnected = true;
|
||||
|
||||
let fragment;
|
||||
if (this.type === "menu") {
|
||||
fragment = MozButton.menuFragment;
|
||||
|
||||
this.addEventListener("keypress", (event) => {
|
||||
if (event.keyCode != KeyEvent.DOM_VK_RETURN && event.key != " ") {
|
||||
return;
|
||||
}
|
||||
|
||||
this.open = true;
|
||||
// Prevent page from scrolling on the space key.
|
||||
if (event.key == " ") {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fragment = this.constructor.buttonFragment;
|
||||
}
|
||||
|
||||
this.appendChild(fragment.cloneNode(true));
|
||||
this.initializeAttributeInheritance();
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("button", MozButton);
|
||||
}
|
|
@ -189,44 +189,4 @@
|
|||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="button"
|
||||
extends="chrome://global/content/bindings/button.xml#button-base">
|
||||
<content>
|
||||
<children includes="observes|template|menupopup|panel|tooltip"/>
|
||||
<xul:hbox class="box-inherit button-box" xbl:inherits="align,dir,pack,orient"
|
||||
align="center" pack="center" flex="1" anonid="button-box">
|
||||
<xul:image class="button-icon" xbl:inherits="src=image"/>
|
||||
<xul:label class="button-text" xbl:inherits="value=label,accesskey,crop,highlightable"/>
|
||||
<xul:label class="button-highlightable-text" xbl:inherits="xbl:text=label,accesskey,crop,highlightable"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="menu"
|
||||
extends="chrome://global/content/bindings/button.xml#button">
|
||||
<content>
|
||||
<children includes="observes|template|menupopup|panel|tooltip"/>
|
||||
<xul:hbox class="box-inherit button-box" xbl:inherits="align,dir,pack,orient"
|
||||
align="center" pack="center" flex="1">
|
||||
<xul:hbox class="box-inherit" xbl:inherits="align,dir,pack,orient"
|
||||
align="center" pack="center" flex="1">
|
||||
<xul:image class="button-icon" xbl:inherits="src=image"/>
|
||||
<xul:label class="button-text" xbl:inherits="value=label,accesskey,crop"/>
|
||||
</xul:hbox>
|
||||
<xul:dropmarker class="button-menu-dropmarker" xbl:inherits="open,disabled,label"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
<handlers>
|
||||
<handler event="keypress" keycode="VK_RETURN" action="this.open = true;"/>
|
||||
<handler event="keypress" key=" ">
|
||||
<![CDATA[
|
||||
this.open = true;
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
|
|
@ -105,16 +105,6 @@ label html|span.accesskey {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/********** button **********/
|
||||
|
||||
button {
|
||||
-moz-binding: url("chrome://global/content/bindings/button.xml#button");
|
||||
}
|
||||
|
||||
button[type="menu"] {
|
||||
-moz-binding: url("chrome://global/content/bindings/button.xml#menu");
|
||||
}
|
||||
|
||||
/********** toolbarbutton **********/
|
||||
|
||||
toolbarbutton {
|
||||
|
@ -664,8 +654,6 @@ tabmodalprompt {
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
.button-highlightable-text:not([highlightable="true"]),
|
||||
.button-text[highlightable="true"],
|
||||
.menulist-highlightable-label:not([highlightable="true"]),
|
||||
.menulist-label[highlightable="true"],
|
||||
.menu-iconic-highlightable-text:not([highlightable="true"]),
|
||||
|
|
|
@ -692,6 +692,8 @@
|
|||
<implementation>
|
||||
<constructor><![CDATA[
|
||||
window.customElements.upgrade(this._stateMenulist);
|
||||
window.customElements.upgrade(this._enableBtn);
|
||||
window.customElements.upgrade(this._disableBtn);
|
||||
|
||||
this._installStatus = document.getAnonymousElementByAttribute(this, "anonid", "install-status");
|
||||
this._installStatus.mControl = this;
|
||||
|
|
|
@ -67,7 +67,15 @@ void remoteClientNotificationCallback(CFNotificationCenterRef aCenter, void* aOb
|
|||
// Autorelease pool to prevent memory leaks, in case there is no outer pool.
|
||||
mozilla::MacAutoreleasePool pool;
|
||||
NSDictionary* userInfoDict = (__bridge NSDictionary*)aUserInfo;
|
||||
if (userInfoDict && [userInfoDict objectForKey:@"commandLineArgs"]) {
|
||||
if (userInfoDict && [userInfoDict objectForKey:@"commandLineArgs"] &&
|
||||
[userInfoDict objectForKey:@"senderPath"]) {
|
||||
|
||||
NSString* senderPath = [userInfoDict objectForKey:@"senderPath"];
|
||||
if (![senderPath isEqual:[[NSBundle mainBundle] bundlePath]]) {
|
||||
// The caller is not the process at the same path as we are at. Skipping.
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray* args = [userInfoDict objectForKey:@"commandLineArgs"];
|
||||
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
||||
|
||||
|
@ -201,16 +209,28 @@ NS_IMETHODIMP nsNativeAppSupportCocoa::Start(bool* _retval) {
|
|||
if (!shallProceedLikeNoRemote) {
|
||||
// We check for other running instances only if -no-remote was not specified.
|
||||
// The check is needed so the marAppApplyUpdateSuccess.js test doesn't fail on next call.
|
||||
runningInstanceFound =
|
||||
[[NSRunningApplication
|
||||
runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]]
|
||||
count] > 1;
|
||||
NSArray* appsWithMatchingId = [NSRunningApplication runningApplicationsWithBundleIdentifier:
|
||||
[[NSBundle mainBundle] bundleIdentifier]];
|
||||
NSString* currentAppBundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
NSRunningApplication* currentApp = [NSRunningApplication currentApplication];
|
||||
for (NSRunningApplication* app in appsWithMatchingId) {
|
||||
if ([currentAppBundlePath isEqual:[[app bundleURL] path]] &&
|
||||
![currentApp isEqual:app]) {
|
||||
runningInstanceFound = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shallProceedLikeNoRemote && !mozillaRestarting && runningInstanceFound) {
|
||||
// There is another instance of this app already running!
|
||||
NSArray* arguments = [[NSProcessInfo processInfo] arguments];
|
||||
CFDictionaryRef userInfoDict = (__bridge CFDictionaryRef) @{@"commandLineArgs" : arguments};
|
||||
NSString* senderPath = [[NSBundle mainBundle] bundlePath];
|
||||
CFDictionaryRef userInfoDict = (__bridge CFDictionaryRef) @{@"commandLineArgs" :
|
||||
arguments,
|
||||
@"senderPath":
|
||||
senderPath
|
||||
};
|
||||
|
||||
// This code is shared between Firefox, Thunderbird and other Mozilla products.
|
||||
// So we need a notification name that is unique to the product, so we
|
||||
|
|
Загрузка…
Ссылка в новой задаче