зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to elm
--HG-- rename : mobile/android/base/resources/drawable-mdpi/crash_reporter.png => mobile/android/base/crashreporter/res/drawable-mdpi/crash_reporter.png rename : mobile/android/base/resources/layout/crash_reporter.xml => mobile/android/base/crashreporter/res/layout/crash_reporter.xml rename : mobile/android/branding/aurora/content/fennec_72x72.png => mobile/android/branding/aurora/res/drawable-hdpi/icon.png rename : mobile/android/branding/aurora/content/fennec_48x48.png => mobile/android/branding/aurora/res/drawable-mdpi/icon.png rename : mobile/android/branding/aurora/content/fennec_96x96.png => mobile/android/branding/aurora/res/drawable-xhdpi/icon.png rename : mobile/android/branding/aurora/content/fennec_144x144.png => mobile/android/branding/aurora/res/drawable-xxhdpi/icon.png rename : mobile/android/branding/beta/content/fennec_72x72.png => mobile/android/branding/beta/res/drawable-hdpi/icon.png rename : mobile/android/branding/beta/content/fennec_48x48.png => mobile/android/branding/beta/res/drawable-mdpi/icon.png rename : mobile/android/branding/beta/content/fennec_96x96.png => mobile/android/branding/beta/res/drawable-xhdpi/icon.png rename : mobile/android/branding/beta/content/fennec_144x144.png => mobile/android/branding/beta/res/drawable-xxhdpi/icon.png rename : mobile/android/branding/nightly/content/fennec_72x72.png => mobile/android/branding/nightly/res/drawable-hdpi/icon.png rename : mobile/android/branding/nightly/content/fennec_48x48.png => mobile/android/branding/nightly/res/drawable-mdpi/icon.png rename : mobile/android/branding/nightly/content/fennec_96x96.png => mobile/android/branding/nightly/res/drawable-xhdpi/icon.png rename : mobile/android/branding/nightly/content/fennec_144x144.png => mobile/android/branding/nightly/res/drawable-xxhdpi/icon.png rename : mobile/android/branding/official/content/fennec_72x72.png => mobile/android/branding/official/res/drawable-hdpi/icon.png rename : mobile/android/branding/official/content/fennec_48x48.png => mobile/android/branding/official/res/drawable-mdpi/icon.png rename : mobile/android/branding/official/content/fennec_96x96.png => mobile/android/branding/official/res/drawable-xhdpi/icon.png rename : mobile/android/branding/official/content/fennec_144x144.png => mobile/android/branding/official/res/drawable-xxhdpi/icon.png rename : mobile/android/branding/unofficial/content/fennec_72x72.png => mobile/android/branding/unofficial/res/drawable-hdpi/icon.png rename : mobile/android/branding/unofficial/content/fennec_48x48.png => mobile/android/branding/unofficial/res/drawable-mdpi/icon.png rename : mobile/android/branding/unofficial/content/fennec_96x96.png => mobile/android/branding/unofficial/res/drawable-xhdpi/icon.png rename : mobile/android/branding/unofficial/content/fennec_144x144.png => mobile/android/branding/unofficial/res/drawable-xxhdpi/icon.png
This commit is contained in:
Коммит
03c9e15f08
5
CLOBBER
5
CLOBBER
|
@ -18,4 +18,7 @@
|
|||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||
#
|
||||
|
||||
Bug 946067 required a clobber on Windows because bug 928195
|
||||
Bug 934646 needs a clobber -- the icon resources previously copied
|
||||
into $OBJDIR/mobile/android/base/res will conflict with those in
|
||||
$BRANDING_DIRECTORY/res.
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "States.h"
|
||||
|
||||
#include "nsContentList.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
#include "nsIAccessibleRelation.h"
|
||||
#include "nsIDOMNSEditableElement.h"
|
||||
|
@ -26,6 +25,7 @@
|
|||
#include "nsISelectionController.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsITextControlFrame.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -468,8 +468,7 @@ HTMLTextFieldAccessible::GetEditor() const
|
|||
// nsGenericHTMLElement::GetEditor has a security check.
|
||||
// Make sure we're not restricted by the permissions of
|
||||
// whatever script is currently running.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
mozilla::dom::AutoSystemCaller asc;
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editableElt->GetEditor(getter_AddRefs(editor));
|
||||
|
|
|
@ -87,8 +87,6 @@
|
|||
"infojobs.net": "\\(Mobile#(Android; Mobile",
|
||||
// bug 828399, antena3.com
|
||||
"antena3.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 828401, ingdirect.es
|
||||
"ingdirect.es": "\\(Mobile#(Android; Mobile",
|
||||
// bug 828403, fotocasa.es
|
||||
"fotocasa.es": "\\(Mobile#(Android; Mobile",
|
||||
// bug 828406, orange.es
|
||||
|
@ -107,8 +105,6 @@
|
|||
"movistar.com.ve": "\\(Mobile#(Android; Mobile",
|
||||
// bug 828445, bumeran.com.ve
|
||||
"bumeran.com.ve": "\\(Mobile#(Android; Mobile",
|
||||
// bug 828448, petardas.com
|
||||
"petardas.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843112, movil.bankinter.es
|
||||
"movil.bankinter.es": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843114, einforma.com
|
||||
|
@ -139,16 +135,12 @@
|
|||
"citibank.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843153, games.com
|
||||
"games.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843156, orbitz.com
|
||||
"orbitz.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843160, ehow.com
|
||||
"ehow.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843162, urbanspoon.com
|
||||
"urbanspoon.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843165, virginatlantic.com
|
||||
"virginatlantic.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843168, cheaptickets.com
|
||||
"cheaptickets.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843172, zimbio.com
|
||||
"zimbio.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 843176, tylted.com
|
||||
|
@ -171,8 +163,6 @@
|
|||
"hazipatika.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878234, hvg.hu
|
||||
"hvg.hu": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878236, jofogas.hu
|
||||
"jofogas.hu": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878238, koponyeg.hu
|
||||
"koponyeg.hu": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878240, kuruc.info
|
||||
|
@ -205,16 +195,12 @@
|
|||
"mondo.rs": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878277, naslovi.net
|
||||
"naslovi.net": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878284, softonic.com
|
||||
"softonic.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878630, ask.com
|
||||
"ask.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878632, banorte.com
|
||||
"banorte.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878637, eluniversal.com.mx
|
||||
"eluniversal.com.mx": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878640, hootsuite.com
|
||||
"hootsuite.com": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878642, mercadolibre.com.mx
|
||||
"mercadolibre.com.mx": "\\(Mobile#(Android; Mobile",
|
||||
// bug 878645, olx.com.mx
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "336e9464c144268a8902bbb2d9026be3ff2b327f",
|
||||
"revision": "5bfef5faac50d14e055f642a44ed2df8483fb2fe",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ MOZ_PLACES=
|
|||
MOZ_B2G=1
|
||||
|
||||
if test "$OS_TARGET" = "Android"; then
|
||||
MOZ_NUWA_PROCESS=0
|
||||
MOZ_NUWA_PROCESS=
|
||||
fi
|
||||
MOZ_FOLD_LIBS=1
|
||||
|
||||
|
|
|
@ -106,11 +106,6 @@ function appUpdater()
|
|||
this.bundle = Services.strings.
|
||||
createBundle("chrome://browser/locale/browser.properties");
|
||||
|
||||
this.updateBtn = document.getElementById("updateButton");
|
||||
|
||||
// The button label value must be set so its height is correct.
|
||||
this.setupUpdateButton("update.checkInsideButton");
|
||||
|
||||
let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual");
|
||||
let manualLink = document.getElementById("manualLink");
|
||||
manualLink.value = manualURL;
|
||||
|
@ -123,8 +118,7 @@ function appUpdater()
|
|||
}
|
||||
|
||||
if (this.isPending || this.isApplied) {
|
||||
this.setupUpdateButton("update.restart." +
|
||||
(this.isMajor ? "upgradeButton" : "updateButton"));
|
||||
this.selectPanel("apply");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -135,15 +129,19 @@ function appUpdater()
|
|||
|
||||
if (this.isDownloading) {
|
||||
this.startDownload();
|
||||
// selectPanel("downloading") is called from setupDownloadingUI().
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.updateEnabled && this.updateAuto) {
|
||||
this.selectPanel("checkingForUpdates");
|
||||
this.isChecking = true;
|
||||
this.checker.checkForUpdates(this.updateCheckListener, true);
|
||||
return;
|
||||
}
|
||||
// If app.update.enabled is false, we don't pop up an update dialog
|
||||
// automatically, but opening the About dialog is considered manually
|
||||
// checking for updates, so we always check.
|
||||
// If app.update.auto is false, we ask before downloading though,
|
||||
// in onCheckComplete.
|
||||
this.selectPanel("checkingForUpdates");
|
||||
this.isChecking = true;
|
||||
this.checker.checkForUpdates(this.updateCheckListener, true);
|
||||
// after checking, onCheckComplete() is called
|
||||
}
|
||||
|
||||
appUpdater.prototype =
|
||||
|
@ -180,13 +178,6 @@ appUpdater.prototype =
|
|||
this.um.activeUpdate.state == "downloading";
|
||||
},
|
||||
|
||||
// true when the update type is major.
|
||||
get isMajor() {
|
||||
if (this.update)
|
||||
return this.update.type == "major";
|
||||
return this.um.activeUpdate.type == "major";
|
||||
},
|
||||
|
||||
// true when updating is disabled by an administrator.
|
||||
get updateDisabledAndLocked() {
|
||||
return !this.updateEnabled &&
|
||||
|
@ -218,36 +209,54 @@ appUpdater.prototype =
|
|||
},
|
||||
|
||||
/**
|
||||
* Sets the deck's selected panel.
|
||||
* Sets the panel of the updateDeck.
|
||||
*
|
||||
* @param aChildID
|
||||
* The id of the deck's child to select.
|
||||
* The id of the deck's child to select, e.g. "apply".
|
||||
*/
|
||||
selectPanel: function(aChildID) {
|
||||
this.updateDeck.selectedPanel = document.getElementById(aChildID);
|
||||
this.updateBtn.disabled = (aChildID != "updateButtonBox");
|
||||
let panel = document.getElementById(aChildID);
|
||||
|
||||
let button = panel.querySelector("button");
|
||||
if (button) {
|
||||
if (aChildID == "downloadAndInstall") {
|
||||
let updateVersion = gAppUpdater.update.displayVersion;
|
||||
button.label = this.bundle.formatStringFromName("update.downloadAndInstallButton.label", [updateVersion], 1);
|
||||
button.accessKey = this.bundle.GetStringFromName("update.downloadAndInstallButton.accesskey");
|
||||
}
|
||||
this.updateDeck.selectedPanel = panel;
|
||||
if (!document.commandDispatcher.focusedElement || // don't steal the focus
|
||||
document.commandDispatcher.focusedElement.localName == "button") // except from the other buttons
|
||||
button.focus();
|
||||
|
||||
} else {
|
||||
this.updateDeck.selectedPanel = panel;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the update button's label and accesskey.
|
||||
*
|
||||
* @param aKeyPrefix
|
||||
* The prefix for the properties file entry to use for setting the
|
||||
* label and accesskey.
|
||||
* Check for addon compat, or start the download right away
|
||||
*/
|
||||
setupUpdateButton: function(aKeyPrefix) {
|
||||
this.updateBtn.label = this.bundle.GetStringFromName(aKeyPrefix + ".label");
|
||||
this.updateBtn.accessKey = this.bundle.GetStringFromName(aKeyPrefix + ".accesskey");
|
||||
if (!document.commandDispatcher.focusedElement ||
|
||||
document.commandDispatcher.focusedElement == this.updateBtn)
|
||||
this.updateBtn.focus();
|
||||
doUpdate: function() {
|
||||
// skip the compatibility check if the update doesn't provide appVersion,
|
||||
// or the appVersion is unchanged, e.g. nightly update
|
||||
if (!this.update.appVersion ||
|
||||
Services.vc.compare(gAppUpdater.update.appVersion,
|
||||
Services.appinfo.version) == 0) {
|
||||
this.startDownload();
|
||||
} else {
|
||||
this.checkAddonCompatibility();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles oncommand for the update button.
|
||||
* Handles oncommand for the "Restart to Update" button
|
||||
* which is presented after the download has been downloaded.
|
||||
*/
|
||||
buttonOnCommand: function() {
|
||||
if (this.isPending || this.isApplied) {
|
||||
buttonRestartAfterDownload: function() {
|
||||
if (!this.isPending && !this.isApplied)
|
||||
return;
|
||||
|
||||
// Notify all windows that an application quit has been requested.
|
||||
let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
|
||||
createInstance(Components.interfaces.nsISupportsPRBool);
|
||||
|
@ -268,27 +277,21 @@ appUpdater.prototype =
|
|||
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
|
||||
Components.interfaces.nsIAppStartup.eRestart);
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles oncommand for the "Apply Update…" button
|
||||
* which is presented if we need to show the billboard or license.
|
||||
*/
|
||||
buttonApplyBillboard: function() {
|
||||
const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul";
|
||||
// Firefox no longer displays a license for updates and the licenseURL check
|
||||
// is just in case a distibution does.
|
||||
if (this.update && (this.update.billboardURL || this.update.licenseURL ||
|
||||
this.addons.length != 0)) {
|
||||
var ary = null;
|
||||
ary = Components.classes["@mozilla.org/supports-array;1"].
|
||||
createInstance(Components.interfaces.nsISupportsArray);
|
||||
ary.AppendElement(this.update);
|
||||
var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no";
|
||||
Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary);
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectPanel("checkingForUpdates");
|
||||
this.isChecking = true;
|
||||
this.checker.checkForUpdates(this.updateCheckListener, true);
|
||||
var ary = null;
|
||||
ary = Components.classes["@mozilla.org/supports-array;1"].
|
||||
createInstance(Components.interfaces.nsISupportsArray);
|
||||
ary.AppendElement(this.update);
|
||||
var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no";
|
||||
Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary);
|
||||
window.close(); // close the "About" window; updates.xul takes over.
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -326,21 +329,14 @@ appUpdater.prototype =
|
|||
// Firefox no longer displays a license for updates and the licenseURL
|
||||
// check is just in case a distibution does.
|
||||
if (gAppUpdater.update.billboardURL || gAppUpdater.update.licenseURL) {
|
||||
gAppUpdater.selectPanel("updateButtonBox");
|
||||
gAppUpdater.setupUpdateButton("update.openUpdateUI." +
|
||||
(this.isMajor ? "upgradeButton"
|
||||
: "applyButton"));
|
||||
gAppUpdater.selectPanel("applyBillboard");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gAppUpdater.update.appVersion ||
|
||||
Services.vc.compare(gAppUpdater.update.appVersion,
|
||||
Services.appinfo.version) == 0) {
|
||||
gAppUpdater.startDownload();
|
||||
return;
|
||||
}
|
||||
|
||||
gAppUpdater.checkAddonCompatibility();
|
||||
if (gAppUpdater.updateAuto) // automatically download and install
|
||||
gAppUpdater.doUpdate();
|
||||
else // ask
|
||||
gAppUpdater.selectPanel("downloadAndInstall");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -474,9 +470,7 @@ appUpdater.prototype =
|
|||
return;
|
||||
}
|
||||
|
||||
this.selectPanel("updateButtonBox");
|
||||
this.setupUpdateButton("update.openUpdateUI." +
|
||||
(this.isMajor ? "upgradeButton" : "applyButton"));
|
||||
this.selectPanel("apply");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -553,11 +547,9 @@ appUpdater.prototype =
|
|||
if (status == "applied" || status == "applied-service" ||
|
||||
status == "pending" || status == "pending-service") {
|
||||
// If the update is successfully applied, or if the updater has
|
||||
// fallen back to non-staged updates, show the Restart to Update
|
||||
// fallen back to non-staged updates, show the "Restart to Update"
|
||||
// button.
|
||||
self.selectPanel("updateButtonBox");
|
||||
self.setupUpdateButton("update.restart." +
|
||||
(self.isMajor ? "upgradeButton" : "updateButton"));
|
||||
self.selectPanel("apply");
|
||||
} else if (status == "failed") {
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
|
@ -572,9 +564,7 @@ appUpdater.prototype =
|
|||
Services.obs.removeObserver(arguments.callee, "update-staged");
|
||||
}, "update-staged", false);
|
||||
} else {
|
||||
this.selectPanel("updateButtonBox");
|
||||
this.setupUpdateButton("update.restart." +
|
||||
(this.isMajor ? "upgradeButton" : "updateButton"));
|
||||
this.selectPanel("apply");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -582,7 +572,6 @@ appUpdater.prototype =
|
|||
this.selectPanel("downloadFailed");
|
||||
break;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,17 +50,29 @@
|
|||
<vbox id="updateBox">
|
||||
#ifdef MOZ_UPDATER
|
||||
<deck id="updateDeck" orient="vertical">
|
||||
<hbox id="updateButtonBox" align="center">
|
||||
<hbox id="downloadAndInstall" align="center">
|
||||
<button id="downloadAndInstallButton" align="start"
|
||||
oncommand="gAppUpdater.doUpdate();"/>
|
||||
<!-- label and accesskey will be filled by JS -->
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
<hbox id="apply" align="center">
|
||||
<button id="updateButton" align="start"
|
||||
oncommand="gAppUpdater.buttonOnCommand();"/>
|
||||
label="&update.updateButton.label;"
|
||||
accesskey="&update.updateButton.accesskey;"
|
||||
oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
<hbox id="applyBillboard" align="center">
|
||||
<button id="applyButtonBillboard" align="start"
|
||||
label="&update.applyButtonBillboard.label;"
|
||||
accesskey="&update.applyButtonBillboard.accesskey;"
|
||||
oncommand="gAppUpdater.buttonApplyBillboard();"/>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
<hbox id="checkingForUpdates" align="center">
|
||||
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
|
||||
</hbox>
|
||||
<hbox id="checkingAddonCompat" align="center">
|
||||
<image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
|
||||
</hbox>
|
||||
<hbox id="downloading" align="center">
|
||||
<image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
|
||||
</hbox>
|
||||
|
|
|
@ -457,10 +457,17 @@ let CustomizableUIInternal = {
|
|||
|
||||
// If the placements have items in them which are (now) no longer removable,
|
||||
// we shouldn't be moving them:
|
||||
if (node.parentNode != container && !this.isWidgetRemovable(node)) {
|
||||
if (provider == CustomizableUI.PROVIDER_API) {
|
||||
let widgetInfo = gPalette.get(id);
|
||||
if (!widgetInfo.removable && aArea != widgetInfo.defaultArea) {
|
||||
placementsToRemove.add(id);
|
||||
continue;
|
||||
}
|
||||
} else if (provider == CustomizableUI.PROVIDER_XUL &&
|
||||
node.parentNode != container && !this.isWidgetRemovable(node)) {
|
||||
placementsToRemove.add(id);
|
||||
continue;
|
||||
}
|
||||
} // Special widgets are always removable, so no need to check them
|
||||
|
||||
if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
|
||||
let widget = gPalette.get(id);
|
||||
|
@ -1736,7 +1743,7 @@ let CustomizableUIInternal = {
|
|||
source: aSource || "addon",
|
||||
instances: new Map(),
|
||||
currentArea: null,
|
||||
removable: false,
|
||||
removable: true,
|
||||
overflows: true,
|
||||
defaultArea: null,
|
||||
shortcutId: null,
|
||||
|
@ -1778,6 +1785,11 @@ let CustomizableUIInternal = {
|
|||
|
||||
if (aData.defaultArea && gAreas.has(aData.defaultArea)) {
|
||||
widget.defaultArea = aData.defaultArea;
|
||||
} else if (!widget.removable) {
|
||||
ERROR("Widget '" + widget.id + "' is not removable but does not specify " +
|
||||
"a valid defaultArea. That's not possible; it must specify a " +
|
||||
"valid defaultArea as well.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if ("type" in aData && gSupportedWidgetTypes.has(aData.type)) {
|
||||
|
@ -2383,11 +2395,13 @@ this.CustomizableUI = {
|
|||
* invoked when a user hides your view.
|
||||
* - tooltiptext: string to use for the tooltip of the widget
|
||||
* - label: string to use for the label of the widget
|
||||
* - removable: whether the widget is removable (optional, default: false)
|
||||
* - removable: whether the widget is removable (optional, default: true)
|
||||
* NB: if you specify false here, you must provide a
|
||||
* defaultArea, too.
|
||||
* - overflows: whether widget can overflow when in an overflowable
|
||||
* toolbar (optional, default: true)
|
||||
* - defaultArea: default area to add the widget to
|
||||
* (optional, default: none)
|
||||
* (optional, default: none; required if non-removable)
|
||||
* - shortcutId: id of an element that has a shortcut for this widget
|
||||
* (optional, default: null). This is only used to display
|
||||
* the shortcut as part of the tooltip for builtin widgets
|
||||
|
|
|
@ -61,7 +61,6 @@ const CustomizableWidgets = [{
|
|||
type: "view",
|
||||
viewId: "PanelUI-history",
|
||||
shortcutId: "key_gotoHistory",
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onViewShowing: function(aEvent) {
|
||||
// Populate our list of history
|
||||
|
@ -148,7 +147,6 @@ const CustomizableWidgets = [{
|
|||
}
|
||||
}, {
|
||||
id: "privatebrowsing-button",
|
||||
removable: true,
|
||||
shortcutId: "key_privatebrowsing",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(e) {
|
||||
|
@ -161,7 +159,6 @@ const CustomizableWidgets = [{
|
|||
}
|
||||
}, {
|
||||
id: "save-page-button",
|
||||
removable: true,
|
||||
shortcutId: "key_savePage",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
|
@ -174,7 +171,6 @@ const CustomizableWidgets = [{
|
|||
}
|
||||
}, {
|
||||
id: "find-button",
|
||||
removable: true,
|
||||
shortcutId: "key_find",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
|
@ -187,7 +183,6 @@ const CustomizableWidgets = [{
|
|||
}
|
||||
}, {
|
||||
id: "open-file-button",
|
||||
removable: true,
|
||||
shortcutId: "openFileKb",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
|
@ -202,7 +197,6 @@ const CustomizableWidgets = [{
|
|||
id: "developer-button",
|
||||
type: "view",
|
||||
viewId: "PanelUI-developer",
|
||||
removable: true,
|
||||
shortcutId: "key_devToolboxMenuItem",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onViewShowing: function(aEvent) {
|
||||
|
@ -265,7 +259,6 @@ const CustomizableWidgets = [{
|
|||
}
|
||||
}, {
|
||||
id: "add-ons-button",
|
||||
removable: true,
|
||||
shortcutId: "key_openAddons",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
|
@ -278,7 +271,6 @@ const CustomizableWidgets = [{
|
|||
}
|
||||
}, {
|
||||
id: "preferences-button",
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
#ifdef XP_WIN
|
||||
label: "preferences-button.labelWin",
|
||||
|
@ -295,7 +287,6 @@ const CustomizableWidgets = [{
|
|||
}, {
|
||||
id: "zoom-controls",
|
||||
type: "custom",
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onBuild: function(aDocument) {
|
||||
const kPanelId = "PanelUI-popup";
|
||||
|
@ -441,7 +432,6 @@ const CustomizableWidgets = [{
|
|||
}, {
|
||||
id: "edit-controls",
|
||||
type: "custom",
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onBuild: function(aDocument) {
|
||||
let inPanel = (this.currentArea == CustomizableUI.AREA_PANEL);
|
||||
|
@ -536,7 +526,6 @@ const CustomizableWidgets = [{
|
|||
id: "feed-button",
|
||||
type: "view",
|
||||
viewId: "PanelUI-feeds",
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onClick: function(aEvent) {
|
||||
let win = aEvent.target.ownerDocument.defaultView;
|
||||
|
@ -576,7 +565,6 @@ const CustomizableWidgets = [{
|
|||
id: "characterencoding-button",
|
||||
type: "view",
|
||||
viewId: "PanelUI-characterEncodingView",
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
maybeDisableMenu: function(aDocument) {
|
||||
let window = aDocument.defaultView;
|
||||
|
@ -783,7 +771,6 @@ const CustomizableWidgets = [{
|
|||
}
|
||||
}, {
|
||||
id: "email-link-button",
|
||||
removable: true,
|
||||
onCommand: function(aEvent) {
|
||||
let win = aEvent.view;
|
||||
win.MailIntegration.sendLinkForWindow(win.content);
|
||||
|
@ -801,7 +788,6 @@ if (Services.sysinfo.getProperty("hasWindowsTouchInterface")) {
|
|||
id: "switch-to-metro-button",
|
||||
label: "switch-to-metro-button2.label",
|
||||
tooltiptext: metroTooltip,
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
showInPrivateBrowsing: false, /* See bug 928068 */
|
||||
onCommand: function(aEvent) {
|
||||
|
|
|
@ -45,4 +45,5 @@ skip-if = os == "mac"
|
|||
[browser_942581_unregisterArea_keeps_placements.js]
|
||||
[browser_943683_migration_test.js]
|
||||
[browser_944887_destroyWidget_should_destroy_in_palette.js]
|
||||
[browser_947987_removable_default.js]
|
||||
[browser_panel_toggle.js]
|
||||
|
|
|
@ -10,16 +10,17 @@ let gTests = [
|
|||
let navbar = document.getElementById("nav-bar");
|
||||
ok(CustomizableUI.inDefaultState, "Should start in default state");
|
||||
|
||||
CustomizableUI.createWidget({id: kWidgetId, removable: false, label: "Test"});
|
||||
let button = createDummyXULButton(kWidgetId, "Test non-removable inDefaultState handling");
|
||||
CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_NAVBAR);
|
||||
button.setAttribute("removable", "false");
|
||||
ok(CustomizableUI.inDefaultState, "Should still be in default state after navbar addition");
|
||||
CustomizableUI.destroyWidget(kWidgetId);
|
||||
button.remove();
|
||||
|
||||
CustomizableUI.createWidget({id: kWidgetId, removable: false, label: "Test"});
|
||||
button = createDummyXULButton(kWidgetId, "Test non-removable inDefaultState handling");
|
||||
CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_PANEL);
|
||||
button.setAttribute("removable", "false");
|
||||
ok(CustomizableUI.inDefaultState, "Should still be in default state after panel addition");
|
||||
CustomizableUI.destroyWidget(kWidgetId);
|
||||
|
||||
button.remove();
|
||||
ok(CustomizableUI.inDefaultState, "Should be in default state after destroying both widgets");
|
||||
},
|
||||
teardown: null
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* 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/. */
|
||||
|
||||
let kWidgetId = "test-removable-widget-default";
|
||||
const kNavBar = CustomizableUI.AREA_NAVBAR;
|
||||
let widgetCounter = 0;
|
||||
let gTests = [
|
||||
{
|
||||
desc: "Sanity checks",
|
||||
run: function() {
|
||||
let brokenSpec = {id: kWidgetId + (widgetCounter++), removable: false};
|
||||
SimpleTest.doesThrow(function() CustomizableUI.createWidget(brokenSpec),
|
||||
"Creating non-removable widget without defaultArea should throw.");
|
||||
|
||||
// Widget without removable set should be removable:
|
||||
let wrapper = CustomizableUI.createWidget({id: kWidgetId + (widgetCounter++)});
|
||||
ok(CustomizableUI.isWidgetRemovable(wrapper.id), "Should be removable by default.");
|
||||
CustomizableUI.destroyWidget(wrapper.id);
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test non-removable widget with defaultArea",
|
||||
run: function() {
|
||||
// Non-removable widget with defaultArea should work:
|
||||
let spec = {id: kWidgetId + (widgetCounter++), removable: false,
|
||||
defaultArea: kNavBar};
|
||||
let widgetWrapper;
|
||||
try {
|
||||
widgetWrapper = CustomizableUI.createWidget(spec);
|
||||
} catch (ex) {
|
||||
ok(false, "Creating a non-removable widget with a default area should not throw.");
|
||||
return;
|
||||
}
|
||||
|
||||
let placement = CustomizableUI.getPlacementOfWidget(spec.id);
|
||||
ok(placement, "Widget should be placed.");
|
||||
is(placement.area, kNavBar, "Widget should be in navbar");
|
||||
let singleWrapper = widgetWrapper.forWindow(window);
|
||||
ok(singleWrapper, "Widget should exist in window.");
|
||||
ok(singleWrapper.node, "Widget node should exist in window.");
|
||||
let expectedParent = CustomizableUI.getCustomizeTargetForArea(kNavBar, window);
|
||||
is(singleWrapper.node.parentNode, expectedParent, "Widget should be in navbar.");
|
||||
|
||||
let otherWin = yield openAndLoadWindow(true);
|
||||
placement = CustomizableUI.getPlacementOfWidget(spec.id);
|
||||
ok(placement, "Widget should be placed.");
|
||||
is(placement && placement.area, kNavBar, "Widget should be in navbar");
|
||||
|
||||
singleWrapper = widgetWrapper.forWindow(otherWin);
|
||||
ok(singleWrapper, "Widget should exist in other window.");
|
||||
if (singleWrapper) {
|
||||
ok(singleWrapper.node, "Widget node should exist in other window.");
|
||||
if (singleWrapper.node) {
|
||||
let expectedParent = CustomizableUI.getCustomizeTargetForArea(kNavBar, otherWin);
|
||||
is(singleWrapper.node.parentNode, expectedParent,
|
||||
"Widget should be in navbar in other window.");
|
||||
}
|
||||
}
|
||||
otherWin.close();
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
function asyncCleanup() {
|
||||
yield resetCustomization();
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
removeCustomToolbars();
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(cleanup);
|
||||
runTests(gTests, asyncCleanup);
|
||||
}
|
||||
|
||||
|
|
@ -170,9 +170,7 @@ function addWindow(windowOptions, callback) {
|
|||
|
||||
let win = OpenBrowserWindow(windowOptions);
|
||||
|
||||
let onLoad = function() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
|
||||
whenDelayedStartupFinished(win, function() {
|
||||
// Would like to get rid of this executeSoon, but without it the url
|
||||
// (TEST_URI) provided in addTabWithToolbarRunTests hasn't loaded
|
||||
executeSoon(function() {
|
||||
|
@ -187,9 +185,7 @@ function addWindow(windowOptions, callback) {
|
|||
deferred.reject(ex);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
win.addEventListener("load", onLoad, false);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,15 @@ let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
|||
Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
|
||||
Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this);
|
||||
|
||||
function whenDelayedStartupFinished(aWindow, aCallback) {
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic) {
|
||||
if (aWindow == aSubject) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
executeSoon(aCallback);
|
||||
}
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force GC on shutdown, because it seems that GCLI can outrun the garbage
|
||||
* collector in some situations, which causes test failures in later tests
|
||||
|
|
|
@ -31,3 +31,4 @@ support-files =
|
|||
[browser_toolbar_tooltip.js]
|
||||
[browser_toolbar_webconsole_errors_count.js]
|
||||
[browser_spectrum.js]
|
||||
[browser_csstransformpreview.js]
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that the spectrum color picker works correctly
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,<div></div>";
|
||||
const {CSSTransformPreviewer} = devtools.require("devtools/shared/widgets/CSSTransformPreviewer");
|
||||
|
||||
let doc, root;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
addTab(TEST_URI, () => {
|
||||
doc = content.document;
|
||||
root = doc.querySelector("div");
|
||||
startTests();
|
||||
});
|
||||
}
|
||||
|
||||
function endTests() {
|
||||
doc = root = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
testCreateAndDestroyShouldAppendAndRemoveElements();
|
||||
}
|
||||
|
||||
function testCreateAndDestroyShouldAppendAndRemoveElements() {
|
||||
ok(root, "We have the root node to append the preview to");
|
||||
is(root.childElementCount, 0, "Root node is empty");
|
||||
|
||||
let p = new CSSTransformPreviewer(root);
|
||||
p.preview("matrix(1, -0.2, 0, 1, 0, 0)");
|
||||
ok(root.childElementCount > 0, "Preview has appended elements");
|
||||
ok(root.querySelector("canvas"), "Canvas preview element is here");
|
||||
|
||||
p.destroy();
|
||||
is(root.childElementCount, 0, "Destroying preview removed all nodes");
|
||||
|
||||
testCanvasDimensionIsConstrainedByMaxDim();
|
||||
}
|
||||
|
||||
function testCanvasDimensionIsConstrainedByMaxDim() {
|
||||
let p = new CSSTransformPreviewer(root);
|
||||
p.MAX_DIM = 500;
|
||||
p.preview("scale(1)", "center", 1000, 1000);
|
||||
|
||||
let canvas = root.querySelector("canvas");
|
||||
is(canvas.width, 500, "Canvas width is correct");
|
||||
is(canvas.height, 500, "Canvas height is correct");
|
||||
|
||||
p.destroy();
|
||||
|
||||
testCallingPreviewSeveralTimesReusesTheSameCanvas();
|
||||
}
|
||||
|
||||
function testCallingPreviewSeveralTimesReusesTheSameCanvas() {
|
||||
let p = new CSSTransformPreviewer(root);
|
||||
|
||||
p.preview("scale(1)", "center", 1000, 1000);
|
||||
let canvas = root.querySelector("canvas");
|
||||
|
||||
p.preview("rotate(90deg)");
|
||||
let canvases = root.querySelectorAll("canvas");
|
||||
is(canvases.length, 1, "Still one canvas element");
|
||||
is(canvases[0], canvas, "Still the same canvas element");
|
||||
p.destroy();
|
||||
|
||||
testCanvasDimensionAreCorrect();
|
||||
}
|
||||
|
||||
function testCanvasDimensionAreCorrect() {
|
||||
// Only test a few simple transformations
|
||||
let p = new CSSTransformPreviewer(root);
|
||||
|
||||
// Make sure we have a square
|
||||
let w = 200, h = w;
|
||||
p.MAX_DIM = w;
|
||||
|
||||
// We can't test the content of the canvas here, just that, given a max width
|
||||
// the aspect ratio of the canvas seems correct.
|
||||
|
||||
// Translate a square by its width, should be a rectangle
|
||||
p.preview("translateX(200px)", "center", w, h);
|
||||
let canvas = root.querySelector("canvas");
|
||||
is(canvas.width, w, "width is correct");
|
||||
is(canvas.height, h/2, "height is half of the width");
|
||||
|
||||
// Rotate on the top right corner, should be a rectangle
|
||||
p.preview("rotate(-90deg)", "top right", w, h);
|
||||
is(canvas.width, w, "width is correct");
|
||||
is(canvas.height, h/2, "height is half of the width");
|
||||
|
||||
// Rotate on the bottom left corner, should be a rectangle
|
||||
p.preview("rotate(90deg)", "top right", w, h);
|
||||
is(canvas.width, w/2, "width is half of the height");
|
||||
is(canvas.height, h, "height is correct");
|
||||
|
||||
// Scale from center, should still be a square
|
||||
p.preview("scale(2)", "center", w, h);
|
||||
is(canvas.width, w, "width is correct");
|
||||
is(canvas.height, h, "height is correct");
|
||||
|
||||
// Skew from center, 45deg, should be a rectangle
|
||||
p.preview("skew(45deg)", "center", w, h);
|
||||
is(canvas.width, w, "width is correct");
|
||||
is(canvas.height, h/2, "height is half of the height");
|
||||
|
||||
p.destroy();
|
||||
|
||||
testPreviewingInvalidTransformReturnsFalse();
|
||||
}
|
||||
|
||||
function testPreviewingInvalidTransformReturnsFalse() {
|
||||
let p = new CSSTransformPreviewer(root);
|
||||
ok(!p.preview("veryWow(muchPx) suchTransform(soDeg)"), "Returned false for invalid transform");
|
||||
ok(!p.preview("rotae(3deg)"), "Returned false for invalid transform");
|
||||
|
||||
// Verify the canvas is empty by checking the image data
|
||||
let canvas = root.querySelector("canvas"), ctx = canvas.getContext("2d");
|
||||
let data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
|
||||
for (let i = 0, n = data.length; i < n; i += 4) {
|
||||
// Let's not log 250*250*4 asserts! Instead, just log when it fails
|
||||
let red = data[i];
|
||||
let green = data[i + 1];
|
||||
let blue = data[i + 2];
|
||||
let alpha = data[i + 3];
|
||||
if (red !== 0 || green !== 0 || blue !== 0 || alpha !== 0) {
|
||||
ok(false, "Image data is not empty after an invalid transformed was previewed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
is(p.preview("translateX(30px)"), true, "Returned true for a valid transform");
|
||||
endTests();
|
||||
}
|
|
@ -0,0 +1,389 @@
|
|||
/* 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";
|
||||
|
||||
/**
|
||||
* The CSSTransformPreview module displays, using a <canvas> a rectangle, with
|
||||
* a given width and height and its transformed version, given a css transform
|
||||
* property and origin. It also displays arrows from/to each corner.
|
||||
*
|
||||
* It is useful to visualize how a css transform affected an element. It can
|
||||
* help debug tricky transformations. It is used today in a tooltip, and this
|
||||
* tooltip is shown when hovering over a css transform declaration in the rule
|
||||
* and computed view panels.
|
||||
*
|
||||
* TODO: For now, it multiplies matrices itself to calculate the coordinates of
|
||||
* the transformed box, but that should be removed as soon as we can get access
|
||||
* to getQuads().
|
||||
*/
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
/**
|
||||
* The TransformPreview needs an element to output a canvas tag.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* let t = new CSSTransformPreviewer(myRootElement);
|
||||
* t.preview("rotate(45deg)", "top left", 200, 400);
|
||||
* t.preview("skew(19deg)", "center", 100, 500);
|
||||
* t.preview("matrix(1, -0.2, 0, 1, 0, 0)");
|
||||
* t.destroy();
|
||||
*
|
||||
* @param {nsIDOMElement} parentEl
|
||||
* Where the canvas will go
|
||||
*/
|
||||
function CSSTransformPreviewer(parentEl) {
|
||||
this.parentEl = parentEl;
|
||||
this.doc = this.parentEl.ownerDocument;
|
||||
this.canvas = null;
|
||||
this.ctx = null;
|
||||
}
|
||||
|
||||
module.exports.CSSTransformPreviewer = CSSTransformPreviewer;
|
||||
|
||||
CSSTransformPreviewer.prototype = {
|
||||
/**
|
||||
* The preview look-and-feel can be changed using these properties
|
||||
*/
|
||||
MAX_DIM: 250,
|
||||
PAD: 5,
|
||||
ORIGINAL_FILL: "#1F303F",
|
||||
ORIGINAL_STROKE: "#B2D8FF",
|
||||
TRANSFORMED_FILL: "rgba(200, 200, 200, .5)",
|
||||
TRANSFORMED_STROKE: "#B2D8FF",
|
||||
ARROW_STROKE: "#329AFF",
|
||||
ORIGIN_STROKE: "#329AFF",
|
||||
ARROW_TIP_HEIGHT: 10,
|
||||
ARROW_TIP_WIDTH: 8,
|
||||
CORNER_SIZE_RATIO: 6,
|
||||
|
||||
/**
|
||||
* Destroy removes the canvas from the parentelement passed in the constructor
|
||||
*/
|
||||
destroy: function() {
|
||||
if (this.canvas) {
|
||||
this.parentEl.removeChild(this.canvas);
|
||||
}
|
||||
if (this._hiddenDiv) {
|
||||
this.parentEl.removeChild(this._hiddenDiv);
|
||||
}
|
||||
this.parentEl = this.canvas = this.ctx = this.doc = null;
|
||||
},
|
||||
|
||||
_createMarkup: function() {
|
||||
this.canvas = this.doc.createElementNS(HTML_NS, "canvas");
|
||||
|
||||
this.canvas.setAttribute("id", "canvas");
|
||||
this.canvas.setAttribute("width", this.MAX_DIM);
|
||||
this.canvas.setAttribute("height", this.MAX_DIM);
|
||||
this.canvas.style.position = "relative";
|
||||
this.parentEl.appendChild(this.canvas);
|
||||
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
},
|
||||
|
||||
_getComputed: function(name, value, width, height) {
|
||||
if (!this._hiddenDiv) {
|
||||
// Create a hidden element to apply the style to
|
||||
this._hiddenDiv = this.doc.createElementNS(HTML_NS, "div");
|
||||
this._hiddenDiv.style.visibility = "hidden";
|
||||
this._hiddenDiv.style.position = "absolute";
|
||||
this.parentEl.appendChild(this._hiddenDiv);
|
||||
}
|
||||
|
||||
// Camelcase the name
|
||||
name = name.replace(/-([a-z]{1})/g, (m, letter) => letter.toUpperCase());
|
||||
|
||||
// Apply width and height to make sure computation is made correctly
|
||||
this._hiddenDiv.style.width = width + "px";
|
||||
this._hiddenDiv.style.height = height + "px";
|
||||
|
||||
// Show the hidden div, apply the style, read the computed style, hide the
|
||||
// hidden div again
|
||||
this._hiddenDiv.style.display = "block";
|
||||
this._hiddenDiv.style[name] = value;
|
||||
let computed = this.doc.defaultView.getComputedStyle(this._hiddenDiv);
|
||||
let computedValue = computed[name];
|
||||
this._hiddenDiv.style.display = "none";
|
||||
|
||||
return computedValue;
|
||||
},
|
||||
|
||||
_getMatrixFromTransformString: function(transformStr) {
|
||||
let matrix = transformStr.substring(0, transformStr.length - 1).
|
||||
substring(transformStr.indexOf("(") + 1).split(",");
|
||||
|
||||
matrix.forEach(function(value, index) {
|
||||
matrix[index] = parseFloat(value, 10);
|
||||
});
|
||||
|
||||
let transformMatrix = null;
|
||||
|
||||
if (matrix.length === 6) {
|
||||
// 2d transform
|
||||
transformMatrix = [
|
||||
[matrix[0], matrix[2], matrix[4], 0],
|
||||
[matrix[1], matrix[3], matrix[5], 0],
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 0, 1]
|
||||
];
|
||||
} else {
|
||||
// 3d transform
|
||||
transformMatrix = [
|
||||
[matrix[0], matrix[4], matrix[8], matrix[12]],
|
||||
[matrix[1], matrix[5], matrix[9], matrix[13]],
|
||||
[matrix[2], matrix[6], matrix[10], matrix[14]],
|
||||
[matrix[3], matrix[7], matrix[11], matrix[15]]
|
||||
];
|
||||
}
|
||||
|
||||
return transformMatrix;
|
||||
},
|
||||
|
||||
_getOriginFromOriginString: function(originStr) {
|
||||
let offsets = originStr.split(" ");
|
||||
offsets.forEach(function(item, index) {
|
||||
offsets[index] = parseInt(item, 10);
|
||||
});
|
||||
|
||||
return offsets;
|
||||
},
|
||||
|
||||
_multiply: function(m1, m2) {
|
||||
let m = [];
|
||||
for (let m1Line = 0; m1Line < m1.length; m1Line++) {
|
||||
m[m1Line] = 0;
|
||||
for (let m2Col = 0; m2Col < m2.length; m2Col++) {
|
||||
m[m1Line] += m1[m1Line][m2Col] * m2[m2Col];
|
||||
}
|
||||
}
|
||||
return [m[0], m[1]];
|
||||
},
|
||||
|
||||
_getTransformedPoint: function(matrix, point, origin) {
|
||||
let pointMatrix = [point[0] - origin[0], point[1] - origin[1], 1, 1];
|
||||
return this._multiply(matrix, pointMatrix);
|
||||
},
|
||||
|
||||
_getTransformedPoints: function(matrix, rect, origin) {
|
||||
return rect.map(point => {
|
||||
let tPoint = this._getTransformedPoint(matrix, [point[0], point[1]], origin);
|
||||
return [tPoint[0] + origin[0], tPoint[1] + origin[1]];
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* For canvas to avoid anti-aliasing
|
||||
*/
|
||||
_round: x => Math.round(x) + .5,
|
||||
|
||||
_drawShape: function(points, fillStyle, strokeStyle) {
|
||||
this.ctx.save();
|
||||
|
||||
this.ctx.lineWidth = 1;
|
||||
this.ctx.strokeStyle = strokeStyle;
|
||||
this.ctx.fillStyle = fillStyle;
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(this._round(points[0][0]), this._round(points[0][1]));
|
||||
for (var i = 1; i < points.length; i++) {
|
||||
this.ctx.lineTo(this._round(points[i][0]), this._round(points[i][1]));
|
||||
}
|
||||
this.ctx.lineTo(this._round(points[0][0]), this._round(points[0][1]));
|
||||
this.ctx.fill();
|
||||
this.ctx.stroke();
|
||||
|
||||
this.ctx.restore();
|
||||
},
|
||||
|
||||
_drawArrow: function(x1, y1, x2, y2) {
|
||||
// do not draw if the line is too small
|
||||
if (Math.abs(x2-x1) < 20 && Math.abs(y2-y1) < 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.ctx.save();
|
||||
|
||||
this.ctx.strokeStyle = this.ARROW_STROKE;
|
||||
this.ctx.fillStyle = this.ARROW_STROKE;
|
||||
this.ctx.lineWidth = 1;
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(this._round(x1), this._round(y1));
|
||||
this.ctx.lineTo(this._round(x2), this._round(y2));
|
||||
this.ctx.stroke();
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.translate(x2, y2);
|
||||
let radians = Math.atan((y1 - y2) / (x1 - x2));
|
||||
radians += ((x1 >= x2) ? -90 : 90) * Math.PI / 180;
|
||||
this.ctx.rotate(radians);
|
||||
this.ctx.moveTo(0, 0);
|
||||
this.ctx.lineTo(this.ARROW_TIP_WIDTH / 2, this.ARROW_TIP_HEIGHT);
|
||||
this.ctx.lineTo(-this.ARROW_TIP_WIDTH / 2, this.ARROW_TIP_HEIGHT);
|
||||
this.ctx.closePath();
|
||||
this.ctx.fill();
|
||||
|
||||
this.ctx.restore();
|
||||
},
|
||||
|
||||
_drawOrigin: function(x, y) {
|
||||
this.ctx.save();
|
||||
|
||||
this.ctx.strokeStyle = this.ORIGIN_STROKE;
|
||||
this.ctx.fillStyle = this.ORIGIN_STROKE;
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(x, y, 4, 0, 2 * Math.PI, false);
|
||||
this.ctx.stroke();
|
||||
this.ctx.fill();
|
||||
|
||||
this.ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* Computes the largest width and height of all the given shapes and changes
|
||||
* all of the shapes' points (by reference) so they fit into the configured
|
||||
* MAX_DIM - 2*PAD area.
|
||||
* @return {Object} A {w, h} giving the size the canvas should be
|
||||
*/
|
||||
_fitAllShapes: function(allShapes) {
|
||||
let allXs = [], allYs = [];
|
||||
for (let shape of allShapes) {
|
||||
for (let point of shape) {
|
||||
allXs.push(point[0]);
|
||||
allYs.push(point[1]);
|
||||
}
|
||||
}
|
||||
let minX = Math.min.apply(Math, allXs);
|
||||
let maxX = Math.max.apply(Math, allXs);
|
||||
let minY = Math.min.apply(Math, allYs);
|
||||
let maxY = Math.max.apply(Math, allYs);
|
||||
|
||||
let spanX = maxX - minX;
|
||||
let spanY = maxY - minY;
|
||||
let isWide = spanX > spanY;
|
||||
|
||||
let cw = isWide ? this.MAX_DIM :
|
||||
this.MAX_DIM * Math.min(spanX, spanY) / Math.max(spanX, spanY);
|
||||
let ch = !isWide ? this.MAX_DIM :
|
||||
this.MAX_DIM * Math.min(spanX, spanY) / Math.max(spanX, spanY);
|
||||
|
||||
let mapX = x => this.PAD + ((cw - 2 * this.PAD) / (maxX - minX)) * (x - minX);
|
||||
let mapY = y => this.PAD + ((ch - 2 * this.PAD) / (maxY - minY)) * (y - minY);
|
||||
|
||||
for (let shape of allShapes) {
|
||||
for (let point of shape) {
|
||||
point[0] = mapX(point[0]);
|
||||
point[1] = mapY(point[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return {w: cw, h: ch};
|
||||
},
|
||||
|
||||
_drawShapes: function(shape, corner, transformed, transformedCorner) {
|
||||
this._drawOriginal(shape);
|
||||
this._drawOriginalCorner(corner);
|
||||
this._drawTransformed(transformed);
|
||||
this._drawTransformedCorner(transformedCorner);
|
||||
},
|
||||
|
||||
_drawOriginal: function(points) {
|
||||
this._drawShape(points, this.ORIGINAL_FILL, this.ORIGINAL_STROKE);
|
||||
},
|
||||
|
||||
_drawTransformed: function(points) {
|
||||
this._drawShape(points, this.TRANSFORMED_FILL, this.TRANSFORMED_STROKE);
|
||||
},
|
||||
|
||||
_drawOriginalCorner: function(points) {
|
||||
this._drawShape(points, this.ORIGINAL_STROKE, this.ORIGINAL_STROKE);
|
||||
},
|
||||
|
||||
_drawTransformedCorner: function(points) {
|
||||
this._drawShape(points, this.TRANSFORMED_STROKE, this.TRANSFORMED_STROKE);
|
||||
},
|
||||
|
||||
_drawArrows: function(shape, transformed) {
|
||||
this._drawArrow(shape[0][0], shape[0][1], transformed[0][0], transformed[0][1]);
|
||||
this._drawArrow(shape[1][0], shape[1][1], transformed[1][0], transformed[1][1]);
|
||||
this._drawArrow(shape[2][0], shape[2][1], transformed[2][0], transformed[2][1]);
|
||||
this._drawArrow(shape[3][0], shape[3][1], transformed[3][0], transformed[3][1]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Draw a transform preview
|
||||
*
|
||||
* @param {String} transform
|
||||
* The css transform value as a string, as typed by the user, as long
|
||||
* as it can be computed by the browser
|
||||
* @param {String} origin
|
||||
* Same as above for the transform-origin value. Defaults to "center"
|
||||
* @param {Number} width
|
||||
* The width of the container. Defaults to 200
|
||||
* @param {Number} height
|
||||
* The height of the container. Defaults to 200
|
||||
* @return {Boolean} Whether or not the preview could be created. Will return
|
||||
* false for instance if the transform is invalid
|
||||
*/
|
||||
preview: function(transform, origin="center", width=200, height=200) {
|
||||
// Create/clear the canvas
|
||||
if (!this.canvas) {
|
||||
this._createMarkup();
|
||||
}
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
// Get computed versions of transform and origin
|
||||
transform = this._getComputed("transform", transform, width, height);
|
||||
if (transform && transform !== "none") {
|
||||
origin = this._getComputed("transform-origin", origin, width, height);
|
||||
|
||||
// Get the matrix, origin and width height data for the previewed element
|
||||
let originData = this._getOriginFromOriginString(origin);
|
||||
let matrixData = this._getMatrixFromTransformString(transform);
|
||||
|
||||
// Compute the original box rect and transformed box rect
|
||||
let shapePoints = [
|
||||
[0, 0],
|
||||
[width, 0],
|
||||
[width, height],
|
||||
[0, height]
|
||||
];
|
||||
let transformedPoints = this._getTransformedPoints(matrixData, shapePoints, originData);
|
||||
|
||||
// Do the same for the corner triangle shape
|
||||
let cornerSize = Math.min(shapePoints[2][1] - shapePoints[1][1],
|
||||
shapePoints[1][0] - shapePoints[0][0]) / this.CORNER_SIZE_RATIO;
|
||||
let cornerPoints = [
|
||||
[shapePoints[1][0], shapePoints[1][1]],
|
||||
[shapePoints[1][0], shapePoints[1][1] + cornerSize],
|
||||
[shapePoints[1][0] - cornerSize, shapePoints[1][1]]
|
||||
];
|
||||
let transformedCornerPoints = this._getTransformedPoints(matrixData, cornerPoints, originData);
|
||||
|
||||
// Resize points to fit everything in the canvas
|
||||
let {w, h} = this._fitAllShapes([
|
||||
shapePoints,
|
||||
transformedPoints,
|
||||
cornerPoints,
|
||||
transformedCornerPoints,
|
||||
[originData]
|
||||
]);
|
||||
|
||||
this.canvas.setAttribute("width", w);
|
||||
this.canvas.setAttribute("height", h);
|
||||
|
||||
this._drawShapes(shapePoints, cornerPoints, transformedPoints, transformedCornerPoints)
|
||||
this._drawArrows(shapePoints, transformedPoints);
|
||||
this._drawOrigin(originData[0], originData[1]);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -12,6 +12,7 @@ const {Spectrum} = require("devtools/shared/widgets/Spectrum");
|
|||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {colorUtils} = require("devtools/css-color");
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const {CSSTransformPreviewer} = require("devtools/shared/widgets/CSSTransformPreviewer");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
@ -100,7 +101,6 @@ let PanelFactory = {
|
|||
panel.setAttribute("hidden", true);
|
||||
panel.setAttribute("ignorekeys", true);
|
||||
|
||||
// Prevent the click used to close the panel from being consumed
|
||||
panel.setAttribute("consumeoutsideclicks", options.get("consumeOutsideClick"));
|
||||
panel.setAttribute("noautofocus", options.get("noAutoFocus"));
|
||||
panel.setAttribute("type", "arrow");
|
||||
|
@ -229,6 +229,10 @@ Tooltip.prototype = {
|
|||
return this.panel.state !== "closed" && this.panel.state !== "hiding";
|
||||
},
|
||||
|
||||
setSize: function(width, height) {
|
||||
this.panel.sizeTo(width, height);
|
||||
},
|
||||
|
||||
/**
|
||||
* Empty the tooltip's content
|
||||
*/
|
||||
|
@ -304,7 +308,8 @@ Tooltip.prototype = {
|
|||
* The container for all target nodes
|
||||
* @param {Function} targetNodeCb
|
||||
* A function that accepts a node argument and returns true or false
|
||||
* to signify if the tooltip should be shown on that node or not.
|
||||
* (or a promise that resolves or rejects) to signify if the tooltip
|
||||
* should be shown on that node or not.
|
||||
* Additionally, the function receives a second argument which is the
|
||||
* tooltip instance itself, to be used to add/modify the content of the
|
||||
* tooltip if needed. If omitted, the tooltip will be shown everytime.
|
||||
|
@ -312,7 +317,7 @@ Tooltip.prototype = {
|
|||
* An optional delay that will be observed before showing the tooltip.
|
||||
* Defaults to this.defaultShowDelay.
|
||||
*/
|
||||
startTogglingOnHover: function(baseNode, targetNodeCb, showDelay = this.defaultShowDelay) {
|
||||
startTogglingOnHover: function(baseNode, targetNodeCb, showDelay=this.defaultShowDelay) {
|
||||
if (this._basedNode) {
|
||||
this.stopTogglingOnHover();
|
||||
}
|
||||
|
@ -357,7 +362,12 @@ Tooltip.prototype = {
|
|||
},
|
||||
|
||||
_showOnHover: function(target) {
|
||||
if (this._targetNodeCb(target, this)) {
|
||||
let res = this._targetNodeCb(target, this);
|
||||
if (res && res.then) {
|
||||
res.then(() => {
|
||||
this.show(target);
|
||||
});
|
||||
} else if (res) {
|
||||
this.show(target);
|
||||
}
|
||||
},
|
||||
|
@ -527,6 +537,8 @@ Tooltip.prototype = {
|
|||
let w = options.naturalWidth || imgObj.naturalWidth;
|
||||
let h = options.naturalHeight || imgObj.naturalHeight;
|
||||
label.textContent = w + " x " + h;
|
||||
|
||||
this.setSize(vbox.width, vbox.height);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -583,6 +595,54 @@ Tooltip.prototype = {
|
|||
// Put the iframe in the tooltip
|
||||
this.content = iframe;
|
||||
|
||||
return def.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the content of the tooltip to be the result of CSSTransformPreviewer.
|
||||
* Meaning a canvas previewing a css transformation.
|
||||
*
|
||||
* @param {String} transform
|
||||
* The CSS transform value (e.g. "rotate(45deg) translateX(50px)")
|
||||
* @param {PageStyleActor} pageStyle
|
||||
* An instance of the PageStyleActor that will be used to retrieve
|
||||
* computed styles
|
||||
* @param {NodeActor} node
|
||||
* The NodeActor for the currently selected node
|
||||
* @return A promise that resolves when the tooltip content is ready, or
|
||||
* rejects if no transform is provided or is invalid
|
||||
*/
|
||||
setCssTransformContent: function(transform, pageStyle, node) {
|
||||
let def = promise.defer();
|
||||
|
||||
if (transform) {
|
||||
// Look into the computed styles to find the width and height and possibly
|
||||
// the origin if it hadn't been provided
|
||||
pageStyle.getComputed(node, {
|
||||
filter: "user",
|
||||
markMatched: false,
|
||||
onlyMatched: false
|
||||
}).then(styles => {
|
||||
let origin = styles["transform-origin"].value;
|
||||
let width = parseInt(styles["width"].value);
|
||||
let height = parseInt(styles["height"].value);
|
||||
|
||||
let root = this.doc.createElementNS(XHTML_NS, "div");
|
||||
let previewer = new CSSTransformPreviewer(root);
|
||||
this.content = root;
|
||||
if (!previewer.preview(transform, origin, width, height)) {
|
||||
// If the preview didn't work, reject the promise
|
||||
def.reject();
|
||||
} else {
|
||||
// Else, make sure the tooltip has the right size and resolve
|
||||
this.setSize(previewer.canvas.width, previewer.canvas.height);
|
||||
def.resolve();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
def.reject();
|
||||
}
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -297,6 +297,8 @@ CssHtmlTree.prototype = {
|
|||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
this.tooltip.hide();
|
||||
|
||||
if (aElement === this.viewedElement) {
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
@ -507,21 +509,27 @@ CssHtmlTree.prototype = {
|
|||
*/
|
||||
_buildTooltipContent: function(target)
|
||||
{
|
||||
// If the hovered element is not a property view and is not a background
|
||||
// image, then don't show a tooltip
|
||||
let isPropertyValue = target.classList.contains("property-value");
|
||||
if (!isPropertyValue) {
|
||||
return false;
|
||||
}
|
||||
let propName = target.parentNode.querySelector(".property-name");
|
||||
let isBackgroundImage = propName.textContent === "background-image";
|
||||
if (!isBackgroundImage) {
|
||||
return false;
|
||||
// Test for image url
|
||||
if (target.classList.contains("theme-link")) {
|
||||
let propValue = target.parentNode;
|
||||
let propName = propValue.parentNode.querySelector(".property-name");
|
||||
if (propName.textContent === "background-image") {
|
||||
this.tooltip.setCssBackgroundImageContent(propValue.textContent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill some content
|
||||
this.tooltip.setCssBackgroundImageContent(target.textContent);
|
||||
return true;
|
||||
// Test for css transform
|
||||
if (target.classList.contains("property-value")) {
|
||||
let def = promise.defer();
|
||||
let propValue = target;
|
||||
let propName = target.parentNode.querySelector(".property-name");
|
||||
if (propName.textContent === "transform") {
|
||||
this.tooltip.setCssTransformContent(propValue.textContent,
|
||||
this.pageStyle, this.viewedElement).then(def.resolve);
|
||||
return def.promise;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -1154,27 +1154,32 @@ CssRuleView.prototype = {
|
|||
* prepare some content for the tooltip
|
||||
*/
|
||||
_buildTooltipContent: function(target) {
|
||||
let isImageHref = target.classList.contains("theme-link") &&
|
||||
target.parentNode.classList.contains("ruleview-propertyvalue");
|
||||
let property = target.textProperty, def = promise.defer(), hasTooltip = false;
|
||||
|
||||
// If the inplace-editor is visible or if this is not a background image
|
||||
// don't show the tooltip
|
||||
if (!isImageHref) {
|
||||
return false;
|
||||
// Test for css transform
|
||||
if (property && property.name === "transform") {
|
||||
this.previewTooltip.setCssTransformContent(property.value, this.pageStyle,
|
||||
this._viewedElement).then(def.resolve);
|
||||
hasTooltip = true;
|
||||
}
|
||||
|
||||
// Retrieve the TextProperty for the hovered element
|
||||
let property = target.parentNode.textProperty;
|
||||
let href = property.rule.domRule.href;
|
||||
// Test for image
|
||||
let isImageHref = target.classList.contains("theme-link") &&
|
||||
target.parentNode.classList.contains("ruleview-propertyvalue");
|
||||
if (isImageHref) {
|
||||
property = target.parentNode.textProperty;
|
||||
this.previewTooltip.setCssBackgroundImageContent(property.value,
|
||||
property.rule.domRule.href);
|
||||
def.resolve();
|
||||
hasTooltip = true;
|
||||
}
|
||||
|
||||
// Fill some content
|
||||
this.previewTooltip.setCssBackgroundImageContent(property.value, href);
|
||||
if (hasTooltip) {
|
||||
this.colorPicker.revert();
|
||||
this.colorPicker.hide();
|
||||
}
|
||||
|
||||
// Hide the color picker tooltip if shown and revert changes
|
||||
this.colorPicker.revert();
|
||||
this.colorPicker.hide();
|
||||
|
||||
return true;
|
||||
return def.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1330,7 +1335,7 @@ CssRuleView.prototype = {
|
|||
/**
|
||||
* Update the highlighted element.
|
||||
*
|
||||
* @param {nsIDOMElement} aElement
|
||||
* @param {NodeActor} aElement
|
||||
* The node whose style rules we'll inspect.
|
||||
*/
|
||||
highlight: function CssRuleView_highlight(aElement)
|
||||
|
@ -1424,6 +1429,9 @@ CssRuleView.prototype = {
|
|||
this._clearRules();
|
||||
this._viewedElement = null;
|
||||
this._elementStyle = null;
|
||||
|
||||
this.previewTooltip.hide();
|
||||
this.colorPicker.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,6 +53,8 @@ support-files = browser_ruleview_pseudoelement.html
|
|||
[browser_bug913014_matched_expand.js]
|
||||
[browser_bug765105_background_image_tooltip.js]
|
||||
[browser_bug889638_rule_view_color_picker.js]
|
||||
[browser_bug726427_csstransform_tooltip.js]
|
||||
|
||||
[browser_bug940500_rule_view_pick_gradient_color.js]
|
||||
[browser_ruleview_original_source_link.js]
|
||||
support-files =
|
||||
|
@ -61,3 +63,4 @@ support-files =
|
|||
sourcemaps.css.map
|
||||
sourcemaps.scss
|
||||
[browser_computedview_original_source_link.js]
|
||||
[browser_bug946331_close_tooltip_on_new_selection.js]
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let contentDoc;
|
||||
let inspector;
|
||||
let ruleView;
|
||||
let computedView;
|
||||
|
||||
const PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' #testElement {',
|
||||
' width: 500px;',
|
||||
' height: 300px;',
|
||||
' background: red;',
|
||||
' transform: skew(16deg);',
|
||||
' }',
|
||||
' .test-element {',
|
||||
' transform-origin: top left;',
|
||||
' transform: rotate(45deg);',
|
||||
' }',
|
||||
' div {',
|
||||
' transform: scaleX(1.5);',
|
||||
' transform-origin: bottom right;',
|
||||
' }',
|
||||
' [attr] {',
|
||||
' }',
|
||||
'</style>',
|
||||
'<div id="testElement" class="test-element" attr="value">transformed element</div>'
|
||||
].join("\n");
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
contentDoc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,rule view css transform tooltip test";
|
||||
}
|
||||
|
||||
function createDocument() {
|
||||
contentDoc.body.innerHTML = PAGE_CONTENT;
|
||||
|
||||
openRuleView((aInspector, aRuleView) => {
|
||||
inspector = aInspector;
|
||||
ruleView = aRuleView;
|
||||
startTests();
|
||||
});
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
inspector.selection.setNode(contentDoc.querySelector("#testElement"));
|
||||
inspector.once("inspector-updated", testTransformTooltipOnIDSelector);
|
||||
}
|
||||
|
||||
function endTests() {
|
||||
contentDoc = inspector = ruleView = computedView = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function testTransformTooltipOnIDSelector() {
|
||||
info("Testing that a transform tooltip appears on the #ID rule");
|
||||
|
||||
let panel = ruleView.previewTooltip.panel;
|
||||
ok(panel, "The XUL panel exists for the rule-view preview tooltips");
|
||||
|
||||
let {valueSpan} = getRuleViewProperty("#testElement", "transform");
|
||||
assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => {
|
||||
// The transform preview is canvas, so there's not much we can test, so for
|
||||
// now, let's just be happy with the fact that the tooltips is shown!
|
||||
ok(true, "Tooltip shown on the transform property of the #ID rule");
|
||||
ruleView.previewTooltip.hide();
|
||||
executeSoon(testTransformTooltipOnClassSelector);
|
||||
});
|
||||
}
|
||||
|
||||
function testTransformTooltipOnClassSelector() {
|
||||
info("Testing that a transform tooltip appears on the .class rule");
|
||||
|
||||
let {valueSpan} = getRuleViewProperty(".test-element", "transform");
|
||||
assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => {
|
||||
// The transform preview is canvas, so there's not much we can test, so for
|
||||
// now, let's just be happy with the fact that the tooltips is shown!
|
||||
ok(true, "Tooltip shown on the transform property of the .class rule");
|
||||
ruleView.previewTooltip.hide();
|
||||
executeSoon(testTransformTooltipOnTagSelector);
|
||||
});
|
||||
}
|
||||
|
||||
function testTransformTooltipOnTagSelector() {
|
||||
info("Testing that a transform tooltip appears on the tag rule");
|
||||
|
||||
let {valueSpan} = getRuleViewProperty("div", "transform");
|
||||
assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => {
|
||||
// The transform preview is canvas, so there's not much we can test, so for
|
||||
// now, let's just be happy with the fact that the tooltips is shown!
|
||||
ok(true, "Tooltip shown on the transform property of the tag rule");
|
||||
ruleView.previewTooltip.hide();
|
||||
executeSoon(testTransformTooltipNotShownOnInvalidTransform);
|
||||
});
|
||||
}
|
||||
|
||||
function testTransformTooltipNotShownOnInvalidTransform() {
|
||||
info("Testing that a transform tooltip does not appear for invalid values");
|
||||
|
||||
let ruleEditor;
|
||||
for (let rule of ruleView._elementStyle.rules) {
|
||||
if (rule.matchedSelectors[0] === "[attr]") {
|
||||
ruleEditor = rule.editor;
|
||||
}
|
||||
}
|
||||
ruleEditor.addProperty("transform", "muchTransform(suchAngle)", "");
|
||||
|
||||
let {valueSpan} = getRuleViewProperty("[attr]", "transform");
|
||||
assertTooltipNotShownOn(ruleView.previewTooltip, valueSpan, () => {
|
||||
executeSoon(testTransformTooltipOnComputedView);
|
||||
});
|
||||
}
|
||||
|
||||
function testTransformTooltipOnComputedView() {
|
||||
info("Testing that a transform tooltip appears in the computed view too");
|
||||
|
||||
inspector.sidebar.select("computedview");
|
||||
computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
let doc = computedView.styleDocument;
|
||||
|
||||
let panel = computedView.tooltip.panel;
|
||||
let {valueSpan} = getComputedViewProperty("transform");
|
||||
|
||||
assertTooltipShownOn(computedView.tooltip, valueSpan, () => {
|
||||
// The transform preview is canvas, so there's not much we can test, so for
|
||||
// now, let's just be happy with the fact that the tooltips is shown!
|
||||
ok(true, "Tooltip shown on the computed transform property");
|
||||
computedView.tooltip.hide();
|
||||
executeSoon(endTests);
|
||||
});
|
||||
}
|
||||
|
||||
function assertTooltipShownOn(tooltip, element, cb) {
|
||||
// If there is indeed a show-on-hover on element, the xul panel will be shown
|
||||
tooltip.panel.addEventListener("popupshown", function shown() {
|
||||
tooltip.panel.removeEventListener("popupshown", shown, true);
|
||||
cb();
|
||||
}, true);
|
||||
tooltip._showOnHover(element);
|
||||
}
|
||||
|
||||
function assertTooltipNotShownOn(tooltip, element, cb) {
|
||||
// The only way to make sure the tooltip is not shown is try and show it, wait
|
||||
// for a given amount of time, and then check if it's shown or not
|
||||
tooltip._showOnHover(element);
|
||||
setTimeout(() => {
|
||||
ok(!tooltip.isShown(), "The tooltip did not appear on hover of the element");
|
||||
cb();
|
||||
}, tooltip.defaultShowDelay + 100);
|
||||
}
|
||||
|
||||
function getRule(selectorText) {
|
||||
let rule;
|
||||
|
||||
[].forEach.call(ruleView.doc.querySelectorAll(".ruleview-rule"), aRule => {
|
||||
let selector = aRule.querySelector(".ruleview-selector-matched");
|
||||
if (selector && selector.textContent === selectorText) {
|
||||
rule = aRule;
|
||||
}
|
||||
});
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
function getRuleViewProperty(selectorText, propertyName) {
|
||||
let prop;
|
||||
|
||||
let rule = getRule(selectorText);
|
||||
if (rule) {
|
||||
// Look for the propertyName in that rule element
|
||||
[].forEach.call(rule.querySelectorAll(".ruleview-property"), property => {
|
||||
let nameSpan = property.querySelector(".ruleview-propertyname");
|
||||
let valueSpan = property.querySelector(".ruleview-propertyvalue");
|
||||
|
||||
if (nameSpan.textContent === propertyName) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
function getComputedViewProperty(name) {
|
||||
let prop;
|
||||
[].forEach.call(computedView.styleDocument.querySelectorAll(".property-view"), property => {
|
||||
let nameSpan = property.querySelector(".property-name");
|
||||
let valueSpan = property.querySelector(".property-value");
|
||||
|
||||
if (nameSpan.textContent === name) {
|
||||
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
|
||||
}
|
||||
});
|
||||
return prop;
|
||||
}
|
|
@ -142,8 +142,9 @@ function testComputedView() {
|
|||
|
||||
let panel = computedView.tooltip.panel;
|
||||
let {valueSpan} = getComputedViewProperty("background-image");
|
||||
let uriSpan = valueSpan.querySelector(".theme-link");
|
||||
|
||||
assertTooltipShownOn(computedView.tooltip, valueSpan, () => {
|
||||
assertTooltipShownOn(computedView.tooltip, uriSpan, () => {
|
||||
let images = panel.getElementsByTagName("image");
|
||||
is(images.length, 1, "Tooltip contains an image");
|
||||
ok(images[0].src === "chrome://global/skin/icons/warning-64.png");
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let contentDoc;
|
||||
let inspector;
|
||||
let ruleView;
|
||||
let computedView;
|
||||
|
||||
const PAGE_CONTENT = '<div class="one">el 1</div><div class="two">el 2</div>';
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
contentDoc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,rule/computed views tooltip hiding test";
|
||||
}
|
||||
|
||||
function createDocument() {
|
||||
contentDoc.body.innerHTML = PAGE_CONTENT;
|
||||
|
||||
openRuleView((aInspector, aRuleView) => {
|
||||
inspector = aInspector;
|
||||
ruleView = aRuleView;
|
||||
inspector.sidebar.once("computedview-ready", () => {
|
||||
computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
startTests();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
inspector.selection.setNode(contentDoc.querySelector(".one"));
|
||||
inspector.once("inspector-updated", testRuleView);
|
||||
}
|
||||
|
||||
function endTests() {
|
||||
contentDoc = inspector = ruleView = computedView = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function testRuleView() {
|
||||
info("Testing rule view tooltip closes on new selection");
|
||||
|
||||
// Show the rule view tooltip
|
||||
let tooltip = ruleView.previewTooltip;
|
||||
tooltip.show();
|
||||
tooltip.once("shown", () => {
|
||||
// Select a new node and assert that the tooltip closes
|
||||
tooltip.once("hidden", () => {
|
||||
ok(true, "Rule view tooltip closed after a new node got selected");
|
||||
inspector.once("inspector-updated", testComputedView);
|
||||
});
|
||||
inspector.selection.setNode(contentDoc.querySelector(".two"));
|
||||
});
|
||||
}
|
||||
|
||||
function testComputedView() {
|
||||
info("Testing computed view tooltip closes on new selection");
|
||||
|
||||
inspector.sidebar.select("computedview");
|
||||
computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
|
||||
// Show the computed view tooltip
|
||||
let tooltip = computedView.tooltip;
|
||||
tooltip.show();
|
||||
tooltip.once("shown", () => {
|
||||
// Select a new node and assert that the tooltip closes
|
||||
tooltip.once("hidden", () => {
|
||||
ok(true, "Computed view tooltip closed after a new node got selected");
|
||||
inspector.once("inspector-updated", endTests);
|
||||
});
|
||||
inspector.selection.setNode(contentDoc.querySelector(".one"));
|
||||
});
|
||||
}
|
|
@ -3,6 +3,17 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<!ENTITY aboutDialog.title "About &brandFullName;">
|
||||
|
||||
<!-- LOCALIZATION NOTE update.applyButton.*, update.upgradeButton.*):
|
||||
# Only one button is present at a time.
|
||||
# The button when displayed is located directly under the Firefox version in
|
||||
# the about dialog (see bug 596813 for screenshots).
|
||||
-->
|
||||
<!ENTITY update.updateButton.label "Restart to Update">
|
||||
<!ENTITY update.updateButton.accesskey "R">
|
||||
<!ENTITY update.applyButtonBillboard.label "Apply Update…">
|
||||
<!ENTITY update.applyButtonBillboard.accesskey "A">
|
||||
|
||||
|
||||
<!-- LOCALIZATION NOTE (warningDesc.version): This is a warning about the experimental nature of Nightly and Aurora builds. It is only shown in those versions. -->
|
||||
<!ENTITY warningDesc.version "&brandShortName; is experimental and may be unstable.">
|
||||
<!-- LOCALIZATION NOTE (warningDesc.telemetryDesc): This is a notification that Nightly/Aurora builds automatically send Telemetry data back to Mozilla. It is only shown in those versions. "It" refers to brandShortName. -->
|
||||
|
@ -41,8 +52,6 @@
|
|||
|
||||
<!-- LOCALIZATION NOTE (update.checkingForUpdates): try to make the localized text short (see bug 596813 for screenshots). -->
|
||||
<!ENTITY update.checkingForUpdates "Checking for updates…">
|
||||
<!-- LOCALIZATION NOTE (update.checkingAddonCompat): try to make the localized text short (see bug 596813 for screenshots). -->
|
||||
<!ENTITY update.checkingAddonCompat "Checking Add-on compatibility…">
|
||||
<!-- LOCALIZATION NOTE (update.noUpdatesFound): try to make the localized text short (see bug 596813 for screenshots). -->
|
||||
<!ENTITY update.noUpdatesFound "&brandShortName; is up to date">
|
||||
<!-- LOCALIZATION NOTE (update.adminDisabled): try to make the localized text short (see bug 596813 for screenshots). -->
|
||||
|
|
|
@ -191,24 +191,10 @@ sanitizeEverythingWarning2=All history will be cleared.
|
|||
# provided that the user has modified the default set of history items to clear.
|
||||
sanitizeSelectedWarning=All selected items will be cleared.
|
||||
|
||||
# Check for Updates in the About Dialog - button labels and accesskeys
|
||||
# LOCALIZATION NOTE - all of the following update buttons labels will only be
|
||||
# displayed one at a time. So, if a button is displayed nothing else will
|
||||
# be displayed alongside of the button. The button when displayed is located
|
||||
# directly under the Firefox version in the about dialog (see bug 596813 for
|
||||
# screenshots).
|
||||
update.checkInsideButton.label=Check for Updates
|
||||
update.checkInsideButton.accesskey=C
|
||||
update.resumeButton.label=Resume Downloading %S…
|
||||
update.resumeButton.accesskey=D
|
||||
update.openUpdateUI.applyButton.label=Apply Update…
|
||||
update.openUpdateUI.applyButton.accesskey=A
|
||||
update.restart.updateButton.label=Restart to Update
|
||||
update.restart.updateButton.accesskey=R
|
||||
update.openUpdateUI.upgradeButton.label=Upgrade Now…
|
||||
update.openUpdateUI.upgradeButton.accesskey=U
|
||||
update.restart.upgradeButton.label=Upgrade Now
|
||||
update.restart.upgradeButton.accesskey=U
|
||||
# LOCALIZATION NOTE (downloadAndInstallButton.label): %S is replaced by the
|
||||
# version of the update: "Update to 28.0".
|
||||
update.downloadAndInstallButton.label=Update to %S
|
||||
update.downloadAndInstallButton.accesskey=U
|
||||
|
||||
# RSS Pretty Print
|
||||
feedShowFeedNew=Subscribe to '%S'…
|
||||
|
|
|
@ -100,4 +100,5 @@
|
|||
#endif
|
||||
</hbox>
|
||||
</html:body>
|
||||
<observes element="bcast_windowState" attribute="*"/>
|
||||
</html:html>
|
||||
|
|
|
@ -201,6 +201,8 @@ pref("signon.rememberSignons", true);
|
|||
pref("layout.spellcheckDefault", 1);
|
||||
|
||||
/* extension manager and xpinstall */
|
||||
// Completely disable extensions
|
||||
pref("extensions.defaultProviders.enabled", false);
|
||||
// Disable all add-on locations other than the profile
|
||||
pref("extensions.enabledScopes", 1);
|
||||
// Auto-disable any add-ons that are "dropped in" to the profile
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
# 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/.
|
||||
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
DIST_PROGRAM = CommandExecuteHandler$(BIN_SUFFIX)
|
||||
|
|
|
@ -16,3 +16,5 @@ DIST_SUBDIR = ''
|
|||
|
||||
for var in ('UNICODE', '_UNICODE', 'NS_NO_XPCOM'):
|
||||
DEFINES[var] = True
|
||||
|
||||
NO_PGO = True
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
# 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/.
|
||||
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
OS_LIBS = \
|
||||
|
|
|
@ -14,3 +14,5 @@ DIST_SUBDIR = 'metro/install'
|
|||
|
||||
for var in ('UNICODE', '_UNICODE'):
|
||||
DEFINES[var] = True
|
||||
|
||||
NO_PGO = True
|
||||
|
|
|
@ -9,8 +9,6 @@ USE_STATIC_LIBS = 1
|
|||
MOZ_GLUE_LDFLAGS =
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS =
|
||||
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
OS_LIBS = \
|
||||
|
|
|
@ -15,3 +15,5 @@ DIST_SUBDIR = ''
|
|||
|
||||
for var in ('UNICODE', '_UNICODE'):
|
||||
DEFINES[var] = True
|
||||
|
||||
NO_PGO = True
|
||||
|
|
|
@ -197,6 +197,12 @@ documenttab[selected] .documenttab-selection {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
#startui-page[viewstate="snapped"],
|
||||
#startui-page[viewstate="portrait"] {
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#startui-body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
|
|
@ -64,7 +64,9 @@ def config_status(topobjdir='.', topsrcdir='.',
|
|||
help='display verbose output')
|
||||
parser.add_option('-n', dest='not_topobjdir', action='store_true',
|
||||
help='do not consider current directory as top object directory')
|
||||
(options, args) = parser.parse_args()
|
||||
parser.add_option('-d', '--diff', action='store_true',
|
||||
help='print diffs of changed files.')
|
||||
options, args = parser.parse_args()
|
||||
|
||||
# Without -n, the current directory is meant to be the top object directory
|
||||
if not options.not_topobjdir:
|
||||
|
@ -98,3 +100,7 @@ def config_status(topobjdir='.', topsrcdir='.',
|
|||
|
||||
for line in summary.summaries():
|
||||
print(line, file=sys.stderr)
|
||||
|
||||
if options.diff:
|
||||
for path, diff in sorted(summary.file_diffs.items()):
|
||||
print(diff)
|
||||
|
|
|
@ -1,20 +1,13 @@
|
|||
==================================
|
||||
Mozilla Build System Documentation
|
||||
==================================
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
glossary
|
||||
============
|
||||
Build System
|
||||
============
|
||||
|
||||
Important Concepts
|
||||
==================
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
glossary
|
||||
build-overview
|
||||
supported-configurations
|
||||
Mozconfig Files <mozconfigs>
|
||||
|
@ -41,24 +34,3 @@ Mozilla build system.
|
|||
|
||||
mozbuild/index
|
||||
mozbuild/dumbmake
|
||||
|
||||
Python Packages
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
python/codegen
|
||||
python/makeutils
|
||||
python/mozbuild
|
||||
python/mozpack
|
||||
python/mozversioncontrol
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
makeutils Module
|
||||
================
|
||||
|
||||
.. automodule:: makeutils
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
|
@ -1,35 +0,0 @@
|
|||
action Package
|
||||
==============
|
||||
|
||||
:mod:`link_deps` Module
|
||||
-----------------------
|
||||
|
||||
.. automodule:: mozbuild.action.link_deps
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`process_install_manifest` Module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: mozbuild.action.process_install_manifest
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`xpccheck` Module
|
||||
----------------------
|
||||
|
||||
.. automodule:: mozbuild.action.xpccheck
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`xpidl-process` Module
|
||||
---------------------------
|
||||
|
||||
.. automodule:: mozbuild.action.xpidl-process
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
backend Package
|
||||
===============
|
||||
|
||||
:mod:`base` Module
|
||||
------------------
|
||||
|
||||
.. automodule:: mozbuild.backend.base
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`common` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozbuild.backend.common
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`configenvironment` Module
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: mozbuild.backend.configenvironment
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`recursivemake` Module
|
||||
---------------------------
|
||||
|
||||
.. automodule:: mozbuild.backend.recursivemake
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
compilation Package
|
||||
===================
|
||||
|
||||
:mod:`warnings` Module
|
||||
----------------------
|
||||
|
||||
.. automodule:: mozbuild.compilation.warnings
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
controller Package
|
||||
==================
|
||||
|
||||
:mod:`building` Module
|
||||
----------------------
|
||||
|
||||
.. automodule:: mozbuild.controller.building
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`clobber` Module
|
||||
---------------------
|
||||
|
||||
.. automodule:: mozbuild.controller.clobber
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
frontend Package
|
||||
================
|
||||
|
||||
:mod:`data` Module
|
||||
------------------
|
||||
|
||||
.. automodule:: mozbuild.frontend.data
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`emitter` Module
|
||||
---------------------
|
||||
|
||||
.. automodule:: mozbuild.frontend.emitter
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`mach_commands` Module
|
||||
---------------------------
|
||||
|
||||
.. automodule:: mozbuild.frontend.mach_commands
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`reader` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozbuild.frontend.reader
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`sandbox` Module
|
||||
---------------------
|
||||
|
||||
.. automodule:: mozbuild.frontend.sandbox
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`sandbox_symbols` Module
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: mozbuild.frontend.sandbox_symbols
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
mozbuild Package
|
||||
================
|
||||
|
||||
:mod:`base` Module
|
||||
------------------
|
||||
|
||||
.. automodule:: mozbuild.base
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`config` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozbuild.config
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`html_build_viewer` Module
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: mozbuild.html_build_viewer
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`mach_commands` Module
|
||||
---------------------------
|
||||
|
||||
.. automodule:: mozbuild.mach_commands
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`makeutil` Module
|
||||
----------------------
|
||||
|
||||
.. automodule:: mozbuild.makeutil
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`mozconfig` Module
|
||||
-----------------------
|
||||
|
||||
.. automodule:: mozbuild.mozconfig
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`mozinfo` Module
|
||||
---------------------
|
||||
|
||||
.. automodule:: mozbuild.mozinfo
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`pythonutil` Module
|
||||
------------------------
|
||||
|
||||
.. automodule:: mozbuild.pythonutil
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`sphinx` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozbuild.sphinx
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`util` Module
|
||||
------------------
|
||||
|
||||
.. automodule:: mozbuild.util
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`virtualenv` Module
|
||||
------------------------
|
||||
|
||||
.. automodule:: mozbuild.virtualenv
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
|
||||
mozbuild.action
|
||||
mozbuild.backend
|
||||
mozbuild.compilation
|
||||
mozbuild.controller
|
||||
mozbuild.frontend
|
||||
mozbuild.test
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
chrome Package
|
||||
==============
|
||||
|
||||
:mod:`flags` Module
|
||||
-------------------
|
||||
|
||||
.. automodule:: mozpack.chrome.flags
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`manifest` Module
|
||||
----------------------
|
||||
|
||||
.. automodule:: mozpack.chrome.manifest
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
packager Package
|
||||
================
|
||||
|
||||
:mod:`packager` Package
|
||||
-----------------------
|
||||
|
||||
.. automodule:: mozpack.packager
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`formats` Module
|
||||
---------------------
|
||||
|
||||
.. automodule:: mozpack.packager.formats
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`l10n` Module
|
||||
------------------
|
||||
|
||||
.. automodule:: mozpack.packager.l10n
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`unpack` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozpack.packager.unpack
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
mozpack Package
|
||||
===============
|
||||
|
||||
:mod:`copier` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozpack.copier
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`errors` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozpack.errors
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`executables` Module
|
||||
-------------------------
|
||||
|
||||
.. automodule:: mozpack.executables
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`files` Module
|
||||
-------------------
|
||||
|
||||
.. automodule:: mozpack.files
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`manifests` Module
|
||||
-----------------------
|
||||
|
||||
.. automodule:: mozpack.manifests
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`mozjar` Module
|
||||
--------------------
|
||||
|
||||
.. automodule:: mozpack.mozjar
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`path` Module
|
||||
------------------
|
||||
|
||||
.. automodule:: mozpack.path
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`unify` Module
|
||||
-------------------
|
||||
|
||||
.. automodule:: mozpack.unify
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
|
||||
mozpack.chrome
|
||||
mozpack.packager
|
||||
mozpack.test
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
mozversioncontrol Package
|
||||
=========================
|
||||
|
||||
:mod:`repoupdate` Module
|
||||
------------------------
|
||||
|
||||
.. automodule:: mozversioncontrol.repoupdate
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
@ -75,6 +75,7 @@ MACH_MODULES = [
|
|||
'testing/xpcshell/mach_commands.py',
|
||||
'testing/talos/mach_commands.py',
|
||||
'testing/xpcshell/mach_commands.py',
|
||||
'tools/docs/mach_commands.py',
|
||||
'tools/mercurial/mach_commands.py',
|
||||
'tools/mach_commands.py',
|
||||
]
|
||||
|
|
|
@ -4,8 +4,4 @@
|
|||
# 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/.
|
||||
|
||||
ANDROID_RESFILES = [
|
||||
'res/values/strings.xml',
|
||||
]
|
||||
|
||||
DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
|
||||
|
|
|
@ -3,11 +3,3 @@
|
|||
# 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/.
|
||||
|
||||
ANDROID_RESFILES = [
|
||||
'res/drawable-hdpi/icon.png',
|
||||
'res/drawable-ldpi/icon.png',
|
||||
'res/drawable-mdpi/icon.png',
|
||||
'res/layout/main.xml',
|
||||
'res/values/strings.xml',
|
||||
]
|
||||
|
|
|
@ -3,11 +3,3 @@
|
|||
# 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/.
|
||||
|
||||
ANDROID_RESFILES = [
|
||||
'res/drawable-hdpi/icon.png',
|
||||
'res/drawable-ldpi/icon.png',
|
||||
'res/drawable-mdpi/icon.png',
|
||||
'res/layout/main.xml',
|
||||
'res/values/strings.xml',
|
||||
]
|
||||
|
|
|
@ -3,13 +3,3 @@
|
|||
# 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/.
|
||||
|
||||
ANDROID_RESFILES = [
|
||||
'res/drawable/ateamlogo.png',
|
||||
'res/drawable/ic_stat_first.png',
|
||||
'res/drawable/ic_stat_neterror.png',
|
||||
'res/drawable/ic_stat_warning.png',
|
||||
'res/drawable/icon.png',
|
||||
'res/layout/main.xml',
|
||||
'res/values/strings.xml',
|
||||
]
|
||||
|
|
|
@ -3,14 +3,3 @@
|
|||
# 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/.
|
||||
|
||||
ANDROID_RESFILES = [
|
||||
'res/drawable-hdpi/ateamlogo.png',
|
||||
'res/drawable-hdpi/icon.png',
|
||||
'res/drawable-ldpi/ateamlogo.png',
|
||||
'res/drawable-ldpi/icon.png',
|
||||
'res/drawable-mdpi/ateamlogo.png',
|
||||
'res/drawable-mdpi/icon.png',
|
||||
'res/layout/main.xml',
|
||||
'res/values/strings.xml',
|
||||
]
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
# 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/.
|
||||
|
||||
SPHINX_TREES['build'] = 'docs'
|
||||
|
||||
if CONFIG['OS_ARCH'] not in ('WINNT', 'OS2'):
|
||||
DIRS += ['unix']
|
||||
elif CONFIG['OS_ARCH'] == 'WINNT':
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
INTERNAL_TOOLS = 1
|
||||
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
|
||||
VPATH += $(topsrcdir)/build
|
||||
|
||||
OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
INTERNAL_TOOLS = 1
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -18,3 +18,5 @@ GENERATED_SOURCES += [
|
|||
]
|
||||
|
||||
DEFINES['ELFHACK_BUILD'] = True
|
||||
|
||||
NO_PGO = True
|
||||
|
|
|
@ -25,3 +25,5 @@ HOST_SOURCES += [
|
|||
HOST_PROGRAM = 'elfhack'
|
||||
|
||||
DEFINES['ELFHACK_BUILD'] = True
|
||||
|
||||
NO_PGO = True
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
STL_FLAGS =
|
||||
NO_EXPAND_LIBS = 1
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -15,3 +15,5 @@ if CONFIG['MOZ_LIBSTDCXX_HOST_VERSION']:
|
|||
]
|
||||
|
||||
FORCE_STATIC_LIB = True
|
||||
|
||||
NO_PGO = True
|
||||
|
|
|
@ -13,6 +13,7 @@ mock.pth:python/mock-1.0.0
|
|||
mozilla.pth:build
|
||||
mozilla.pth:config
|
||||
mozilla.pth:xpcom/typelib/xpt/tools
|
||||
moztreedocs.pth:tools/docs
|
||||
copy:build/buildconfig.py
|
||||
packages.txt:testing/mozbase/packages.txt
|
||||
objdir:build
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
# 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/.
|
||||
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
|
||||
USE_STATIC_LIBS = 1
|
||||
|
|
|
@ -14,3 +14,5 @@ if CONFIG['ENABLE_TESTS']:
|
|||
SOURCES += [
|
||||
'crashinject.cpp',
|
||||
]
|
||||
|
||||
NO_PGO = True
|
||||
|
|
|
@ -35,7 +35,7 @@ endif
|
|||
# responsibility between Makefile.in and mozbuild files.
|
||||
_MOZBUILD_EXTERNAL_VARIABLES := \
|
||||
ANDROID_GENERATED_RESFILES \
|
||||
ANDROID_RESFILES \
|
||||
ANDROID_RES_DIRS \
|
||||
CMSRCS \
|
||||
CMMSRCS \
|
||||
CPP_UNIT_TESTS \
|
||||
|
@ -70,6 +70,7 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
|
|||
$(NULL)
|
||||
|
||||
_DEPRECATED_VARIABLES := \
|
||||
ANDROID_RESFILES \
|
||||
MOCHITEST_FILES_PARTS \
|
||||
MOCHITEST_BROWSER_FILES_PARTS \
|
||||
SHORT_LIBNAME \
|
||||
|
|
|
@ -7,29 +7,6 @@
|
|||
|
||||
ifndef INCLUDED_JAVA_BUILD_MK #{
|
||||
|
||||
ifdef ANDROID_RESFILES #{
|
||||
ifndef IGNORE_ANDROID_RESFILES #{
|
||||
res-dep := .deps-copy-java-res
|
||||
|
||||
GENERATED_DIRS += res
|
||||
GARBAGE += $(res-dep)
|
||||
|
||||
export:: $(res-dep)
|
||||
|
||||
res-dep-preqs := \
|
||||
$(addprefix $(srcdir)/,$(ANDROID_RESFILES)) \
|
||||
$(call mkdir_deps,res) \
|
||||
$(if $(IS_LANGUAGE_REPACK),FORCE) \
|
||||
$(NULL)
|
||||
|
||||
# nop-build: only copy res/ files when needed
|
||||
$(res-dep): $(res-dep-preqs)
|
||||
$(call copy_dir,$(srcdir)/res,$(CURDIR)/res)
|
||||
@$(TOUCH) $@
|
||||
endif #} IGNORE_ANDROID_RESFILES
|
||||
endif #} ANDROID_RESFILES
|
||||
|
||||
|
||||
ifdef JAVAFILES #{
|
||||
GENERATED_DIRS += classes
|
||||
|
||||
|
@ -39,7 +16,8 @@ endif #} JAVAFILES
|
|||
|
||||
|
||||
ifdef ANDROID_APK_NAME #{
|
||||
_ANDROID_RES_FLAG := -S $(or $(ANDROID_RES_DIR),res)
|
||||
android_res_dirs := $(addprefix $(srcdir)/,$(or $(ANDROID_RES_DIRS),res))
|
||||
_ANDROID_RES_FLAG := $(addprefix -S ,$(android_res_dirs))
|
||||
_ANDROID_ASSETS_FLAG := $(addprefix -A ,$(ANDROID_ASSETS_DIR))
|
||||
|
||||
GENERATED_DIRS += classes
|
||||
|
@ -57,7 +35,11 @@ classes.dex: $(JAVAFILES)
|
|||
R.java: .aapt.deps
|
||||
$(ANDROID_APK_NAME).ap_: .aapt.deps
|
||||
|
||||
.aapt.deps: AndroidManifest.xml $(wildcard $(ANDROID_RES_DIR)) $(wildcard $(ANDROID_ASSETS_DIR))
|
||||
# This uses the fact that Android resource directories list all
|
||||
# resource files one subdirectory below the parent resource directory.
|
||||
android_res_files := $(wildcard $(addsuffix /*,$(wildcard $(addsuffix /*,$(android_res_dirs)))))
|
||||
|
||||
.aapt.deps: AndroidManifest.xml $(android_res_files) $(wildcard $(ANDROID_ASSETS_DIR))
|
||||
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar $(_ANDROID_RES_FLAG) $(_ANDROID_ASSETS_FLAG) \
|
||||
-J ${@D} \
|
||||
-F $(ANDROID_APK_NAME).ap_
|
||||
|
|
|
@ -642,7 +642,7 @@ tools::
|
|||
endif
|
||||
|
||||
##############################################
|
||||
ifndef NO_PROFILE_GUIDED_OPTIMIZE
|
||||
ifneq (1,$(NO_PROFILE_GUIDED_OPTIMIZE))
|
||||
ifdef MOZ_PROFILE_USE
|
||||
ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_)
|
||||
# When building with PGO, we have to make sure to re-link
|
||||
|
|
|
@ -1545,6 +1545,7 @@ public:
|
|||
|
||||
static JSContext *GetCurrentJSContext();
|
||||
static JSContext *GetSafeJSContext();
|
||||
static JSContext *GetCurrentJSContextForThread();
|
||||
static JSContext *GetDefaultJSContextForThread();
|
||||
|
||||
/**
|
||||
|
|
|
@ -5262,6 +5262,17 @@ nsContentUtils::GetDefaultJSContextForThread()
|
|||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
JSContext *
|
||||
nsContentUtils::GetCurrentJSContextForThread()
|
||||
{
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
return GetCurrentJSContext();
|
||||
} else {
|
||||
return workers::GetCurrentThreadJSContext();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsContentUtils::ASCIIToLower(nsAString& aStr)
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "nsIDOMNode.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
|
@ -47,6 +46,7 @@
|
|||
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Undefine LoadImage to prevent naming conflict with Windows.
|
||||
|
@ -1194,12 +1194,6 @@ nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
|
|||
if (!mPendingRequest)
|
||||
return;
|
||||
|
||||
// Push a null JSContext on the stack so that code that runs within
|
||||
// the below code doesn't think it's being called by JS. See bug
|
||||
// 604262.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
// Deregister this image from the refresh driver so it no longer receives
|
||||
// notifications.
|
||||
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
|
||||
|
@ -1259,11 +1253,6 @@ nsImageLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
if (!aDocument)
|
||||
return;
|
||||
|
||||
// Push a null JSContext on the stack so that callbacks triggered by the
|
||||
// below code won't think they're being called from JS.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
TrackImage(mCurrentRequest);
|
||||
TrackImage(mPendingRequest);
|
||||
|
||||
|
@ -1279,11 +1268,6 @@ nsImageLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
if (!doc)
|
||||
return;
|
||||
|
||||
// Push a null JSContext on the stack so that callbacks triggered by the
|
||||
// below code won't think they're being called from JS.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
UntrackImage(mCurrentRequest);
|
||||
UntrackImage(mPendingRequest);
|
||||
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
using namespace gfx;
|
||||
|
||||
struct ImageCacheKey {
|
||||
ImageCacheKey(Element* aImage, HTMLCanvasElement* aCanvas)
|
||||
|
@ -32,7 +34,7 @@ struct ImageCacheEntryData {
|
|||
, mILC(aOther.mILC)
|
||||
, mCanvas(aOther.mCanvas)
|
||||
, mRequest(aOther.mRequest)
|
||||
, mSurface(aOther.mSurface)
|
||||
, mSourceSurface(aOther.mSourceSurface)
|
||||
, mSize(aOther.mSize)
|
||||
{}
|
||||
ImageCacheEntryData(const ImageCacheKey& aKey)
|
||||
|
@ -51,7 +53,7 @@ struct ImageCacheEntryData {
|
|||
nsRefPtr<HTMLCanvasElement> mCanvas;
|
||||
// Value
|
||||
nsCOMPtr<imgIRequest> mRequest;
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
RefPtr<SourceSurface> mSourceSurface;
|
||||
gfxIntSize mSize;
|
||||
nsExpirationState mState;
|
||||
};
|
||||
|
@ -127,7 +129,7 @@ void
|
|||
CanvasImageCache::NotifyDrawImage(Element* aImage,
|
||||
HTMLCanvasElement* aCanvas,
|
||||
imgIRequest* aRequest,
|
||||
gfxASurface* aSurface,
|
||||
SourceSurface* aSource,
|
||||
const gfxIntSize& aSize)
|
||||
{
|
||||
if (!gImageCache) {
|
||||
|
@ -137,7 +139,7 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
|
|||
|
||||
ImageCacheEntry* entry = gImageCache->mCache.PutEntry(ImageCacheKey(aImage, aCanvas));
|
||||
if (entry) {
|
||||
if (entry->mData->mSurface) {
|
||||
if (entry->mData->mSourceSurface) {
|
||||
// We are overwriting an existing entry.
|
||||
gImageCache->mTotal -= entry->mData->SizeInBytes();
|
||||
gImageCache->RemoveObject(entry->mData);
|
||||
|
@ -150,7 +152,7 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
|
|||
getter_AddRefs(entry->mData->mRequest));
|
||||
}
|
||||
entry->mData->mILC = ilc;
|
||||
entry->mData->mSurface = aSurface;
|
||||
entry->mData->mSourceSurface = aSource;
|
||||
entry->mData->mSize = aSize;
|
||||
|
||||
gImageCache->mTotal += entry->mData->SizeInBytes();
|
||||
|
@ -164,7 +166,7 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
|
|||
gImageCache->AgeOneGeneration();
|
||||
}
|
||||
|
||||
gfxASurface*
|
||||
SourceSurface*
|
||||
CanvasImageCache::Lookup(Element* aImage,
|
||||
HTMLCanvasElement* aCanvas,
|
||||
gfxIntSize* aSize)
|
||||
|
@ -184,7 +186,7 @@ CanvasImageCache::Lookup(Element* aImage,
|
|||
gImageCache->MarkUsed(entry->mData);
|
||||
|
||||
*aSize = entry->mData->mSize;
|
||||
return entry->mData->mSurface;
|
||||
return entry->mData->mSourceSurface;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(CanvasImageCacheShutdownObserver, nsIObserver)
|
||||
|
|
|
@ -11,6 +11,9 @@ namespace dom {
|
|||
class Element;
|
||||
class HTMLCanvasElement;
|
||||
} // namespace dom
|
||||
namespace gfx {
|
||||
class SourceSurface;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
class imgIRequest;
|
||||
class gfxASurface;
|
||||
|
@ -20,6 +23,7 @@ class gfxASurface;
|
|||
namespace mozilla {
|
||||
|
||||
class CanvasImageCache {
|
||||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
public:
|
||||
/**
|
||||
* Notify that image element aImage was (or is about to be) drawn to aCanvas
|
||||
|
@ -29,7 +33,7 @@ public:
|
|||
static void NotifyDrawImage(dom::Element* aImage,
|
||||
dom::HTMLCanvasElement* aCanvas,
|
||||
imgIRequest* aRequest,
|
||||
gfxASurface* aSurface,
|
||||
SourceSurface* aSource,
|
||||
const gfxIntSize& aSize);
|
||||
|
||||
/**
|
||||
|
@ -38,9 +42,9 @@ public:
|
|||
* (with the same image request) and the returned surface contains the image
|
||||
* data, and the image size will be returned in aSize.
|
||||
*/
|
||||
static gfxASurface* Lookup(dom::Element* aImage,
|
||||
dom::HTMLCanvasElement* aCanvas,
|
||||
gfxIntSize* aSize);
|
||||
static SourceSurface* Lookup(dom::Element* aImage,
|
||||
dom::HTMLCanvasElement* aCanvas,
|
||||
gfxIntSize* aSize);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1450,29 +1450,21 @@ CanvasRenderingContext2D::CreatePattern(const HTMLImageOrCanvasOrVideoElement& e
|
|||
htmlElement = &element.GetAsHTMLVideoElement();
|
||||
}
|
||||
|
||||
EnsureTarget();
|
||||
|
||||
// The canvas spec says that createPattern should use the first frame
|
||||
// of animated images
|
||||
nsLayoutUtils::SurfaceFromElementResult res =
|
||||
nsLayoutUtils::SurfaceFromElement(htmlElement,
|
||||
nsLayoutUtils::SFE_WANT_FIRST_FRAME | nsLayoutUtils::SFE_WANT_NEW_SURFACE);
|
||||
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
|
||||
|
||||
if (!res.mSurface) {
|
||||
if (!res.mSourceSurface) {
|
||||
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Ignore nullptr cairo surfaces! See bug 666312.
|
||||
if (!res.mSurface->CairoSurface() || res.mSurface->CairoStatus()) {
|
||||
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EnsureTarget();
|
||||
RefPtr<SourceSurface> srcSurf =
|
||||
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
|
||||
|
||||
nsRefPtr<CanvasPattern> pat =
|
||||
new CanvasPattern(this, srcSurf, repeatMode, res.mPrincipal,
|
||||
new CanvasPattern(this, res.mSourceSurface, repeatMode, res.mPrincipal,
|
||||
res.mIsWriteOnly, res.mCORSUsed);
|
||||
|
||||
return pat.forget();
|
||||
|
@ -3084,11 +3076,8 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
|||
element = video;
|
||||
}
|
||||
|
||||
gfxASurface* imgsurf =
|
||||
srcSurf =
|
||||
CanvasImageCache::Lookup(element, mCanvasElement, &imgSize);
|
||||
if (imgsurf) {
|
||||
srcSurf = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, imgsurf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!srcSurf) {
|
||||
|
@ -3096,9 +3085,9 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
|||
// of animated images
|
||||
uint32_t sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME;
|
||||
nsLayoutUtils::SurfaceFromElementResult res =
|
||||
nsLayoutUtils::SurfaceFromElement(element, sfeFlags);
|
||||
nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget);
|
||||
|
||||
if (!res.mSurface) {
|
||||
if (!res.mSourceSurface) {
|
||||
// Spec says to silently do nothing if the element is still loading.
|
||||
if (!res.mIsStillLoading) {
|
||||
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
|
@ -3106,11 +3095,6 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
|||
return;
|
||||
}
|
||||
|
||||
// Ignore cairo surfaces that are bad! See bug 666312.
|
||||
if (res.mSurface->CairoStatus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
imgSize = res.mSize;
|
||||
|
||||
// Scale sw/sh based on aspect ratio
|
||||
|
@ -3129,11 +3113,11 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
|||
}
|
||||
|
||||
if (res.mImageRequest) {
|
||||
CanvasImageCache::NotifyDrawImage(element, mCanvasElement,
|
||||
res.mImageRequest, res.mSurface, imgSize);
|
||||
CanvasImageCache::NotifyDrawImage(element, mCanvasElement, res.mImageRequest,
|
||||
res.mSourceSurface, imgSize);
|
||||
}
|
||||
|
||||
srcSurf = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
|
||||
srcSurf = res.mSourceSurface;
|
||||
}
|
||||
|
||||
if (optional_argc == 0) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "ForceDiscreteGPUHelperCGL.h"
|
||||
|
@ -420,18 +421,19 @@ public:
|
|||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
nsRefPtr<gfxImageSurface> isurf;
|
||||
RefPtr<gfx::DataSourceSurface> data;
|
||||
WebGLTexelFormat srcFormat;
|
||||
nsLayoutUtils::SurfaceFromElementResult res = SurfaceFromElement(elt);
|
||||
rv = SurfaceFromElementResultToImageSurface(res, getter_AddRefs(isurf),
|
||||
rv = SurfaceFromElementResultToImageSurface(res, data,
|
||||
&srcFormat);
|
||||
if (rv.Failed() || !isurf)
|
||||
if (rv.Failed() || !data)
|
||||
return;
|
||||
|
||||
uint32_t byteLength = isurf->Stride() * isurf->Height();
|
||||
gfx::IntSize size = data->GetSize();
|
||||
uint32_t byteLength = data->Stride() * size.height;
|
||||
return TexImage2D_base(target, level, internalformat,
|
||||
isurf->Width(), isurf->Height(), isurf->Stride(),
|
||||
0, format, type, isurf->Data(), byteLength,
|
||||
size.width, size.height, data->Stride(),
|
||||
0, format, type, data->GetData(), byteLength,
|
||||
-1, srcFormat, mPixelStorePremultiplyAlpha);
|
||||
}
|
||||
void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
|
||||
|
@ -459,19 +461,20 @@ public:
|
|||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
nsRefPtr<gfxImageSurface> isurf;
|
||||
RefPtr<gfx::DataSourceSurface> data;
|
||||
WebGLTexelFormat srcFormat;
|
||||
nsLayoutUtils::SurfaceFromElementResult res = SurfaceFromElement(elt);
|
||||
rv = SurfaceFromElementResultToImageSurface(res, getter_AddRefs(isurf),
|
||||
rv = SurfaceFromElementResultToImageSurface(res, data,
|
||||
&srcFormat);
|
||||
if (rv.Failed() || !isurf)
|
||||
if (rv.Failed() || !data)
|
||||
return;
|
||||
|
||||
uint32_t byteLength = isurf->Stride() * isurf->Height();
|
||||
gfx::IntSize size = data->GetSize();
|
||||
uint32_t byteLength = data->Stride() * size.height;
|
||||
return TexSubImage2D_base(target, level, xoffset, yoffset,
|
||||
isurf->Width(), isurf->Height(),
|
||||
isurf->Stride(), format, type,
|
||||
isurf->Data(), byteLength,
|
||||
size.width, size.height,
|
||||
data->Stride(), format, type,
|
||||
data->GetData(), byteLength,
|
||||
-1, srcFormat, mPixelStorePremultiplyAlpha);
|
||||
|
||||
}
|
||||
|
@ -992,7 +995,7 @@ protected:
|
|||
nsLayoutUtils::SurfaceFromElementResult SurfaceFromElement(ElementType* aElement) {
|
||||
MOZ_ASSERT(aElement);
|
||||
uint32_t flags =
|
||||
nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
|
||||
nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
|
||||
|
||||
if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
|
||||
flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
|
||||
|
@ -1007,7 +1010,7 @@ protected:
|
|||
}
|
||||
|
||||
nsresult SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
|
||||
gfxImageSurface **imageOut,
|
||||
RefPtr<gfx::DataSourceSurface>& imageOut,
|
||||
WebGLTexelFormat *format);
|
||||
|
||||
void CopyTexSubImage2D_base(GLenum target,
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::gl;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
|
||||
static GLenum InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2);
|
||||
|
@ -2640,14 +2641,14 @@ WebGLContext::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum
|
|||
|
||||
nsresult
|
||||
WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
|
||||
gfxImageSurface **imageOut, WebGLTexelFormat *format)
|
||||
RefPtr<DataSourceSurface>& imageOut, WebGLTexelFormat *format)
|
||||
{
|
||||
*imageOut = nullptr;
|
||||
*format = WebGLTexelFormat::None;
|
||||
|
||||
if (!res.mSurface)
|
||||
if (!res.mSourceSurface)
|
||||
return NS_OK;
|
||||
if (res.mSurface->GetType() != gfxSurfaceTypeImage) {
|
||||
RefPtr<DataSourceSurface> data = res.mSourceSurface->GetDataSurface();
|
||||
if (!data) {
|
||||
// SurfaceFromElement lied!
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2687,22 +2688,17 @@ WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromE
|
|||
// Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
|
||||
// texture sources in the first place.
|
||||
|
||||
gfxImageSurface* surf = static_cast<gfxImageSurface*>(res.mSurface.get());
|
||||
|
||||
res.mSurface.forget();
|
||||
*imageOut = surf;
|
||||
|
||||
switch (surf->Format()) {
|
||||
case gfxImageFormatARGB32:
|
||||
switch (data->GetFormat()) {
|
||||
case FORMAT_B8G8R8A8:
|
||||
*format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
|
||||
break;
|
||||
case gfxImageFormatRGB24:
|
||||
case FORMAT_B8G8R8X8:
|
||||
*format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
|
||||
break;
|
||||
case gfxImageFormatA8:
|
||||
case FORMAT_A8:
|
||||
*format = WebGLTexelFormat::A8;
|
||||
break;
|
||||
case gfxImageFormatRGB16_565:
|
||||
case FORMAT_R5G6B5:
|
||||
*format = WebGLTexelFormat::RGB565;
|
||||
break;
|
||||
default:
|
||||
|
@ -2710,6 +2706,8 @@ WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromE
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
imageOut = data;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsIDocument.h"
|
||||
#include "prprf.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "ScriptSettings.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -271,10 +272,10 @@ nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
|
|||
const JS::Value& aValue)
|
||||
{
|
||||
nsRefPtr<EventHandlerNonNull> handler;
|
||||
JSObject* callable;
|
||||
JS::Rooted<JSObject*> callable(aCx);
|
||||
if (aValue.isObject() &&
|
||||
JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
|
||||
handler = new EventHandlerNonNull(callable);
|
||||
handler = new EventHandlerNonNull(callable, mozilla::dom::GetIncumbentGlobal());
|
||||
}
|
||||
SetEventHandler(aType, EmptyString(), handler);
|
||||
return NS_OK;
|
||||
|
|
|
@ -883,19 +883,23 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS
|
|||
JS::Rooted<JSObject*> scope(cx, listener->GetEventScope());
|
||||
context->BindCompiledEventHandler(mTarget, scope, handler, &boundHandler);
|
||||
aListenerStruct = nullptr;
|
||||
// Note - We pass null for aIncumbentGlobal below. We could also pass the
|
||||
// compilation global, but since the handler is guaranteed to be scripted,
|
||||
// there's no need to use an override, since the JS engine will always give
|
||||
// us the right answer.
|
||||
if (!boundHandler) {
|
||||
listener->ForgetHandler();
|
||||
} else if (listener->EventName() == nsGkAtoms::onerror && win) {
|
||||
nsRefPtr<OnErrorEventHandlerNonNull> handlerCallback =
|
||||
new OnErrorEventHandlerNonNull(boundHandler);
|
||||
new OnErrorEventHandlerNonNull(boundHandler, /* aIncumbentGlobal = */ nullptr);
|
||||
listener->SetHandler(handlerCallback);
|
||||
} else if (listener->EventName() == nsGkAtoms::onbeforeunload && win) {
|
||||
nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handlerCallback =
|
||||
new OnBeforeUnloadEventHandlerNonNull(boundHandler);
|
||||
new OnBeforeUnloadEventHandlerNonNull(boundHandler, /* aIncumbentGlobal = */ nullptr);
|
||||
listener->SetHandler(handlerCallback);
|
||||
} else {
|
||||
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
||||
new EventHandlerNonNull(boundHandler);
|
||||
new EventHandlerNonNull(boundHandler, /* aIncumbentGlobal = */ nullptr);
|
||||
listener->SetHandler(handlerCallback);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2504,11 +2504,11 @@ void
|
|||
nsEventStateManager::DoScrollZoom(nsIFrame *aTargetFrame,
|
||||
int32_t adjustment)
|
||||
{
|
||||
// Exclude form controls and XUL content.
|
||||
// Exclude form controls and content in chrome docshells.
|
||||
nsIContent *content = aTargetFrame->GetContent();
|
||||
if (content &&
|
||||
!content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
|
||||
!content->OwnerDoc()->IsXUL())
|
||||
!nsContentUtils::IsInChromeDocshell(content->OwnerDoc()))
|
||||
{
|
||||
// positive adjustment to decrease zoom, negative to increase
|
||||
int32_t change = (adjustment > 0) ? -1 : 1;
|
||||
|
|
|
@ -207,10 +207,6 @@ public:
|
|||
virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE;
|
||||
layers::ImageContainer* GetImageContainer();
|
||||
|
||||
// Called by the video frame to get the print surface, if this is
|
||||
// a static document and we're not actually playing video
|
||||
gfxASurface* GetPrintSurface() { return mPrintSurface; }
|
||||
|
||||
// Dispatch events
|
||||
using nsGenericHTMLElement::DispatchEvent;
|
||||
virtual nsresult DispatchEvent(const nsAString& aName) MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
@ -1013,8 +1009,6 @@ protected:
|
|||
// non-intrinsic value.
|
||||
bool mPreservesPitch;
|
||||
|
||||
nsRefPtr<gfxASurface> mPrintSurface;
|
||||
|
||||
// Reference to the source element last returned by GetNextSource().
|
||||
// This is the child source element which we're trying to load from.
|
||||
nsCOMPtr<nsIContent> mSourceLoadCandidate;
|
||||
|
|
|
@ -3223,11 +3223,6 @@ VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer()
|
|||
if (mVideoFrameContainer)
|
||||
return mVideoFrameContainer;
|
||||
|
||||
// If we have a print surface, this is just a static image so
|
||||
// no image container is required
|
||||
if (mPrintSurface)
|
||||
return nullptr;
|
||||
|
||||
// Only video frames need an image container.
|
||||
nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
|
||||
if (!video)
|
||||
|
@ -3604,26 +3599,7 @@ HTMLMediaElement::CopyInnerTo(Element* aDest)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aDest->OwnerDoc()->IsStaticDocument()) {
|
||||
HTMLMediaElement* dest = static_cast<HTMLMediaElement*>(aDest);
|
||||
if (mPrintSurface) {
|
||||
dest->mPrintSurface = mPrintSurface;
|
||||
dest->mMediaSize = mMediaSize;
|
||||
} else {
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
Element* element;
|
||||
if (frame && frame->GetType() == nsGkAtoms::HTMLVideoFrame &&
|
||||
static_cast<nsVideoFrame*>(frame)->ShouldDisplayPoster()) {
|
||||
nsIContent* content = static_cast<nsVideoFrame*>(frame)->GetPosterImage();
|
||||
element = content ? content->AsElement() : nullptr;
|
||||
} else {
|
||||
element = const_cast<HTMLMediaElement*>(this);
|
||||
}
|
||||
|
||||
nsLayoutUtils::SurfaceFromElementResult res =
|
||||
nsLayoutUtils::SurfaceFromElement(element,
|
||||
nsLayoutUtils::SFE_WANT_NEW_SURFACE);
|
||||
dest->mPrintSurface = res.mSurface;
|
||||
dest->mMediaSize = nsIntSize(res.mSize.width, res.mSize.height);
|
||||
}
|
||||
dest->mMediaSize = mMediaSize;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
#include "mozilla/Selection.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsTextNode.h"
|
||||
#include "nsIController.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -1283,13 +1283,12 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
|
|||
|
||||
// What follows is a bit of a hack. The editor uses the public DOM APIs
|
||||
// for its content manipulations, and it causes it to fail some security
|
||||
// checks deep inside when initializing. So we push a null JSContext
|
||||
// on the JS stack here to make it clear that we're native code.
|
||||
// checks deep inside when initializing. So we explictly make it clear that
|
||||
// we're native code.
|
||||
// Note that any script that's directly trying to access our value
|
||||
// has to be going through some scriptable object to do that and that
|
||||
// already does the relevant security checks.
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
AutoSystemCaller asc;
|
||||
|
||||
rv = newEditor->Init(domdoc, GetRootNode(), mSelCon, editorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1777,9 +1776,8 @@ nsTextEditorState::GetValue(nsAString& aValue, bool aIgnoreWrap) const
|
|||
// XXXbz if we could just get the textContent of our anonymous content (eg
|
||||
// if plaintext editor didn't create <br> nodes all over), we wouldn't need
|
||||
// this.
|
||||
{ /* Scope for context pusher */
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
{ /* Scope for AutoSystemCaller. */
|
||||
AutoSystemCaller asc;
|
||||
|
||||
mEditor->OutputToString(NS_LITERAL_STRING("text/plain"), flags,
|
||||
aValue);
|
||||
|
@ -1857,9 +1855,8 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
|
|||
// Time to mess with our security context... See comments in GetValue()
|
||||
// for why this is needed. Note that we have to do this up here, because
|
||||
// otherwise SelectAll() will fail.
|
||||
{ /* Scope for context pusher */
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
{
|
||||
AutoSystemCaller asc;
|
||||
|
||||
nsCOMPtr<nsISelection> domSel;
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv;
|
||||
|
|
|
@ -32,6 +32,11 @@ static const int kOpusSamplingRate = 48000;
|
|||
// The duration of an Opus frame, and it must be 2.5, 5, 10, 20, 40 or 60 ms.
|
||||
static const int kFrameDurationMs = 20;
|
||||
|
||||
// The supported sampling rate of input signal (Hz),
|
||||
// must be one of the following. Will resampled to 48kHz otherwise.
|
||||
static const int kOpusSupportedInputSamplingRates[5] =
|
||||
{8000, 12000, 16000, 24000, 48000};
|
||||
|
||||
namespace {
|
||||
|
||||
// An endian-neutral serialization of integers. Serializing T in little endian
|
||||
|
@ -146,12 +151,14 @@ OpusTrackEncoder::Init(int aChannels, int aSamplingRate)
|
|||
if (aChannels <= 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// The granule position is required to be incremented at a rate of 48KHz, and
|
||||
// it is simply calculated as |granulepos = samples * (48000/source_rate)|,
|
||||
// that is, the source sampling rate must divide 48000 evenly.
|
||||
// If this constraint is not satisfied, we resample the input to 48kHz.
|
||||
if (!((aSamplingRate >= 8000) && (kOpusSamplingRate / aSamplingRate) *
|
||||
aSamplingRate == kOpusSamplingRate)) {
|
||||
|
||||
// According to www.opus-codec.org, creating an opus encoder requires the
|
||||
// sampling rate of source signal be one of 8000, 12000, 16000, 24000, or
|
||||
// 48000. If this constraint is not satisfied, we resample the input to 48kHz.
|
||||
nsTArray<int> supportedSamplingRates;
|
||||
supportedSamplingRates.AppendElements(kOpusSupportedInputSamplingRates,
|
||||
MOZ_ARRAY_LENGTH(kOpusSupportedInputSamplingRates));
|
||||
if (!supportedSamplingRates.Contains(aSamplingRate)) {
|
||||
int error;
|
||||
mResampler = speex_resampler_init(mChannels,
|
||||
aSamplingRate,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "WebMBufferedParser.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "VorbisUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
#define VPX_DONT_DEFINE_STDINT_TYPES
|
||||
#include "vpx/vp8dx.h"
|
||||
|
@ -147,6 +148,7 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
|
|||
mOpusParser(nullptr),
|
||||
mOpusDecoder(nullptr),
|
||||
mSkip(0),
|
||||
mSeekPreroll(0),
|
||||
#endif
|
||||
mVideoTrack(0),
|
||||
mAudioTrack(0),
|
||||
|
@ -218,10 +220,20 @@ nsresult WebMReader::ResetDecode()
|
|||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Ignore failed results from vorbis_synthesis_restart. They
|
||||
// aren't fatal and it fails when ResetDecode is called at a
|
||||
// time when no vorbis data has been read.
|
||||
vorbis_synthesis_restart(&mVorbisDsp);
|
||||
if (mAudioCodec == NESTEGG_CODEC_VORBIS) {
|
||||
// Ignore failed results from vorbis_synthesis_restart. They
|
||||
// aren't fatal and it fails when ResetDecode is called at a
|
||||
// time when no vorbis data has been read.
|
||||
vorbis_synthesis_restart(&mVorbisDsp);
|
||||
#ifdef MOZ_OPUS
|
||||
} else if (mAudioCodec == NESTEGG_CODEC_OPUS) {
|
||||
if (mOpusDecoder) {
|
||||
// Reset the decoder.
|
||||
opus_multistream_decoder_ctl(mOpusDecoder, OPUS_RESET_STATE);
|
||||
mSkip = mOpusParser->mPreSkip;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
mVideoPackets.Reset();
|
||||
mAudioPackets.Reset();
|
||||
|
@ -431,6 +443,8 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
|
|||
|
||||
mInfo.mAudio.mChannels = mOpusParser->mChannels;
|
||||
mInfo.mAudio.mChannels = mInfo.mAudio.mChannels > 2 ? 2 : mInfo.mAudio.mChannels;
|
||||
mChannels = mInfo.mAudio.mChannels;
|
||||
mSeekPreroll = params.seek_preroll;
|
||||
#endif
|
||||
} else {
|
||||
Cleanup();
|
||||
|
@ -627,6 +641,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
|
|||
if (ret < 0)
|
||||
return false;
|
||||
NS_ASSERTION(ret == frames, "Opus decoded too few audio samples");
|
||||
CheckedInt64 startTime = tstamp_usecs;
|
||||
|
||||
// Trim the initial frames while the decoder is settling.
|
||||
if (mSkip > 0) {
|
||||
|
@ -643,7 +658,7 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
|
|||
nsAutoArrayPtr<AudioDataValue> trimBuffer(new AudioDataValue[samples]);
|
||||
for (int i = 0; i < samples; i++)
|
||||
trimBuffer[i] = buffer[skipFrames*channels + i];
|
||||
|
||||
startTime = startTime + FramesToUsecs(skipFrames, rate);
|
||||
frames = keepFrames;
|
||||
buffer = trimBuffer;
|
||||
|
||||
|
@ -708,14 +723,12 @@ bool WebMReader::DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset)
|
|||
NS_WARNING("Int overflow converting WebM audio duration");
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt64 time = tstamp_usecs;
|
||||
CheckedInt64 time = startTime - (mCodecDelay / NS_PER_USEC);
|
||||
if (!time.isValid()) {
|
||||
NS_WARNING("Int overflow adding total_duration and tstamp_usecs");
|
||||
NS_WARNING("Int overflow shifting tstamp by codec delay");
|
||||
nestegg_free_packet(aPacket);
|
||||
return false;
|
||||
};
|
||||
|
||||
AudioQueue().Push(new AudioData(mDecoder->GetResource()->Tell(),
|
||||
time.value(),
|
||||
duration.value(),
|
||||
|
@ -982,7 +995,11 @@ nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
uint32_t trackToSeek = mHasVideo ? mVideoTrack : mAudioTrack;
|
||||
int r = nestegg_track_seek(mContext, trackToSeek, aTarget * NS_PER_USEC);
|
||||
uint64_t target = aTarget * NS_PER_USEC;
|
||||
if (mSeekPreroll) {
|
||||
target = std::max(static_cast<uint64_t>(aStartTime * NS_PER_USEC), target - mSeekPreroll);
|
||||
}
|
||||
int r = nestegg_track_seek(mContext, trackToSeek, target);
|
||||
if (r != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -197,6 +197,7 @@ private:
|
|||
nsAutoPtr<OpusParser> mOpusParser;
|
||||
OpusMSDecoder *mOpusDecoder;
|
||||
int mSkip; // Number of samples left to trim before playback.
|
||||
uint64_t mSeekPreroll; // Number of nanoseconds that must be discarded after seeking.
|
||||
#endif
|
||||
|
||||
// Queue of video and audio packets that have been read but not decoded. These
|
||||
|
|
|
@ -322,7 +322,7 @@ nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
|
|||
}
|
||||
|
||||
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
||||
new EventHandlerNonNull(bound);
|
||||
new EventHandlerNonNull(bound, /* aIncumbentGlobal = */ nullptr);
|
||||
|
||||
nsEventHandler eventHandler(handlerCallback);
|
||||
|
||||
|
|
|
@ -46,11 +46,6 @@ ifeq ($(OS_ARCH),WINNT)
|
|||
MODULE_OPTIMIZE_FLAGS = -O2
|
||||
endif
|
||||
|
||||
# disable PGO for Sun Studio
|
||||
ifdef SOLARIS_SUNPRO_CC
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# next line allows use of MOZ_OBJDIR in .mozconfig with older gcc on BeOS, maybe others
|
||||
|
|
|
@ -62,3 +62,7 @@ if CONFIG['OS_TARGET'] == 'Android':
|
|||
if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_MEMORY']:
|
||||
DEFINES['HAVE_MALLOC_USABLE_SIZE'] = True
|
||||
DEFINES['SQLITE_WITHOUT_MSIZE'] = True
|
||||
|
||||
# disable PGO for Sun Studio
|
||||
if CONFIG['SOLARIS_SUNPRO_CC']:
|
||||
NO_PGO = True
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim: ft=cpp tw=78 sw=2 et ts=2
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScriptSettingsStack;
|
||||
static mozilla::ThreadLocal<ScriptSettingsStack*> sScriptSettingsTLS;
|
||||
|
||||
ScriptSettingsStackEntry ScriptSettingsStackEntry::SystemSingleton;
|
||||
|
||||
class ScriptSettingsStack {
|
||||
public:
|
||||
static ScriptSettingsStack& Ref() {
|
||||
return *sScriptSettingsTLS.get();
|
||||
}
|
||||
ScriptSettingsStack() {};
|
||||
|
||||
void Push(ScriptSettingsStackEntry* aSettings) {
|
||||
// The bottom-most entry must always be a candidate entry point.
|
||||
MOZ_ASSERT_IF(mStack.Length() == 0 || mStack.LastElement()->IsSystemSingleton(),
|
||||
aSettings->mIsCandidateEntryPoint);
|
||||
mStack.AppendElement(aSettings);
|
||||
}
|
||||
|
||||
void PushSystem() {
|
||||
mStack.AppendElement(&ScriptSettingsStackEntry::SystemSingleton);
|
||||
}
|
||||
|
||||
void Pop() {
|
||||
MOZ_ASSERT(mStack.Length() > 0);
|
||||
mStack.RemoveElementAt(mStack.Length() - 1);
|
||||
}
|
||||
|
||||
nsIGlobalObject* Incumbent() {
|
||||
if (!mStack.Length()) {
|
||||
return nullptr;
|
||||
}
|
||||
return mStack.LastElement()->mGlobalObject;
|
||||
}
|
||||
|
||||
nsIGlobalObject* EntryPoint() {
|
||||
if (!mStack.Length())
|
||||
return nullptr;
|
||||
for (int i = mStack.Length() - 1; i >= 0; --i) {
|
||||
if (mStack[i]->mIsCandidateEntryPoint) {
|
||||
return mStack[i]->mGlobalObject;
|
||||
}
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Non-empty stack should always have an entry point");
|
||||
}
|
||||
|
||||
private:
|
||||
// These pointers are caller-owned.
|
||||
nsTArray<ScriptSettingsStackEntry*> mStack;
|
||||
};
|
||||
|
||||
void
|
||||
InitScriptSettings()
|
||||
{
|
||||
if (!sScriptSettingsTLS.initialized()) {
|
||||
bool success = sScriptSettingsTLS.init();
|
||||
if (!success) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
ScriptSettingsStack* ptr = new ScriptSettingsStack();
|
||||
sScriptSettingsTLS.set(ptr);
|
||||
}
|
||||
|
||||
void DestroyScriptSettings()
|
||||
{
|
||||
ScriptSettingsStack* ptr = sScriptSettingsTLS.get();
|
||||
MOZ_ASSERT(ptr);
|
||||
sScriptSettingsTLS.set(nullptr);
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
// Note: When we're ready to expose it, GetEntryGlobal will look similar to
|
||||
// GetIncumbentGlobal below.
|
||||
|
||||
nsIGlobalObject*
|
||||
GetIncumbentGlobal()
|
||||
{
|
||||
// We need the current JSContext in order to check the JS for
|
||||
// scripted frames that may have appeared since anyone last
|
||||
// manipulated the stack. If it's null, that means that there
|
||||
// must be no entry point on the stack, and therefore no incumbent
|
||||
// global either.
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
|
||||
if (!cx) {
|
||||
MOZ_ASSERT(ScriptSettingsStack::Ref().EntryPoint() == nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// See what the JS engine has to say. If we've got a scripted caller
|
||||
// override in place, the JS engine will lie to us and pretend that
|
||||
// there's nothing on the JS stack, which will cause us to check the
|
||||
// incumbent script stack below.
|
||||
JS::RootedScript script(cx);
|
||||
if (JS_DescribeScriptedCaller(cx, &script, nullptr)) {
|
||||
JS::RootedObject global(cx, JS_GetGlobalFromScript(script));
|
||||
MOZ_ASSERT(global);
|
||||
return xpc::GetNativeForGlobal(global);
|
||||
}
|
||||
|
||||
// Ok, nothing from the JS engine. Let's use whatever's on the
|
||||
// explicit stack.
|
||||
return ScriptSettingsStack::Ref().Incumbent();
|
||||
}
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
, mEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
if (!aCx) {
|
||||
// If the caller didn't provide a cx, hunt one down. This isn't exactly
|
||||
// fast, but the callers that care about performance can pass an explicit
|
||||
// cx for now. Eventually, the whole cx pushing thing will go away
|
||||
// entirely.
|
||||
MOZ_ASSERT(aIsMainThread, "cx is mandatory off-main-thread");
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobalObject);
|
||||
if (sgo && sgo->GetScriptContext()) {
|
||||
aCx = sgo->GetScriptContext()->GetNativeContext();
|
||||
}
|
||||
if (!aCx) {
|
||||
aCx = nsContentUtils::GetSafeJSContext();
|
||||
}
|
||||
}
|
||||
if (aIsMainThread) {
|
||||
mCxPusher.Push(aCx);
|
||||
}
|
||||
mAc.construct(aCx, aGlobalObject->GetGlobalJSObject());
|
||||
mStack.Push(&mEntry);
|
||||
}
|
||||
|
||||
AutoEntryScript::~AutoEntryScript()
|
||||
{
|
||||
MOZ_ASSERT(mStack.Incumbent() == mEntry.mGlobalObject);
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject* aGlobalObject)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
, mEntry(aGlobalObject, /* aCandidate = */ false)
|
||||
, mCallerOverride(nsContentUtils::GetCurrentJSContextForThread())
|
||||
{
|
||||
mStack.Push(&mEntry);
|
||||
}
|
||||
|
||||
AutoIncumbentScript::~AutoIncumbentScript()
|
||||
{
|
||||
MOZ_ASSERT(mStack.Incumbent() == mEntry.mGlobalObject);
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
AutoSystemCaller::AutoSystemCaller(bool aIsMainThread)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
{
|
||||
if (aIsMainThread) {
|
||||
mCxPusher.PushNull();
|
||||
}
|
||||
mStack.PushSystem();
|
||||
}
|
||||
|
||||
AutoSystemCaller::~AutoSystemCaller()
|
||||
{
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim: ft=cpp tw=78 sw=2 et ts=2
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Utilities for managing the script settings object stack defined in webapps */
|
||||
|
||||
#ifndef mozilla_dom_ScriptSettings_h
|
||||
#define mozilla_dom_ScriptSettings_h
|
||||
|
||||
#include "nsCxPusher.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*
|
||||
* System-wide setup/teardown routines. Init and Destroy should be invoked
|
||||
* once each, at startup and shutdown (respectively).
|
||||
*/
|
||||
void InitScriptSettings();
|
||||
void DestroyScriptSettings();
|
||||
|
||||
// Note: We don't yet expose GetEntryGlobal, because in order for it to be
|
||||
// correct, we first need to replace a bunch of explicit cx pushing in the
|
||||
// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
|
||||
// can mostly be inferred from the JS stack.
|
||||
nsIGlobalObject* GetIncumbentGlobal();
|
||||
|
||||
class ScriptSettingsStack;
|
||||
struct ScriptSettingsStackEntry {
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
bool mIsCandidateEntryPoint;
|
||||
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate)
|
||||
: mGlobalObject(aGlobal)
|
||||
, mIsCandidateEntryPoint(aCandidate)
|
||||
{
|
||||
MOZ_ASSERT(mGlobalObject);
|
||||
MOZ_ASSERT(mGlobalObject->GetGlobalJSObject(),
|
||||
"Must have an actual JS global for the duration on the stack");
|
||||
MOZ_ASSERT(JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
|
||||
"No outer windows allowed");
|
||||
}
|
||||
|
||||
~ScriptSettingsStackEntry() {
|
||||
// We must have an actual JS global for the entire time this is on the stack.
|
||||
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
|
||||
}
|
||||
|
||||
bool IsSystemSingleton() { return this == &SystemSingleton; }
|
||||
static ScriptSettingsStackEntry SystemSingleton;
|
||||
|
||||
private:
|
||||
ScriptSettingsStackEntry() : mGlobalObject(nullptr)
|
||||
, mIsCandidateEntryPoint(true)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* A class that represents a new script entry point.
|
||||
*/
|
||||
class AutoEntryScript {
|
||||
public:
|
||||
AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
bool aIsMainThread = NS_IsMainThread(),
|
||||
// Note: aCx is mandatory off-main-thread.
|
||||
JSContext* aCx = nullptr);
|
||||
~AutoEntryScript();
|
||||
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
dom::ScriptSettingsStackEntry mEntry;
|
||||
nsCxPusher mCxPusher;
|
||||
mozilla::Maybe<JSAutoCompartment> mAc; // This can de-Maybe-fy when mCxPusher
|
||||
// goes away.
|
||||
};
|
||||
|
||||
/*
|
||||
* A class that can be used to force a particular incumbent script on the stack.
|
||||
*/
|
||||
class AutoIncumbentScript {
|
||||
public:
|
||||
AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
|
||||
~AutoIncumbentScript();
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
dom::ScriptSettingsStackEntry mEntry;
|
||||
JS::AutoHideScriptedCaller mCallerOverride;
|
||||
};
|
||||
|
||||
/*
|
||||
* A class used for C++ to indicate that existing entry and incumbent scripts
|
||||
* should not apply to anything in scope, and that callees should act as if
|
||||
* they were invoked "from C++".
|
||||
*/
|
||||
class AutoSystemCaller {
|
||||
public:
|
||||
AutoSystemCaller(bool aIsMainThread = NS_IsMainThread());
|
||||
~AutoSystemCaller();
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
nsCxPusher mCxPusher;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ScriptSettings_h
|
|
@ -59,6 +59,7 @@ EXPORTS.mozilla.dom += [
|
|||
'MessagePortList.h',
|
||||
'Navigator.h',
|
||||
'ScreenOrientation.h',
|
||||
'ScriptSettings.h',
|
||||
'StructuredCloneTags.h',
|
||||
'URL.h',
|
||||
]
|
||||
|
@ -94,6 +95,7 @@ UNIFIED_SOURCES += [
|
|||
'nsWindowMemoryReporter.cpp',
|
||||
'nsWindowRoot.cpp',
|
||||
'nsWrapperCache.cpp',
|
||||
'ScriptSettings.cpp',
|
||||
'URL.cpp',
|
||||
'WindowNamedPropertiesHandler.cpp',
|
||||
]
|
||||
|
|
|
@ -93,6 +93,7 @@ using namespace mozilla;
|
|||
using namespace mozilla::dom;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::widget;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
class gfxContext;
|
||||
|
||||
|
@ -1385,8 +1386,8 @@ nsDOMWindowUtils::NodesFromRect(float aX, float aY,
|
|||
aIgnoreRootScrollFrame, aFlushLayout, aReturn);
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxImageSurface>
|
||||
CanvasToImageSurface(nsIDOMHTMLCanvasElement* aCanvas)
|
||||
static TemporaryRef<DataSourceSurface>
|
||||
CanvasToDataSourceSurface(nsIDOMHTMLCanvasElement* aCanvas)
|
||||
{
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aCanvas);
|
||||
if (!node) {
|
||||
|
@ -1397,9 +1398,8 @@ CanvasToImageSurface(nsIDOMHTMLCanvasElement* aCanvas)
|
|||
"An nsINode that implements nsIDOMHTMLCanvasElement should "
|
||||
"be an element.");
|
||||
nsLayoutUtils::SurfaceFromElementResult result =
|
||||
nsLayoutUtils::SurfaceFromElement(node->AsElement(),
|
||||
nsLayoutUtils::SFE_WANT_IMAGE_SURFACE);
|
||||
return result.mSurface.forget().downcast<gfxImageSurface>();
|
||||
nsLayoutUtils::SurfaceFromElement(node->AsElement());
|
||||
return result.mSourceSurface->GetDataSurface();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1417,8 +1417,8 @@ nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
|
|||
retVal == nullptr)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsRefPtr<gfxImageSurface> img1 = CanvasToImageSurface(aCanvas1);
|
||||
nsRefPtr<gfxImageSurface> img2 = CanvasToImageSurface(aCanvas2);
|
||||
RefPtr<DataSourceSurface> img1 = CanvasToDataSourceSurface(aCanvas1);
|
||||
RefPtr<DataSourceSurface> img2 = CanvasToDataSourceSurface(aCanvas2);
|
||||
|
||||
if (img1 == nullptr || img2 == nullptr ||
|
||||
img1->GetSize() != img2->GetSize() ||
|
||||
|
@ -1426,12 +1426,12 @@ nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
|
|||
return NS_ERROR_FAILURE;
|
||||
|
||||
int v;
|
||||
gfxIntSize size = img1->GetSize();
|
||||
IntSize size = img1->GetSize();
|
||||
uint32_t stride = img1->Stride();
|
||||
|
||||
// we can optimize for the common all-pass case
|
||||
if (stride == (uint32_t) size.width * 4) {
|
||||
v = memcmp(img1->Data(), img2->Data(), size.width * size.height * 4);
|
||||
v = memcmp(img1->GetData(), img2->GetData(), size.width * size.height * 4);
|
||||
if (v == 0) {
|
||||
if (aMaxDifference)
|
||||
*aMaxDifference = 0;
|
||||
|
@ -1444,8 +1444,8 @@ nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
|
|||
uint32_t different = 0;
|
||||
|
||||
for (int j = 0; j < size.height; j++) {
|
||||
unsigned char *p1 = img1->Data() + j*stride;
|
||||
unsigned char *p2 = img2->Data() + j*stride;
|
||||
unsigned char *p1 = img1->GetData() + j*stride;
|
||||
unsigned char *p2 = img2->GetData() + j*stride;
|
||||
v = memcmp(p1, p2, stride);
|
||||
|
||||
if (v) {
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "nsReadableUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "ScriptSettings.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
|
@ -209,6 +210,7 @@
|
|||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "nsITabChild.h"
|
||||
#include "nsIDOMMediaQueryList.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
#include "mozilla/dom/SpeechSynthesis.h"
|
||||
|
@ -4944,8 +4946,9 @@ nsGlobalWindow::RequestAnimationFrame(const JS::Value& aCallback,
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> callbackObj(cx, &aCallback.toObject());
|
||||
nsRefPtr<FrameRequestCallback> callback =
|
||||
new FrameRequestCallback(&aCallback.toObject());
|
||||
new FrameRequestCallback(callbackObj, GetIncumbentGlobal());
|
||||
|
||||
ErrorResult rv;
|
||||
*aHandle = RequestAnimationFrame(*callback, rv);
|
||||
|
@ -11211,18 +11214,18 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
aDialog, aNavigate, argv,
|
||||
getter_AddRefs(domReturn));
|
||||
} else {
|
||||
// Push a null JSContext here so that the window watcher won't screw us
|
||||
// Force a system caller here so that the window watcher won't screw us
|
||||
// up. We do NOT want this case looking at the JS context on the stack
|
||||
// when searching. Compare comments on
|
||||
// nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
|
||||
|
||||
// Note: Because nsWindowWatcher is so broken, it's actually important
|
||||
// that we don't push a null cx here, because that screws it up when it
|
||||
// tries to compute the caller principal to associate with dialog
|
||||
// that we don't force a system caller here, because that screws it up
|
||||
// when it tries to compute the caller principal to associate with dialog
|
||||
// arguments. That whole setup just really needs to be rewritten. :-(
|
||||
nsCxPusher pusher;
|
||||
Maybe<AutoSystemCaller> asc;
|
||||
if (!aContentModal) {
|
||||
pusher.PushNull();
|
||||
asc.construct();
|
||||
}
|
||||
|
||||
|
||||
|
@ -13229,10 +13232,10 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
|
|||
NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
|
||||
const JS::Value &v) { \
|
||||
nsRefPtr<EventHandlerNonNull> handler; \
|
||||
JSObject *callable; \
|
||||
JS::Rooted<JSObject*> callable(cx); \
|
||||
if (v.isObject() && \
|
||||
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
|
||||
handler = new EventHandlerNonNull(callable); \
|
||||
handler = new EventHandlerNonNull(callable, GetIncumbentGlobal()); \
|
||||
} \
|
||||
SetOn##name_(handler); \
|
||||
return NS_OK; \
|
||||
|
@ -13259,10 +13262,10 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
|
|||
} \
|
||||
\
|
||||
nsRefPtr<OnErrorEventHandlerNonNull> handler; \
|
||||
JSObject *callable; \
|
||||
JS::Rooted<JSObject*> callable(cx); \
|
||||
if (v.isObject() && \
|
||||
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
|
||||
handler = new OnErrorEventHandlerNonNull(callable); \
|
||||
handler = new OnErrorEventHandlerNonNull(callable, GetIncumbentGlobal()); \
|
||||
} \
|
||||
elm->SetEventHandler(handler); \
|
||||
return NS_OK; \
|
||||
|
@ -13290,10 +13293,10 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
|
|||
} \
|
||||
\
|
||||
nsRefPtr<OnBeforeUnloadEventHandlerNonNull> handler; \
|
||||
JSObject *callable; \
|
||||
JS::Rooted<JSObject*> callable(cx); \
|
||||
if (v.isObject() && \
|
||||
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
|
||||
handler = new OnBeforeUnloadEventHandlerNonNull(callable); \
|
||||
handler = new OnBeforeUnloadEventHandlerNonNull(callable, GetIncumbentGlobal()); \
|
||||
} \
|
||||
elm->SetEventHandler(handler); \
|
||||
return NS_OK; \
|
||||
|
|
|
@ -360,7 +360,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval,
|
|||
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
mFunction = new Function(funobj);
|
||||
mFunction = new Function(funobj, GetIncumbentGlobal());
|
||||
|
||||
// Create our arg array. argc is the number of arguments passed
|
||||
// to setTimeout or setInterval; the first two are our callback
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "nsPrintfCString.h"
|
||||
#include "prprf.h"
|
||||
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/DOMErrorBinding.h"
|
||||
#include "mozilla/dom/HTMLObjectElement.h"
|
||||
|
@ -2015,12 +2016,12 @@ ConstructJSImplementation(JSContext* aCx, const char* aContractId,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Make sure to have nothing on the JS context stack while creating and
|
||||
// Make sure to divorce ourselves from the calling JS while creating and
|
||||
// initializing the object, so exceptions from that will get reported
|
||||
// properly, since those are never exceptions that a spec wants to be thrown.
|
||||
{ // Scope for the nsCxPusher
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
{
|
||||
AutoSystemCaller asc;
|
||||
|
||||
// Get the XPCOM component containing the JS implementation.
|
||||
nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId);
|
||||
if (!implISupports) {
|
||||
|
|
|
@ -25,8 +25,9 @@ namespace dom {
|
|||
class CallbackFunction : public CallbackObject
|
||||
{
|
||||
public:
|
||||
explicit CallbackFunction(JSObject* aCallable)
|
||||
: CallbackObject(aCallable)
|
||||
explicit CallbackFunction(JS::Handle<JSObject*> aCallable,
|
||||
nsIGlobalObject* aIncumbentGlobal)
|
||||
: CallbackObject(aCallable, aIncumbentGlobal)
|
||||
{
|
||||
MOZ_ASSERT(JS_ObjectIsCallable(nullptr, mCallback));
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@ namespace dom {
|
|||
class CallbackInterface : public CallbackObject
|
||||
{
|
||||
public:
|
||||
explicit CallbackInterface(JSObject* aCallback)
|
||||
: CallbackObject(aCallback)
|
||||
explicit CallbackInterface(JS::Handle<JSObject*> aCallback,
|
||||
nsIGlobalObject *aIncumbentGlobal)
|
||||
: CallbackObject(aCallback, aIncumbentGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "xpcprivate.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "WorkerScope.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -35,15 +36,17 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(CallbackObject)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CallbackObject)
|
||||
tmp->DropCallback();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncumbentGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CallbackObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncumbentGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
||||
CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment)
|
||||
|
@ -63,8 +66,9 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
// callable.
|
||||
|
||||
// First, find the real underlying callback.
|
||||
JSObject* realCallback = js::UncheckedUnwrap(aCallback);
|
||||
JSObject* realCallback = js::UncheckedUnwrap(aCallback->CallbackPreserveColor());
|
||||
JSContext* cx = nullptr;
|
||||
nsIGlobalObject* globalObject = nullptr;
|
||||
|
||||
if (mIsMainThread) {
|
||||
// Now get the global and JSContext for this callback.
|
||||
|
@ -85,18 +89,33 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
// This happens - Removing it causes
|
||||
// test_bug293235.xul to go orange.
|
||||
: nsContentUtils::GetSafeJSContext();
|
||||
globalObject = win;
|
||||
} else {
|
||||
// No DOM Window. Use the SafeJSContext.
|
||||
// No DOM Window. Store the global and use the SafeJSContext.
|
||||
JSObject* glob = js::GetGlobalForObjectCrossCompartment(realCallback);
|
||||
globalObject = xpc::GetNativeForGlobal(glob);
|
||||
MOZ_ASSERT(globalObject);
|
||||
cx = nsContentUtils::GetSafeJSContext();
|
||||
}
|
||||
|
||||
// Make sure our JSContext is pushed on the stack.
|
||||
mCxPusher.Push(cx);
|
||||
} else {
|
||||
cx = workers::GetCurrentThreadJSContext();
|
||||
globalObject = workers::GetCurrentThreadWorkerPrivate()->GlobalScope();
|
||||
}
|
||||
|
||||
// Unmark the callable, and stick it in a Rooted before it can go gray again.
|
||||
// Bail out if there's no useful global. This seems to happen intermittently
|
||||
// on gaia-ui tests, probably because nsInProcessTabChildGlobal is returning
|
||||
// null in some kind of teardown state.
|
||||
if (!globalObject->GetGlobalJSObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAutoEntryScript.construct(globalObject, mIsMainThread, cx);
|
||||
if (aCallback->IncumbentGlobalOrNull()) {
|
||||
mAutoIncumbentScript.construct(aCallback->IncumbentGlobalOrNull());
|
||||
}
|
||||
|
||||
// Unmark the callable (by invoking Callback() and not the CallbackPreserveColor()
|
||||
// variant), and stick it in a Rooted before it can go gray again.
|
||||
// Nothing before us in this function can trigger a CC, so it's safe to wait
|
||||
// until here it do the unmark. This allows us to order the following two
|
||||
// operations _after_ the Push() above, which lets us take advantage of the
|
||||
|
@ -104,15 +123,14 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
//
|
||||
// We can do this even though we're not in the right compartment yet, because
|
||||
// Rooted<> does not care about compartments.
|
||||
JS::ExposeObjectToActiveJS(aCallback);
|
||||
mRootedCallable.construct(cx, aCallback);
|
||||
mRootedCallable.construct(cx, aCallback->Callback());
|
||||
|
||||
if (mIsMainThread) {
|
||||
// Check that it's ok to run this callback at all.
|
||||
// Make sure to unwrap aCallback before passing it in to get the global of
|
||||
// the callback object, not the wrapper.
|
||||
// Make sure to use realCallback to get the global of the callback object,
|
||||
// not the wrapper.
|
||||
bool allowed = nsContentUtils::GetSecurityManager()->
|
||||
ScriptAllowed(js::GetGlobalForObjectCrossCompartment(js::UncheckedUnwrap(aCallback)));
|
||||
ScriptAllowed(js::GetGlobalForObjectCrossCompartment(realCallback));
|
||||
|
||||
if (!allowed) {
|
||||
return;
|
||||
|
@ -120,7 +138,11 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
|||
}
|
||||
|
||||
// Enter the compartment of our callback, so we can actually work with it.
|
||||
mAc.construct(cx, aCallback);
|
||||
//
|
||||
// Note that if the callback is a wrapper, this will not be the same
|
||||
// compartment that we ended up in with mAutoEntryScript above, because the
|
||||
// entry point is based off of the unwrapped callback (realCallback).
|
||||
mAc.construct(cx, mRootedCallable.ref());
|
||||
|
||||
// And now we're ready to go.
|
||||
mCx = cx;
|
||||
|
@ -194,17 +216,11 @@ CallbackObject::CallSetup::~CallSetup()
|
|||
// But be careful: it might not have been constructed at all!
|
||||
mAc.destroyIfConstructed();
|
||||
|
||||
// XXXbz For that matter why do we need to manually call ScriptEvaluated at
|
||||
// all? nsCxPusher::Pop will do that nowadays if !mScriptIsRunning, so the
|
||||
// concerns from bug 295983 don't seem relevant anymore. Do we want to make
|
||||
// sure it's still called when !mScriptIsRunning? I guess play it safe for
|
||||
// now and do what CallEventHandler did, which is call always.
|
||||
|
||||
// Popping an nsCxPusher is safe even if it never got pushed.
|
||||
mCxPusher.Pop();
|
||||
mAutoIncumbentScript.destroyIfConstructed();
|
||||
mAutoEntryScript.destroyIfConstructed();
|
||||
|
||||
// It is important that this is the last thing we do, after leaving the
|
||||
// compartment and popping the context.
|
||||
// compartment and undoing all our entry/incumbent script changes
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::LeaveMicroTask();
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -45,9 +45,13 @@ public:
|
|||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CallbackObject)
|
||||
|
||||
explicit CallbackObject(JSObject* aCallback)
|
||||
// The caller may pass a global object which will act as an override for the
|
||||
// incumbent script settings object when the callback is invoked (overriding
|
||||
// the entry point computed from aCallback). If no override is required, the
|
||||
// caller should pass null.
|
||||
explicit CallbackObject(JS::Handle<JSObject*> aCallback, nsIGlobalObject *aIncumbentGlobal)
|
||||
{
|
||||
Init(aCallback);
|
||||
Init(aCallback, aIncumbentGlobal);
|
||||
}
|
||||
|
||||
virtual ~CallbackObject()
|
||||
|
@ -76,6 +80,11 @@ public:
|
|||
return JS::Handle<JSObject*>::fromMarkedLocation(mCallback.address());
|
||||
}
|
||||
|
||||
nsIGlobalObject* IncumbentGlobalOrNull() const
|
||||
{
|
||||
return mIncumbentGlobal;
|
||||
}
|
||||
|
||||
enum ExceptionHandling {
|
||||
// Report any exception and don't throw it to the caller code.
|
||||
eReportExceptions,
|
||||
|
@ -90,17 +99,19 @@ public:
|
|||
protected:
|
||||
explicit CallbackObject(CallbackObject* aCallbackObject)
|
||||
{
|
||||
Init(aCallbackObject->mCallback);
|
||||
Init(aCallbackObject->mCallback, aCallbackObject->mIncumbentGlobal);
|
||||
}
|
||||
|
||||
private:
|
||||
inline void Init(JSObject* aCallback)
|
||||
inline void Init(JSObject* aCallback, nsIGlobalObject* aIncumbentGlobal)
|
||||
{
|
||||
MOZ_ASSERT(aCallback && !mCallback);
|
||||
// Set mCallback before we hold, on the off chance that a GC could somehow
|
||||
// happen in there... (which would be pretty odd, granted).
|
||||
mCallback = aCallback;
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
mIncumbentGlobal = aIncumbentGlobal;
|
||||
}
|
||||
|
||||
CallbackObject(const CallbackObject&) MOZ_DELETE;
|
||||
|
@ -116,6 +127,7 @@ protected:
|
|||
}
|
||||
|
||||
JS::Heap<JSObject*> mCallback;
|
||||
nsCOMPtr<nsIGlobalObject> mIncumbentGlobal;
|
||||
|
||||
class MOZ_STACK_CLASS CallSetup
|
||||
{
|
||||
|
@ -128,7 +140,7 @@ protected:
|
|||
public:
|
||||
// If aExceptionHandling == eRethrowContentExceptions then aCompartment
|
||||
// needs to be set to the caller's compartment.
|
||||
CallSetup(JS::Handle<JSObject*> aCallable, ErrorResult& aRv,
|
||||
CallSetup(CallbackObject* aCallback, ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment = nullptr);
|
||||
~CallSetup();
|
||||
|
@ -152,17 +164,17 @@ protected:
|
|||
JSCompartment* mCompartment;
|
||||
|
||||
// And now members whose construction/destruction order we need to control.
|
||||
|
||||
nsCxPusher mCxPusher;
|
||||
Maybe<AutoEntryScript> mAutoEntryScript;
|
||||
Maybe<AutoIncumbentScript> mAutoIncumbentScript;
|
||||
|
||||
// Constructed the rooter within the scope of mCxPusher above, so that it's
|
||||
// always within a request during its lifetime.
|
||||
Maybe<JS::Rooted<JSObject*> > mRootedCallable;
|
||||
|
||||
// Can't construct a JSAutoCompartment without a JSContext either. Also,
|
||||
// Put mAc after mCxPusher so that we exit the compartment before we pop the
|
||||
// JSContext. Though in practice we'll often manually order those two
|
||||
// things.
|
||||
// Put mAc after mAutoEntryScript so that we exit the compartment before
|
||||
// we pop the JSContext. Though in practice we'll often manually order
|
||||
// those two things.
|
||||
Maybe<JSAutoCompartment> mAc;
|
||||
|
||||
// An ErrorResult to possibly re-throw exceptions on and whether
|
||||
|
@ -336,28 +348,7 @@ public:
|
|||
nsRefPtr<WebIDLCallbackT> callback = GetWebIDLCallback();
|
||||
return callback.forget();
|
||||
}
|
||||
|
||||
XPCOMCallbackT* callback = GetXPCOMCallback();
|
||||
if (!callback) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(callback);
|
||||
if (!wrappedJS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, wrappedJS->GetJSObject());
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
|
||||
nsRefPtr<WebIDLCallbackT> newCallback = new WebIDLCallbackT(obj);
|
||||
return newCallback.forget();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -3396,7 +3396,10 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||
else:
|
||||
declType = CGGeneric("OwningNonNull<%s>" % name)
|
||||
conversion = (
|
||||
"${declName} = new %s(&${val}.toObject());\n" % name)
|
||||
"{ // Scope for tempRoot\n"
|
||||
" JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());\n"
|
||||
" ${declName} = new %s(tempRoot, mozilla::dom::GetIncumbentGlobal());\n"
|
||||
"}" % name)
|
||||
|
||||
template = wrapObjectTemplate(conversion, type,
|
||||
"${declName} = nullptr",
|
||||
|
@ -3729,7 +3732,10 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||
else:
|
||||
declType = CGGeneric("OwningNonNull<%s>" % name)
|
||||
conversion = (
|
||||
" ${declName} = new %s(&${val}.toObject());\n" % name)
|
||||
"{ // Scope for tempRoot\n"
|
||||
" JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());\n"
|
||||
" ${declName} = new %s(tempRoot, mozilla::dom::GetIncumbentGlobal());\n"
|
||||
"}\n" % name)
|
||||
|
||||
if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
|
||||
haveCallable = "JS_ObjectIsCallable(cx, &${val}.toObject())"
|
||||
|
@ -10549,7 +10555,7 @@ class CGJSImplClass(CGBindingImplClass):
|
|||
decorators = "MOZ_FINAL"
|
||||
destructor = None
|
||||
|
||||
baseConstructors=["mImpl(new %s(aJSImplObject))" % jsImplName(descriptor.name),
|
||||
baseConstructors=["mImpl(new %s(aJSImplObject, /* aIncumbentGlobal = */ nullptr))" % jsImplName(descriptor.name),
|
||||
"mParent(aParent)"]
|
||||
parentInterface = descriptor.interface.parent
|
||||
while parentInterface:
|
||||
|
@ -10676,12 +10682,12 @@ class CGCallback(CGClass):
|
|||
|
||||
def getConstructors(self):
|
||||
return [ClassConstructor(
|
||||
[Argument("JSObject*", "aCallback")],
|
||||
[Argument("JS::Handle<JSObject*>", "aCallback"), Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
||||
bodyInHeader=True,
|
||||
visibility="public",
|
||||
explicit=True,
|
||||
baseConstructors=[
|
||||
"%s(aCallback)" % self.baseName
|
||||
"%s(aCallback, aIncumbentGlobal)" % self.baseName,
|
||||
])]
|
||||
|
||||
def getMethodImpls(self, method):
|
||||
|
@ -10706,7 +10712,7 @@ class CGCallback(CGClass):
|
|||
argsWithoutThis = list(args)
|
||||
args.insert(0, Argument("const T&", "thisObj"))
|
||||
|
||||
setupCall = ("CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
|
||||
setupCall = ("CallSetup s(this, aRv, aExceptionHandling);\n"
|
||||
"if (!s.GetContext()) {\n"
|
||||
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
||||
" return${errorReturn};\n"
|
||||
|
@ -10996,7 +11002,7 @@ class CallbackMember(CGNativeMember):
|
|||
if self.needThisHandling:
|
||||
# It's been done for us already
|
||||
return ""
|
||||
callSetup = "CallSetup s(CallbackPreserveColor(), aRv"
|
||||
callSetup = "CallSetup s(this, aRv"
|
||||
if self.rethrowContentException:
|
||||
# getArgs doesn't add the aExceptionHandling argument but does add
|
||||
# aCompartment for us.
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
int
|
||||
AppendHeaderName(uint8_t* aRetBuf, const char* aName, int aLength)
|
||||
AppendHeaderName(uint8_t* aRetBuf, int aBufferSize, const char* aName,
|
||||
int aLength)
|
||||
{
|
||||
int headerLength = aLength + 3;
|
||||
|
||||
|
@ -17,13 +18,15 @@ AppendHeaderName(uint8_t* aRetBuf, const char* aName, int aLength)
|
|||
aRetBuf[1] = (headerLength & 0xFF00) >> 8;
|
||||
aRetBuf[2] = headerLength & 0x00FF;
|
||||
|
||||
memcpy(&aRetBuf[3], aName, aLength);
|
||||
memcpy(&aRetBuf[3], aName, (aLength < aBufferSize - 3)? aLength
|
||||
: aBufferSize - 3);
|
||||
|
||||
return headerLength;
|
||||
}
|
||||
|
||||
int
|
||||
AppendHeaderBody(uint8_t* aRetBuf, uint8_t* aData, int aLength)
|
||||
AppendHeaderBody(uint8_t* aRetBuf, int aBufferSize, const uint8_t* aData,
|
||||
int aLength)
|
||||
{
|
||||
int headerLength = aLength + 3;
|
||||
|
||||
|
@ -31,7 +34,8 @@ AppendHeaderBody(uint8_t* aRetBuf, uint8_t* aData, int aLength)
|
|||
aRetBuf[1] = (headerLength & 0xFF00) >> 8;
|
||||
aRetBuf[2] = headerLength & 0x00FF;
|
||||
|
||||
memcpy(&aRetBuf[3], aData, aLength);
|
||||
memcpy(&aRetBuf[3], aData, (aLength < aBufferSize - 3)? aLength
|
||||
: aBufferSize - 3);
|
||||
|
||||
return headerLength;
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче