mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Merge m-c to b2g-inbound. a=merge
--HG-- rename : dom/telephony/gonk/TelephonyProvider.js => dom/telephony/gonk/TelephonyService.js
This commit is contained in:
commit
8d0739d241
@ -813,7 +813,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
||||
#endif
|
||||
|
||||
@BINPATH@/components/DataStore.manifest
|
||||
@BINPATH@/components/DataStoreService.js
|
||||
@BINPATH@/components/DataStoreImpl.js
|
||||
@BINPATH@/components/dom_datastore.xpt
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
|
@ -85,7 +85,13 @@ add_task(function*() {
|
||||
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
|
||||
|
||||
let wasInformedCorrectlyOfAreaDisappearing = false;
|
||||
let windowClosed = null;
|
||||
//XXXgijs So we could be using promiseWindowClosed here. However, after
|
||||
// repeated random oranges, I'm instead relying on onWindowClosed below to
|
||||
// fire appropriately - it is linked to an unload event as well, and so
|
||||
// reusing it prevents a potential race between unload handlers where the
|
||||
// one from promiseWindowClosed could fire before the onWindowClosed
|
||||
// (and therefore onAreaNodeRegistered) one, causing the test to fail.
|
||||
let windowCloseDeferred = Promise.defer();
|
||||
listener = {
|
||||
onAreaNodeUnregistered: function(aArea, aNode, aReason) {
|
||||
if (aArea == TOOLBARID) {
|
||||
@ -96,8 +102,7 @@ add_task(function*() {
|
||||
},
|
||||
onWindowClosed: function(aWindow) {
|
||||
if (aWindow == otherWin) {
|
||||
info("Got window closed notification for correct window.");
|
||||
windowClosed = aWindow;
|
||||
windowCloseDeferred.resolve(aWindow);
|
||||
} else {
|
||||
info("Other window was closed!");
|
||||
info("Other window title: " + (aWindow.document && aWindow.document.title));
|
||||
@ -106,7 +111,8 @@ add_task(function*() {
|
||||
},
|
||||
};
|
||||
CustomizableUI.addListener(listener);
|
||||
yield promiseWindowClosed(otherWin);
|
||||
otherWin.close();
|
||||
let windowClosed = yield windowCloseDeferred.promise;
|
||||
|
||||
is(windowClosed, otherWin, "Window should have sent onWindowClosed notification.");
|
||||
ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
|
||||
|
@ -249,8 +249,13 @@ function openAndLoadWindow(aOptions, aWaitForDelayedStartup=false) {
|
||||
}
|
||||
|
||||
function promiseWindowClosed(win) {
|
||||
let deferred = Promise.defer();
|
||||
win.addEventListener("unload", function onunload() {
|
||||
win.removeEventListener("unload", onunload);
|
||||
deferred.resolve();
|
||||
});
|
||||
win.close();
|
||||
return waitForCondition(() => win.closed);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promisePanelShown(win) {
|
||||
|
@ -203,6 +203,11 @@ var gPermissionManager = {
|
||||
{
|
||||
if (aTopic == "perm-changed") {
|
||||
var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
|
||||
|
||||
// Ignore unrelated permission types.
|
||||
if (permission.type != this._type)
|
||||
return;
|
||||
|
||||
if (aData == "added") {
|
||||
this._addPermissionToList(permission);
|
||||
++this._view._rowCount;
|
||||
|
@ -8,6 +8,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "BingTranslation" ];
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
@ -327,14 +328,16 @@ let BingTokenManager = {
|
||||
let params = [
|
||||
"grant_type=client_credentials",
|
||||
"scope=" + encodeURIComponent("http://api.microsofttranslator.com"),
|
||||
"client_id=",
|
||||
"client_secret="
|
||||
"client_id=" +
|
||||
getAuthTokenParam("%BING_API_CLIENTID%", "browser.translation.bing.clientIdOverride"),
|
||||
"client_secret=" +
|
||||
getAuthTokenParam("%BING_API_KEY%", "browser.translation.bing.apiKeyOverride")
|
||||
];
|
||||
|
||||
let deferred = Promise.defer();
|
||||
this._pendingRequest = deferred.promise;
|
||||
request.post(params.join("&"), function(err) {
|
||||
this._pendingRequest = null;
|
||||
BingTokenManager._pendingRequest = null;
|
||||
|
||||
if (err) {
|
||||
deferred.reject(err);
|
||||
@ -367,3 +370,16 @@ function escapeXML(aStr) {
|
||||
.replace("<", "<", "g")
|
||||
.replace(">", ">", "g");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an auth token (clientID or client secret), which may be overridden by
|
||||
* a pref if it's set.
|
||||
*/
|
||||
function getAuthTokenParam(key, prefName) {
|
||||
let val;
|
||||
try {
|
||||
val = Services.prefs.getCharPref(prefName);
|
||||
} catch(ex) {}
|
||||
|
||||
return encodeURIComponent(Services.urlFormatter.formatURL(val || key));
|
||||
}
|
||||
|
@ -42,10 +42,10 @@
|
||||
</xul:hbox>
|
||||
|
||||
<!-- translating -->
|
||||
<xul:hbox class="translating-box" pack="center">
|
||||
<xul:vbox class="translating-box" pack="center">
|
||||
<xul:label class="translate-infobar-element"
|
||||
value="&translation.translatingContent.label;"/>
|
||||
</xul:hbox>
|
||||
</xul:vbox>
|
||||
|
||||
<!-- translated -->
|
||||
<xul:hbox class="translated-box" align="center">
|
||||
@ -58,11 +58,13 @@
|
||||
</xul:menulist>
|
||||
<xul:label class="translate-infobar-element"
|
||||
value="&translation.translatedTo.label;"/>
|
||||
<xul:menulist anonid="toLanguage"
|
||||
<xul:menulist class="translate-infobar-element"
|
||||
anonid="toLanguage"
|
||||
oncommand="document.getBindingParent(this).translate()">
|
||||
<xul:menupopup/>
|
||||
</xul:menulist>
|
||||
<xul:label value="&translation.translatedToSuffix.label;"/>
|
||||
<xul:label class="translate-infobar-element"
|
||||
value="&translation.translatedToSuffix.label;"/>
|
||||
<xul:button anonid="showOriginal"
|
||||
class="translate-infobar-element"
|
||||
label="&translation.showOriginal.button;"
|
||||
|
@ -113,6 +113,8 @@ skip-if = os == 'win' # bug 1005274
|
||||
[browser_dbg_break-on-dom-06.js]
|
||||
[browser_dbg_break-on-dom-07.js]
|
||||
[browser_dbg_break-on-dom-08.js]
|
||||
[browser_dbg_break-on-dom-event.js]
|
||||
skip-if = os == "mac" || e10s # Bug 895426
|
||||
[browser_dbg_breakpoints-actual-location.js]
|
||||
[browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
|
||||
[browser_dbg_breakpoints-button-01.js]
|
||||
@ -124,6 +126,7 @@ skip-if = os == 'win' # bug 1005274
|
||||
[browser_dbg_breakpoints-highlight.js]
|
||||
[browser_dbg_breakpoints-new-script.js]
|
||||
[browser_dbg_breakpoints-pane.js]
|
||||
[browser_dbg_chrome-create.js]
|
||||
[browser_dbg_chrome-debugging.js]
|
||||
[browser_dbg_clean-exit-window.js]
|
||||
skip-if = true # Bug 933950 (leaky test)
|
||||
@ -165,6 +168,8 @@ skip-if = true # Bug 933950 (leaky test)
|
||||
[browser_dbg_navigation.js]
|
||||
[browser_dbg_no-page-sources.js]
|
||||
[browser_dbg_on-pause-highlight.js]
|
||||
[browser_dbg_on-pause-raise.js]
|
||||
skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
|
||||
[browser_dbg_optimized-out-vars.js]
|
||||
[browser_dbg_panel-size.js]
|
||||
[browser_dbg_parser-01.js]
|
||||
@ -298,9 +303,3 @@ skip-if = (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
|
||||
[browser_dbg_variables-view-webidl.js]
|
||||
[browser_dbg_watch-expressions-01.js]
|
||||
[browser_dbg_watch-expressions-02.js]
|
||||
[browser_dbg_chrome-create.js]
|
||||
skip-if = true # Test doesn't clean up after itself (bug 918507), but also bug 847558 on Linux
|
||||
[browser_dbg_on-pause-raise.js]
|
||||
skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
|
||||
[browser_dbg_break-on-dom-event.js]
|
||||
skip-if = os == "mac" || e10s # Bug 895426
|
||||
|
@ -51,7 +51,10 @@ registerCleanupFunction(function() {
|
||||
|
||||
// Import the GCLI test helper
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
|
||||
testDir = testDir.replace(/\/\//g, '/');
|
||||
testDir = testDir.replace("chrome:/mochitest", "chrome://mochitest");
|
||||
let helpersjs = testDir + "/../../commandline/test/helpers.js";
|
||||
Services.scriptloader.loadSubScript(helpersjs, this);
|
||||
|
||||
// Redeclare dbg_assert with a fatal behavior.
|
||||
function dbg_assert(cond, e) {
|
||||
|
@ -857,7 +857,7 @@ bin/libfreebl_32int64_3.so
|
||||
#endif
|
||||
|
||||
@BINPATH@/components/DataStore.manifest
|
||||
@BINPATH@/components/DataStoreService.js
|
||||
@BINPATH@/components/DataStoreImpl.js
|
||||
@BINPATH@/components/dom_datastore.xpt
|
||||
|
||||
|
||||
|
@ -11,16 +11,16 @@
|
||||
|
||||
<!ENTITY color "Text and Background">
|
||||
<!ENTITY textColor.label "Text:">
|
||||
<!ENTITY textColor.accesskey "t">
|
||||
<!ENTITY textColor.accesskey "T">
|
||||
<!ENTITY backgroundColor.label "Background:">
|
||||
<!ENTITY backgroundColor.accesskey "b">
|
||||
<!ENTITY backgroundColor.accesskey "B">
|
||||
<!ENTITY useSystemColors.label "Use system colors">
|
||||
<!ENTITY useSystemColors.accesskey "s">
|
||||
|
||||
<!ENTITY underlineLinks.label "Underline links">
|
||||
<!ENTITY underlineLinks.accesskey "u">
|
||||
<!ENTITY underlineLinks.accesskey "U">
|
||||
<!ENTITY links "Link Colors">
|
||||
<!ENTITY linkColor.label "Unvisited Links:">
|
||||
<!ENTITY linkColor.accesskey "l">
|
||||
<!ENTITY linkColor.accesskey "L">
|
||||
<!ENTITY visitedLinkColor.label "Visited Links:">
|
||||
<!ENTITY visitedLinkColor.accesskey "v">
|
||||
<!ENTITY visitedLinkColor.accesskey "V">
|
||||
|
@ -250,7 +250,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
|
@ -368,7 +368,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
|
@ -153,6 +153,11 @@
|
||||
|
||||
/* Debugging pane controls */
|
||||
|
||||
#debugging-controls .devtools-toolbarbutton > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#resume {
|
||||
list-style-image: url(debugger-play.png);
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
@ -170,6 +175,25 @@
|
||||
list-style-image: url(debugger-step-out.png);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#resume {
|
||||
list-style-image: url(debugger-play@2x.png);
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
|
||||
#step-over {
|
||||
list-style-image: url(debugger-step-over@2x.png);
|
||||
}
|
||||
|
||||
#step-in {
|
||||
list-style-image: url(debugger-step-in@2x.png);
|
||||
}
|
||||
|
||||
#step-out {
|
||||
list-style-image: url(debugger-step-out@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#debugging-controls > toolbarbutton {
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
@ -256,6 +280,12 @@
|
||||
background-size: 12px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.selected .call-item-gutter {
|
||||
background-image: url("editor-debug-location@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.theme-dark .call-item-gutter {
|
||||
background-color: #181d20;
|
||||
color: #5f7387;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 218 B |
3
browser/themes/shared/devtools/images/dropmarker.svg
Normal file
3
browser/themes/shared/devtools/images/dropmarker.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="8" height="4" viewBox="0 0 8 4" enable-background="new 0 0 8 4">
|
||||
<polygon points="0,0 4,4 8,0" fill="#B6BABF" />
|
||||
</svg>
|
After Width: | Height: | Size: 213 B |
@ -96,7 +96,7 @@
|
||||
-moz-appearance: none;
|
||||
display: -moz-box;
|
||||
background-color: transparent;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
border-width: 0;
|
||||
min-width: 16px;
|
||||
@ -122,7 +122,7 @@
|
||||
.devtools-responsiveui-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
|
||||
.devtools-responsiveui-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-appearance: none !important;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@
|
||||
.devtools-menulist > .menulist-dropmarker {
|
||||
-moz-appearance: none;
|
||||
display: -moz-box;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
min-width: 16px;
|
||||
}
|
||||
@ -168,7 +168,7 @@
|
||||
.devtools-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
|
||||
.devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-appearance: none !important;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
@ -125,6 +125,11 @@ text {
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#inspector-pane-toggle[pane-collapsed] {
|
||||
list-style-image: url(debugger-expand.png);
|
||||
}
|
||||
@ -132,3 +137,18 @@ text {
|
||||
#inspector-pane-toggle:active {
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#inspector-pane-toggle {
|
||||
list-style-image: url(debugger-collapse@2x.png);
|
||||
-moz-image-region: rect(0px,32px,32px,0px);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle[pane-collapsed] {
|
||||
list-style-image: url(debugger-expand@2x.png);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle:active {
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
}
|
@ -288,7 +288,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
@ -688,7 +688,7 @@ browser.jar:
|
||||
skin/classic/aero/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/aero/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/aero/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/aero/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/aero/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/aero/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/aero/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/aero/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
|
@ -814,7 +814,7 @@ class Automation(object):
|
||||
xrePath = None, certPath = None,
|
||||
debuggerInfo = None, symbolsPath = None,
|
||||
timeout = -1, maxTime = None, onLaunch = None,
|
||||
webapprtChrome = False, screenshotOnFail=False):
|
||||
webapprtChrome = False, screenshotOnFail=False, testPath=None):
|
||||
"""
|
||||
Run the app, log the duration it took to execute, return the status code.
|
||||
Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
|
||||
|
@ -9187,6 +9187,7 @@ if test -z "$direct_nspr_config"; then
|
||||
LDFLAGS="$_SUBDIR_LDFLAGS"
|
||||
HOST_CC="$_SUBDIR_HOST_CC"
|
||||
HOST_CFLAGS="$_SUBDIR_HOST_CFLAGS"
|
||||
HOST_CXXFLAGS="$_SUBDIR_HOST_CXXFLAGS"
|
||||
HOST_LDFLAGS="$_SUBDIR_HOST_LDFLAGS"
|
||||
RC=
|
||||
fi
|
||||
@ -9289,6 +9290,7 @@ CXXFLAGS="$_SUBDIR_CXXFLAGS"
|
||||
LDFLAGS="$_SUBDIR_LDFLAGS"
|
||||
HOST_CC="$_SUBDIR_HOST_CC"
|
||||
HOST_CFLAGS="$_SUBDIR_HOST_CFLAGS"
|
||||
HOST_CXXFLAGS="$_SUBDIR_HOST_CXXFLAGS"
|
||||
HOST_LDFLAGS="$_SUBDIR_HOST_LDFLAGS"
|
||||
RC=
|
||||
|
||||
|
@ -138,7 +138,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
|
||||
enum DocumentFlavor {
|
||||
DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
|
||||
DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
|
||||
DocumentFlavorSVG // SVGDocument
|
||||
DocumentFlavorSVG, // SVGDocument
|
||||
DocumentFlavorPlain, // Just a Document
|
||||
};
|
||||
|
||||
// Document states
|
||||
@ -2685,7 +2686,8 @@ nsresult
|
||||
NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData = false);
|
||||
|
||||
nsresult
|
||||
NS_NewXMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData = false);
|
||||
NS_NewXMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData = false,
|
||||
bool aIsPlainDocument = false);
|
||||
|
||||
nsresult
|
||||
NS_NewSVGDocument(nsIDocument** aInstancePtrResult);
|
||||
|
@ -12067,7 +12067,7 @@ nsIDocument::Constructor(const GlobalObject& aGlobal,
|
||||
prin->GetPrincipal(),
|
||||
true,
|
||||
global,
|
||||
DocumentFlavorLegacyGuess);
|
||||
DocumentFlavorPlain);
|
||||
if (NS_FAILED(res)) {
|
||||
rv.Throw(res);
|
||||
return nullptr;
|
||||
|
@ -566,6 +566,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 904183 # b2g(cl
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(bug 904183) b2g-debug(bug 904183) b2g-desktop(bug 904183)
|
||||
[test_createHTMLDocument.html]
|
||||
[test_declare_stylesheet_obsolete.html]
|
||||
[test_document_constructor.html]
|
||||
[test_domparser_null_char.html]
|
||||
[test_domparsing.html]
|
||||
[test_elementTraversal.html]
|
||||
|
31
content/base/test/test_document_constructor.html
Normal file
31
content/base/test/test_document_constructor.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1017932
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1017932</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1017932 **/
|
||||
var doc = new Document;
|
||||
ok(doc instanceof Document, "Should have a document");
|
||||
ok(!(doc instanceof XMLDocument), "Should not be an XMLDocument");
|
||||
ok(!("load" in doc), "Should not have a load() method");
|
||||
is(Object.getPrototypeOf(doc), Document.prototype,
|
||||
"Should have the right proto");
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1017932">Mozilla Bug 1017932</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -50,6 +50,7 @@
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/XMLDocumentBinding.h"
|
||||
#include "mozilla/dom/DocumentBinding.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -87,7 +88,10 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
|
||||
} else if (aFlavor == DocumentFlavorHTML) {
|
||||
rv = NS_NewHTMLDocument(getter_AddRefs(d));
|
||||
isHTML = true;
|
||||
} else if (aFlavor == DocumentFlavorPlain) {
|
||||
rv = NS_NewXMLDocument(getter_AddRefs(d), aLoadedAsData, true);
|
||||
} else if (aDoctype) {
|
||||
MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
|
||||
nsAutoString publicId, name;
|
||||
aDoctype->GetPublicId(publicId);
|
||||
if (publicId.IsEmpty()) {
|
||||
@ -117,6 +121,7 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
|
||||
rv = NS_NewXMLDocument(getter_AddRefs(d));
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(aFlavor == DocumentFlavorLegacyGuess);
|
||||
rv = NS_NewXMLDocument(getter_AddRefs(d));
|
||||
}
|
||||
|
||||
@ -172,7 +177,8 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewXMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData)
|
||||
NS_NewXMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData,
|
||||
bool aIsPlainDocument)
|
||||
{
|
||||
nsRefPtr<XMLDocument> doc = new XMLDocument();
|
||||
|
||||
@ -184,6 +190,7 @@ NS_NewXMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData)
|
||||
}
|
||||
|
||||
doc->SetLoadedAsData(aLoadedAsData);
|
||||
doc->mIsPlainDocument = aIsPlainDocument;
|
||||
doc.forget(aInstancePtrResult);
|
||||
|
||||
return NS_OK;
|
||||
@ -597,6 +604,7 @@ XMLDocument::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
|
||||
// State from XMLDocument
|
||||
clone->mAsync = mAsync;
|
||||
clone->mIsPlainDocument = mIsPlainDocument;
|
||||
|
||||
return CallQueryInterface(clone.get(), aResult);
|
||||
}
|
||||
@ -604,6 +612,10 @@ XMLDocument::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
JSObject*
|
||||
XMLDocument::WrapNode(JSContext *aCx)
|
||||
{
|
||||
if (mIsPlainDocument) {
|
||||
return DocumentBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
return XMLDocumentBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,9 @@ public:
|
||||
protected:
|
||||
virtual JSObject* WrapNode(JSContext *aCx) MOZ_OVERRIDE;
|
||||
|
||||
friend nsresult (::NS_NewXMLDocument)(nsIDocument**, bool, bool);
|
||||
|
||||
|
||||
// mChannelIsPending indicates whether we're currently asynchronously loading
|
||||
// data from mChannel (via document.load() or normal load). It's set to true
|
||||
// when we first find out about the channel (StartDocumentLoad) and set to
|
||||
@ -79,6 +82,9 @@ protected:
|
||||
bool mChannelIsPending;
|
||||
bool mAsync;
|
||||
bool mLoopingForSyncLoad;
|
||||
|
||||
// If true. we're really a Document, not an XMLDocument
|
||||
bool mIsPlainDocument;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -82,7 +82,7 @@
|
||||
#endif
|
||||
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
#include "nsIDataStoreService.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
#include "nsScriptNameSpaceManager.h"
|
||||
@ -1466,8 +1466,7 @@ Navigator::GetDataStores(nsPIDOMWindow* aWindow,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDataStoreService> service =
|
||||
do_GetService("@mozilla.org/datastore-service;1");
|
||||
nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
|
||||
if (!service) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
|
@ -4339,13 +4339,7 @@ nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
|
||||
nsGlobalWindow::IsChromeWindow(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
// For now, have to deal with XPConnect objects here.
|
||||
nsGlobalWindow* win;
|
||||
nsresult rv = UNWRAP_OBJECT(Window, aObj, win);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrapper(aCx, aObj);
|
||||
win = static_cast<nsGlobalWindow*>(piWin.get());
|
||||
}
|
||||
return win->IsChromeWindow();
|
||||
return xpc::WindowOrNull(aObj)->IsChromeWindow();
|
||||
}
|
||||
|
||||
nsIDOMOfflineResourceList*
|
||||
@ -4471,9 +4465,9 @@ nsGlobalWindow::GetControllers(nsIControllers** aResult)
|
||||
}
|
||||
|
||||
nsIDOMWindow*
|
||||
nsGlobalWindow::GetOpener(ErrorResult& aError)
|
||||
nsGlobalWindow::GetOpenerWindow(ErrorResult& aError)
|
||||
{
|
||||
FORWARD_TO_OUTER_OR_THROW(GetOpener, (aError), aError, nullptr);
|
||||
FORWARD_TO_OUTER_OR_THROW(GetOpenerWindow, (aError), aError, nullptr);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
|
||||
if (!opener) {
|
||||
@ -4512,18 +4506,41 @@ nsGlobalWindow::GetOpener(ErrorResult& aError)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
nsGlobalWindow::GetOpener(JSContext* aCx, ErrorResult& aError)
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(aError);
|
||||
if (aError.Failed() || !opener) {
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
aError = nsContentUtils::WrapNative(aCx, opener, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetOpener(nsIDOMWindow** aOpener)
|
||||
nsGlobalWindow::GetScriptableOpener(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aOpener)
|
||||
{
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIDOMWindow> opener = GetOpener(rv);
|
||||
opener.forget(aOpener);
|
||||
aOpener.set(GetOpener(aCx, rv));
|
||||
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetOpener(nsIDOMWindow** aOpener)
|
||||
{
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIDOMWindow> opener = GetOpenerWindow(rv);
|
||||
opener.forget(aOpener);
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener, ErrorResult& aError)
|
||||
nsGlobalWindow::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
// Check if we were called from a privileged chrome script. If not, and if
|
||||
// aOpener is not null, just define aOpener on our inner window's JS object,
|
||||
@ -4531,35 +4548,15 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener, ErrorResult& aError)
|
||||
// Xray expando object, but don't set it on the outer window, so that it'll
|
||||
// get reset on navigation. This is just like replaceable properties, but
|
||||
// we're not quite readonly.
|
||||
if (aOpener && !nsContentUtils::IsCallerChrome()) {
|
||||
// JS_WrapObject will outerize, so we don't care if aOpener is an inner.
|
||||
nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOpener);
|
||||
if (!glob) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
AutoJSContext cx;
|
||||
JSAutoRequest ar(cx);
|
||||
// Note we explicitly do NOT enter any particular compartment here; we want
|
||||
// the caller compartment in cases when we have a caller, so that we define
|
||||
// expandos on Xrays as needed.
|
||||
|
||||
JS::Rooted<JSObject*> otherObj(cx, glob->GetGlobalJSObject());
|
||||
if (!otherObj) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> thisObj(cx, GetWrapperPreserveColor());
|
||||
if (!aOpener.isNull() && !nsContentUtils::IsCallerChrome()) {
|
||||
JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
|
||||
if (!thisObj) {
|
||||
aError.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!JS_WrapObject(cx, &otherObj) ||
|
||||
!JS_WrapObject(cx, &thisObj) ||
|
||||
!JS_DefineProperty(cx, thisObj, "opener", otherObj, JSPROP_ENUMERATE,
|
||||
if (!JS_WrapObject(aCx, &thisObj) ||
|
||||
!JS_DefineProperty(aCx, thisObj, "opener", aOpener, JSPROP_ENUMERATE,
|
||||
JS_PropertyStub, JS_StrictPropertyStub)) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
@ -4567,16 +4564,47 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener, ErrorResult& aError)
|
||||
return;
|
||||
}
|
||||
|
||||
SetOpenerWindow(aOpener, false);
|
||||
if (!aOpener.isObjectOrNull()) {
|
||||
// Chrome code trying to set some random value as opener
|
||||
aError.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
}
|
||||
|
||||
nsGlobalWindow* win = nullptr;
|
||||
if (aOpener.isObject()) {
|
||||
JSObject* unwrapped = js::CheckedUnwrap(&aOpener.toObject(),
|
||||
/* stopAtOuter = */ false);
|
||||
if (!unwrapped) {
|
||||
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
win = xpc::WindowOrNull(unwrapped);
|
||||
if (!win) {
|
||||
// Wasn't a window
|
||||
aError.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SetOpenerWindow(win, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::SetScriptableOpener(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aOpener)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetOpener(aCx, aOpener, rv);
|
||||
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener)
|
||||
{
|
||||
ErrorResult rv;
|
||||
SetOpener(aOpener, rv);
|
||||
|
||||
return rv.ErrorCode();
|
||||
SetOpenerWindow(aOpener, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@ -13699,13 +13727,7 @@ bool
|
||||
nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
|
||||
{
|
||||
// For now, have to deal with XPConnect objects here.
|
||||
nsGlobalWindow* win;
|
||||
nsresult rv = UNWRAP_OBJECT(Window, aGlobal, win);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrapper(aCx, aGlobal);
|
||||
win = static_cast<nsGlobalWindow*>(piWin.get());
|
||||
}
|
||||
return win->IsModalContentWindow();
|
||||
return xpc::WindowOrNull(aGlobal)->IsModalContentWindow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -836,8 +836,12 @@ public:
|
||||
aError = GetScriptableTop(getter_AddRefs(top));
|
||||
return top.forget();
|
||||
}
|
||||
nsIDOMWindow* GetOpener(mozilla::ErrorResult& aError);
|
||||
void SetOpener(nsIDOMWindow* aOpener, mozilla::ErrorResult& aError);
|
||||
protected:
|
||||
nsIDOMWindow* GetOpenerWindow(mozilla::ErrorResult& aError);
|
||||
public:
|
||||
JS::Value GetOpener(JSContext* aCx, mozilla::ErrorResult& aError);
|
||||
void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
|
||||
mozilla::ErrorResult& aError);
|
||||
using nsIDOMWindow::GetParent;
|
||||
already_AddRefed<nsIDOMWindow> GetParent(mozilla::ErrorResult& aError);
|
||||
mozilla::dom::Element* GetFrameElement(mozilla::ErrorResult& aError);
|
||||
|
@ -59,6 +59,25 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=868996
|
||||
is(evalsb("win.opener", sb2), window,
|
||||
"Navigating a window should have reset the opener in sb2");
|
||||
|
||||
win.opener = 5;
|
||||
evalsb("win.opener = 5", sb1);
|
||||
evalsb("win.opener = 5", sb2);
|
||||
is(win.opener, 5, "Should be able to set an opener to a primitive");
|
||||
is(evalsb("win.opener", sb1), 5,
|
||||
"Should be able to set the opener to a primitive in a sandbox one");
|
||||
is(evalsb("win.opener", sb2), 5,
|
||||
"Should be able to set the opener to a primitive in a sandbox two");
|
||||
win.location = "data:text/html,<script>opener.setTimeout(opener.continueOpenerTest2, 0, this);</" + "script>";
|
||||
}
|
||||
|
||||
function continueOpenerTest2(win) {
|
||||
is(win.opener, window,
|
||||
"Navigating a window again should have reset the opener we stashed on it temporarily");
|
||||
is(evalsb("win.opener", sb1), window,
|
||||
"Navigating a window again should have reset the opener in sb1");
|
||||
is(evalsb("win.opener", sb2), window,
|
||||
"Navigating a window again should have reset the opener in sb2");
|
||||
|
||||
win.opener = null;
|
||||
is(win.opener, null, "Should be able to set the opener to null");
|
||||
is(evalsb("win.opener", sb1), null,
|
||||
|
@ -86,8 +86,10 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
// GC, so just paper over the necessary dataflow inversion.
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
if (mIsMainThread) {
|
||||
// Now get the global and JSContext for this callback.
|
||||
nsGlobalWindow* win = xpc::WindowGlobalOrNull(realCallback);
|
||||
// Now get the global and JSContext for this callback. Note that for the
|
||||
// case of JS-implemented WebIDL we never have a window here.
|
||||
nsGlobalWindow* win =
|
||||
aIsJSImplementedWebIDL ? nullptr : xpc::WindowGlobalOrNull(realCallback);
|
||||
if (win) {
|
||||
// Make sure that if this is a window it's the current inner, since the
|
||||
// nsIScriptContext and hence JSContext are associated with the outer
|
||||
@ -151,7 +153,9 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
mRootedCallable.construct(cx, aCallback->Callback());
|
||||
}
|
||||
|
||||
if (mIsMainThread) {
|
||||
// JS-implemented WebIDL is always OK to run, since it runs with Chrome
|
||||
// privileges anyway.
|
||||
if (mIsMainThread && !aIsJSImplementedWebIDL) {
|
||||
// Check that it's ok to run this callback at all.
|
||||
// Make sure to use realCallback to get the global of the callback object,
|
||||
// not the wrapper.
|
||||
@ -220,24 +224,24 @@ CallbackObject::CallSetup::~CallSetup()
|
||||
// Now, if we have a JSContext, report any pending errors on it, unless we
|
||||
// were told to re-throw them.
|
||||
if (mCx) {
|
||||
bool dealtWithPendingException = false;
|
||||
bool needToDealWithException = JS_IsExceptionPending(mCx);
|
||||
if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
|
||||
mExceptionHandling == eRethrowExceptions) {
|
||||
// Restore the old context options
|
||||
JS::ContextOptionsRef(mCx) = mSavedJSContextOptions;
|
||||
mErrorResult.MightThrowJSException();
|
||||
if (JS_IsExceptionPending(mCx)) {
|
||||
if (needToDealWithException) {
|
||||
JS::Rooted<JS::Value> exn(mCx);
|
||||
if (JS_GetPendingException(mCx, &exn) &&
|
||||
ShouldRethrowException(exn)) {
|
||||
mErrorResult.ThrowJSException(mCx, exn);
|
||||
JS_ClearPendingException(mCx);
|
||||
dealtWithPendingException = true;
|
||||
needToDealWithException = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dealtWithPendingException) {
|
||||
if (needToDealWithException) {
|
||||
// Either we're supposed to report our exceptions, or we're supposed to
|
||||
// re-throw them but we failed to JS_GetPendingException. Either way,
|
||||
// just report the pending exception, if any.
|
||||
|
@ -7483,7 +7483,8 @@ class CGMemberJITInfo(CGThing):
|
||||
return ""
|
||||
|
||||
def defineJitInfo(self, infoName, opName, opType, infallible, movable,
|
||||
aliasSet, hasSlot, slotIndex, returnTypes, args):
|
||||
aliasSet, alwaysInSlot, lazilyInSlot, slotIndex,
|
||||
returnTypes, args):
|
||||
"""
|
||||
aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
|
||||
|
||||
@ -7492,7 +7493,7 @@ class CGMemberJITInfo(CGThing):
|
||||
otherwise an iterable of the arguments for this method.
|
||||
"""
|
||||
assert(not movable or aliasSet != "AliasEverything") # Can't move write-aliasing things
|
||||
assert(not hasSlot or movable) # Things with slots had better be movable
|
||||
assert(not alwaysInSlot or movable) # Things always in slots had better be movable
|
||||
|
||||
def jitInfoInitializer(isTypedMethod):
|
||||
initializer = fill(
|
||||
@ -7506,7 +7507,8 @@ class CGMemberJITInfo(CGThing):
|
||||
${returnType}, /* returnType. Not relevant for setters. */
|
||||
${isInfallible}, /* isInfallible. False in setters. */
|
||||
${isMovable}, /* isMovable. Not relevant for setters. */
|
||||
${isInSlot}, /* isInSlot. Only relevant for getters. */
|
||||
${isAlwaysInSlot}, /* isAlwaysInSlot. Only relevant for getters. */
|
||||
${isLazilyCachedInSlot}, /* isLazilyCachedInSlot. Only relevant for getters. */
|
||||
${isTypedMethod}, /* isTypedMethod. Only relevant for methods. */
|
||||
${slotIndex} /* Reserved slot index, if we're stored in a slot, else 0. */
|
||||
}
|
||||
@ -7519,7 +7521,8 @@ class CGMemberJITInfo(CGThing):
|
||||
""),
|
||||
isInfallible=toStringBool(infallible),
|
||||
isMovable=toStringBool(movable),
|
||||
isInSlot=toStringBool(hasSlot),
|
||||
isAlwaysInSlot=toStringBool(alwaysInSlot),
|
||||
isLazilyCachedInSlot=toStringBool(lazilyInSlot),
|
||||
isTypedMethod=toStringBool(isTypedMethod),
|
||||
slotIndex=slotIndex)
|
||||
return initializer.rstrip()
|
||||
@ -7568,17 +7571,22 @@ class CGMemberJITInfo(CGThing):
|
||||
movable = getterpure and getterinfal
|
||||
|
||||
getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
|
||||
isInSlot = self.member.getExtendedAttribute("StoreInSlot")
|
||||
if isInSlot:
|
||||
isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
|
||||
if self.member.slotIndex is not None:
|
||||
assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
|
||||
isLazilyCachedInSlot = not isAlwaysInSlot
|
||||
slotIndex = memberReservedSlot(self.member)
|
||||
# We'll statically assert that this is not too big in
|
||||
# CGUpdateMemberSlotsMethod
|
||||
# CGUpdateMemberSlotsMethod, in the case when
|
||||
# isAlwaysInSlot is true.
|
||||
else:
|
||||
isLazilyCachedInSlot = False
|
||||
slotIndex = "0"
|
||||
|
||||
result = self.defineJitInfo(getterinfo, getter, "Getter",
|
||||
getterinfal, movable, aliasSet,
|
||||
isInSlot, slotIndex,
|
||||
isAlwaysInSlot, isLazilyCachedInSlot,
|
||||
slotIndex,
|
||||
[self.member.type], None)
|
||||
if (not self.member.readonly or
|
||||
self.member.getExtendedAttribute("PutForwards") is not None or
|
||||
@ -7590,7 +7598,7 @@ class CGMemberJITInfo(CGThing):
|
||||
# Setters are always fallible, since they have to do a typed unwrap.
|
||||
result += self.defineJitInfo(setterinfo, setter, "Setter",
|
||||
False, False, "AliasEverything",
|
||||
False, "0",
|
||||
False, False, "0",
|
||||
[BuiltinTypes[IDLBuiltinType.Types.void]],
|
||||
None)
|
||||
return result
|
||||
@ -7641,7 +7649,8 @@ class CGMemberJITInfo(CGThing):
|
||||
else:
|
||||
aliasSet = "AliasEverything"
|
||||
result = self.defineJitInfo(methodinfo, method, "Method",
|
||||
methodInfal, movable, aliasSet, False, "0",
|
||||
methodInfal, movable, aliasSet,
|
||||
False, False, "0",
|
||||
[s[0] for s in sigs], args)
|
||||
return result
|
||||
raise TypeError("Illegal member type to CGPropertyJITInfo")
|
||||
|
@ -1,2 +1,2 @@
|
||||
component {d193d0e2-c677-4a7b-bb0a-19155b470f2e} DataStoreService.js
|
||||
contract @mozilla.org/datastore-service;1 {d193d0e2-c677-4a7b-bb0a-19155b470f2e}
|
||||
component {db5c9602-030f-4bff-a3de-881a8de370f2} DataStoreImpl.js
|
||||
contract @mozilla.org/dom/datastore;1 {db5c9602-030f-4bff-a3de-881a8de370f2}
|
||||
|
48
dom/datastore/DataStoreCallbacks.h
Normal file
48
dom/datastore/DataStoreCallbacks.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_DataStoreCallbacks_h
|
||||
#define mozilla_dom_DataStoreCallbacks_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreDB;
|
||||
|
||||
class DataStoreDBCallback
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
virtual void Run(DataStoreDB* aDb, bool aSuccess) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DataStoreDBCallback()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DataStoreRevisionCallback
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
virtual void Run(const nsAString& aRevisionID) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DataStoreRevisionCallback()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_DataStoreCallbacks_h
|
@ -12,9 +12,6 @@ function debug(s) {
|
||||
//dump('DEBUG DataStoreChangeNotifier: ' + s + '\n');
|
||||
}
|
||||
|
||||
// DataStoreServiceInternal should not be converted into a lazy getter as it
|
||||
// runs code during initialization.
|
||||
Cu.import('resource://gre/modules/DataStoreServiceInternal.jsm');
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
319
dom/datastore/DataStoreDB.cpp
Normal file
319
dom/datastore/DataStoreDB.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DataStoreDB.h"
|
||||
|
||||
#include "DataStoreCallbacks.h"
|
||||
#include "mozilla/dom/IDBDatabaseBinding.h"
|
||||
#include "mozilla/dom/IDBFactoryBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBDatabase.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||
#include "mozilla/dom/indexedDB/IDBIndex.h"
|
||||
#include "mozilla/dom/indexedDB/IDBObjectStore.h"
|
||||
#include "mozilla/dom/indexedDB/IDBRequest.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
#define DATASTOREDB_VERSION 1
|
||||
#define DATASTOREDB_NAME "DataStoreDB"
|
||||
#define DATASTOREDB_REVISION_INDEX "revisionIndex"
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(DataStoreDB, nsIDOMEventListener)
|
||||
|
||||
DataStoreDB::DataStoreDB(const nsAString& aManifestURL, const nsAString& aName)
|
||||
: mState(Inactive)
|
||||
{
|
||||
mDatabaseName.Assign(aName);
|
||||
mDatabaseName.AppendASCII("|");
|
||||
mDatabaseName.Append(aManifestURL);
|
||||
}
|
||||
|
||||
DataStoreDB::~DataStoreDB()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::CreateFactoryIfNeeded()
|
||||
{
|
||||
if (!mFactory) {
|
||||
nsresult rv = IDBFactory::Create(nullptr, getter_AddRefs(mFactory));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::Open(IDBTransactionMode aMode, const Sequence<nsString>& aDbs,
|
||||
DataStoreDBCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(mState == Inactive);
|
||||
|
||||
nsresult rv = CreateFactoryIfNeeded();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
mRequest = mFactory->Open(mDatabaseName, DATASTOREDB_VERSION, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
rv = AddEventListeners();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mState = Active;
|
||||
mTransactionMode = aMode;
|
||||
mObjectStores = aDbs;
|
||||
mCallback = aCallback;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataStoreDB::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsString type;
|
||||
nsresult rv = aEvent->GetType(type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("success")) {
|
||||
RemoveEventListeners();
|
||||
mState = Inactive;
|
||||
|
||||
rv = DatabaseOpened();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mCallback->Run(this, false);
|
||||
} else {
|
||||
mCallback->Run(this, true);
|
||||
}
|
||||
|
||||
mRequest = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("upgradeneeded")) {
|
||||
return UpgradeSchema();
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("error") || type.EqualsASCII("blocked")) {
|
||||
RemoveEventListeners();
|
||||
mState = Inactive;
|
||||
mCallback->Run(this, false);
|
||||
mRequest = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("This should not happen");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::UpgradeSchema()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
ErrorResult error;
|
||||
JS::Rooted<JS::Value> result(cx, mRequest->GetResult(error));
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(result.isObject());
|
||||
|
||||
IDBDatabase* database = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), database);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Didn't get the object we expected!");
|
||||
return rv;
|
||||
}
|
||||
|
||||
{
|
||||
RootedDictionary<IDBObjectStoreParameters> params(cx);
|
||||
params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true }"));
|
||||
nsRefPtr<IDBObjectStore> store =
|
||||
database->CreateObjectStore(cx, NS_LITERAL_STRING(DATASTOREDB_NAME),
|
||||
params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<IDBObjectStore> store;
|
||||
|
||||
{
|
||||
RootedDictionary<IDBObjectStoreParameters> params(cx);
|
||||
params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true, \"keyPath\": \"internalRevisionId\" }"));
|
||||
|
||||
store =
|
||||
database->CreateObjectStore(cx, NS_LITERAL_STRING(DATASTOREDB_REVISION),
|
||||
params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
RootedDictionary<IDBIndexParameters> params(cx);
|
||||
params.Init(NS_LITERAL_STRING("{ \"unique\": true }"));
|
||||
nsRefPtr<IDBIndex> index =
|
||||
store->CreateIndex(cx, NS_LITERAL_STRING(DATASTOREDB_REVISION_INDEX),
|
||||
NS_LITERAL_STRING("revisionId"), params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::DatabaseOpened()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
ErrorResult error;
|
||||
JS::Rooted<JS::Value> result(cx, mRequest->GetResult(error));
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(result.isObject());
|
||||
|
||||
nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), mDatabase);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Didn't get the object we expected!");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBTransaction> txn = mDatabase->Transaction(mObjectStores,
|
||||
mTransactionMode,
|
||||
error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
mTransaction = txn.forget();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::Delete()
|
||||
{
|
||||
MOZ_ASSERT(mState == Inactive);
|
||||
|
||||
nsresult rv = CreateFactoryIfNeeded();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mTransaction = nullptr;
|
||||
|
||||
if (mDatabase) {
|
||||
rv = mDatabase->Close();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mDatabase = nullptr;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
nsRefPtr<IDBOpenDBRequest> request =
|
||||
mFactory->DeleteDatabase(mDatabaseName, IDBOpenDBOptions(), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
indexedDB::IDBTransaction*
|
||||
DataStoreDB::Transaction() const
|
||||
{
|
||||
MOZ_ASSERT(mTransaction);
|
||||
MOZ_ASSERT(mTransaction->IsOpen());
|
||||
return mTransaction;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::AddEventListeners()
|
||||
{
|
||||
nsresult rv;
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("upgradeneeded"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("error"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("blocked"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::RemoveEventListeners()
|
||||
{
|
||||
nsresult rv;
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("upgradeneeded"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("error"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("blocked"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
82
dom/datastore/DataStoreDB.h
Normal file
82
dom/datastore/DataStoreDB.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_DataStoreDB_h
|
||||
#define mozilla_dom_DataStoreDB_h
|
||||
|
||||
#include "mozilla/dom/IDBTransactionBinding.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#define DATASTOREDB_REVISION "revision"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace indexedDB {
|
||||
class IDBDatabase;
|
||||
class IDBFactory;
|
||||
class IDBObjectStore;
|
||||
class IDBOpenDBRequest;
|
||||
class IDBTransaction;
|
||||
}
|
||||
|
||||
class DataStoreDBCallback;
|
||||
|
||||
class DataStoreDB MOZ_FINAL : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
DataStoreDB(const nsAString& aManifestURL, const nsAString& aName);
|
||||
~DataStoreDB();
|
||||
|
||||
nsresult Open(IDBTransactionMode aMode, const Sequence<nsString>& aDb,
|
||||
DataStoreDBCallback* aCallback);
|
||||
|
||||
nsresult Delete();
|
||||
|
||||
indexedDB::IDBTransaction* Transaction() const;
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
private:
|
||||
nsresult CreateFactoryIfNeeded();
|
||||
|
||||
nsresult UpgradeSchema();
|
||||
|
||||
nsresult DatabaseOpened();
|
||||
|
||||
nsresult AddEventListeners();
|
||||
|
||||
nsresult RemoveEventListeners();
|
||||
|
||||
nsString mDatabaseName;
|
||||
|
||||
nsRefPtr<indexedDB::IDBFactory> mFactory;
|
||||
nsRefPtr<indexedDB::IDBOpenDBRequest> mRequest;
|
||||
nsRefPtr<indexedDB::IDBDatabase> mDatabase;
|
||||
nsRefPtr<indexedDB::IDBTransaction> mTransaction;
|
||||
|
||||
nsRefPtr<DataStoreDBCallback> mCallback;
|
||||
|
||||
// Internal state to avoid strange use of this class.
|
||||
enum StateType {
|
||||
Inactive,
|
||||
Active
|
||||
} mState;
|
||||
|
||||
IDBTransactionMode mTransactionMode;
|
||||
Sequence<nsString> mObjectStores;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreDB_h
|
@ -6,8 +6,6 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DataStore"];
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStore: ' + s + '\n');
|
||||
}
|
||||
@ -59,17 +57,16 @@ function validateId(aId) {
|
||||
}
|
||||
|
||||
/* DataStore object */
|
||||
this.DataStore = function(aWindow, aName, aOwner, aReadOnly) {
|
||||
function DataStore() {
|
||||
debug("DataStore created");
|
||||
this.init(aWindow, aName, aOwner, aReadOnly);
|
||||
}
|
||||
|
||||
this.DataStore.prototype = {
|
||||
DataStore.prototype = {
|
||||
classDescription: "DataStore XPCOM Component",
|
||||
classID: Components.ID("{db5c9602-030f-4bff-a3de-881a8de370f2}"),
|
||||
contractID: "@mozilla.org/dom/datastore-impl;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports,
|
||||
Components.interfaces.nsIObserver]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataStore, Ci.nsISupports,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
callbacks: [],
|
||||
|
||||
@ -536,3 +533,5 @@ this.DataStore.prototype = {
|
||||
return exposedCursor;
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataStore]);
|
102
dom/datastore/DataStoreRevision.cpp
Normal file
102
dom/datastore/DataStoreRevision.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DataStoreRevision.h"
|
||||
|
||||
#include "DataStoreCallbacks.h"
|
||||
#include "DataStoreService.h"
|
||||
#include "mozilla/dom/DataStoreBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBObjectStore.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace indexedDB;
|
||||
|
||||
NS_IMPL_ISUPPORTS(DataStoreRevision, nsIDOMEventListener)
|
||||
|
||||
// Note: this code in it must not assume anything about the compartment cx is
|
||||
// in.
|
||||
nsresult
|
||||
DataStoreRevision::AddRevision(JSContext* aCx,
|
||||
IDBObjectStore* aStore,
|
||||
uint32_t aObjectId,
|
||||
RevisionType aRevisionType,
|
||||
DataStoreRevisionCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aStore);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
nsRefPtr<DataStoreService> service = DataStoreService::Get();
|
||||
if (!service) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsString id;
|
||||
nsresult rv = service->GenerateUUID(mRevisionID);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DataStoreRevisionData data;
|
||||
data.mRevisionId = mRevisionID;
|
||||
data.mObjectId = aObjectId;
|
||||
|
||||
switch (aRevisionType) {
|
||||
case RevisionVoid:
|
||||
data.mOperation = NS_LITERAL_STRING("void");
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("This should not happen");
|
||||
break;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!data.ToObject(aCx, &value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
mRequest = aStore->Put(aCx, value, JS::UndefinedHandleValue, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mCallback = aCallback;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataStoreRevision::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsString type;
|
||||
nsresult rv = aEvent->GetType(type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!type.EqualsASCII("success")) {
|
||||
MOZ_ASSUME_UNREACHABLE("This should not happen");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mRequest->RemoveEventListener(NS_LITERAL_STRING("success"), this, false);
|
||||
mRequest = nullptr;
|
||||
|
||||
mCallback->Run(mRevisionID);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
52
dom/datastore/DataStoreRevision.h
Normal file
52
dom/datastore/DataStoreRevision.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_DataStoreRevision_h
|
||||
#define mozilla_dom_DataStoreRevision_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace indexedDB {
|
||||
class IDBObjectStore;
|
||||
class IDBRequest;
|
||||
}
|
||||
|
||||
class DataStoreRevisionCallback;
|
||||
|
||||
class DataStoreRevision MOZ_FINAL : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
enum RevisionType {
|
||||
RevisionVoid
|
||||
};
|
||||
|
||||
nsresult AddRevision(JSContext* aCx,
|
||||
indexedDB::IDBObjectStore* aStore,
|
||||
uint32_t aObjectId,
|
||||
RevisionType aRevisionType,
|
||||
DataStoreRevisionCallback* aCallback);
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
private:
|
||||
nsRefPtr<DataStoreRevisionCallback> mCallback;
|
||||
nsRefPtr<indexedDB::IDBRequest> mRequest;
|
||||
nsString mRevisionID;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreRevision_h
|
1352
dom/datastore/DataStoreService.cpp
Normal file
1352
dom/datastore/DataStoreService.cpp
Normal file
File diff suppressed because it is too large
Load Diff
110
dom/datastore/DataStoreService.h
Normal file
110
dom/datastore/DataStoreService.h
Normal file
@ -0,0 +1,110 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_DataStoreService_h
|
||||
#define mozilla_dom_DataStoreService_h
|
||||
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIDataStoreService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIUUIDGenerator;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreInfo;
|
||||
class FirstRevisionIdCallback;
|
||||
class PendingRequest;
|
||||
class Promise;
|
||||
class RetrieveRevisionsCounter;
|
||||
class RevisionAddedEnableStoreCallback;
|
||||
|
||||
class DataStoreService MOZ_FINAL : public nsIDataStoreService
|
||||
, public nsIObserver
|
||||
{
|
||||
friend class ContentChild;
|
||||
friend class FirstRevisionIdCallback;
|
||||
friend class RetrieveRevisionsCounter;
|
||||
friend class RevisionAddedEnableStoreCallback;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDATASTORESERVICE
|
||||
|
||||
// Returns the DataStoreService singleton. Only to be called from main
|
||||
// thread.
|
||||
static already_AddRefed<DataStoreService> GetOrCreate();
|
||||
|
||||
static already_AddRefed<DataStoreService> Get();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
nsresult GenerateUUID(nsAString& aID);
|
||||
|
||||
nsresult GetDataStoresFromIPC(const nsAString& aName,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreSetting>* aValue);
|
||||
|
||||
private:
|
||||
DataStoreService();
|
||||
~DataStoreService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
typedef nsClassHashtable<nsUint32HashKey, DataStoreInfo> HashApp;
|
||||
|
||||
nsresult AddPermissions(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aOriginURL,
|
||||
const nsAString& aManifestURL,
|
||||
bool aReadOnly);
|
||||
|
||||
nsresult AddAccessPermissions(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aOriginURL,
|
||||
const nsAString& aManifestURL,
|
||||
bool aReadOnly);
|
||||
|
||||
nsresult CreateFirstRevisionId(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aManifestURL);
|
||||
|
||||
void GetDataStoresCreate(nsPIDOMWindow* aWindow, Promise* aPromise,
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void GetDataStoresResolve(nsPIDOMWindow* aWindow, Promise* aPromise,
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
nsresult GetDataStoreInfos(const nsAString& aName, uint32_t aAppId,
|
||||
nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void DeleteDataStores(uint32_t aAppId);
|
||||
|
||||
nsresult EnableDataStore(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aManifestURL);
|
||||
|
||||
already_AddRefed<RetrieveRevisionsCounter> GetCounter(uint32_t aId) const;
|
||||
|
||||
void RemoveCounter(uint32_t aId);
|
||||
|
||||
nsClassHashtable<nsStringHashKey, HashApp> mStores;
|
||||
nsClassHashtable<nsStringHashKey, HashApp> mAccessStores;
|
||||
|
||||
typedef nsTArray<PendingRequest> PendingRequests;
|
||||
nsClassHashtable<nsStringHashKey, PendingRequests> mPendingRequests;
|
||||
|
||||
nsRefPtrHashtable<nsUint32HashKey, RetrieveRevisionsCounter> mPendingCounters;
|
||||
|
||||
nsCOMPtr<nsIUUIDGenerator> mUUIDGenerator;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreService_h
|
@ -1,522 +0,0 @@
|
||||
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict'
|
||||
|
||||
/* static functions */
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStoreService: ' + s + '\n');
|
||||
}
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/DataStoreImpl.jsm');
|
||||
Cu.import("resource://gre/modules/DataStoreDB.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "permissionManager",
|
||||
"@mozilla.org/permissionmanager;1",
|
||||
"nsIPermissionManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "secMan",
|
||||
"@mozilla.org/scriptsecuritymanager;1",
|
||||
"nsIScriptSecurityManager");
|
||||
|
||||
/* DataStoreService */
|
||||
|
||||
const DATASTORESERVICE_CID = Components.ID('{d193d0e2-c677-4a7b-bb0a-19155b470f2e}');
|
||||
const REVISION_VOID = "void";
|
||||
|
||||
function DataStoreService() {
|
||||
debug('DataStoreService Constructor');
|
||||
|
||||
this.inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
if (this.inParent) {
|
||||
let obs = Services.obs;
|
||||
if (!obs) {
|
||||
debug("DataStore Error: observer-service is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
obs.addObserver(this, 'webapps-clear-data', false);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
cpmm.addMessageListener("datastore-first-revision-created",
|
||||
function(aMsg) { self.receiveMessage(aMsg); });
|
||||
}
|
||||
|
||||
DataStoreService.prototype = {
|
||||
inParent: false,
|
||||
|
||||
// Hash of DataStores
|
||||
stores: {},
|
||||
accessStores: {},
|
||||
pendingRequests: {},
|
||||
|
||||
installDataStore: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
debug('installDataStore - appId: ' + aAppId + ', aName: ' +
|
||||
aName + ', aOrigin: ' + aOrigin + ', aOwner:' + aOwner +
|
||||
', aReadOnly: ' + aReadOnly);
|
||||
|
||||
this.checkIfInParent();
|
||||
|
||||
if (aName in this.stores && aAppId in this.stores[aName]) {
|
||||
debug('This should not happen');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aName in this.stores)) {
|
||||
this.stores[aName] = {};
|
||||
}
|
||||
|
||||
// A DataStore is enabled when it has a first valid revision.
|
||||
this.stores[aName][aAppId] = { origin: aOrigin, owner: aOwner,
|
||||
readOnly: aReadOnly, enabled: false };
|
||||
|
||||
this.addPermissions(aAppId, aName, aOrigin, aOwner, aReadOnly);
|
||||
|
||||
this.createFirstRevisionId(aAppId, aName, aOwner);
|
||||
},
|
||||
|
||||
installAccessDataStore: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
debug('installAccessDataStore - appId: ' + aAppId + ', aName: ' +
|
||||
aName + ', aOrigin: ' + aOrigin + ', aOwner:' + aOwner +
|
||||
', aReadOnly: ' + aReadOnly);
|
||||
|
||||
this.checkIfInParent();
|
||||
|
||||
if (aName in this.accessStores && aAppId in this.accessStores[aName]) {
|
||||
debug('This should not happen');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aName in this.accessStores)) {
|
||||
this.accessStores[aName] = {};
|
||||
}
|
||||
|
||||
this.accessStores[aName][aAppId] = { origin: aOrigin, owner: aOwner,
|
||||
readOnly: aReadOnly };
|
||||
this.addAccessPermissions(aAppId, aName, aOrigin, aOwner, aReadOnly);
|
||||
},
|
||||
|
||||
checkIfInParent: function() {
|
||||
if (!this.inParent) {
|
||||
throw "DataStore can execute this operation just in the parent process";
|
||||
}
|
||||
},
|
||||
|
||||
createFirstRevisionId: function(aAppId, aName, aOwner) {
|
||||
debug("createFirstRevisionId database: " + aName);
|
||||
|
||||
let self = this;
|
||||
let db = new DataStoreDB();
|
||||
db.init(aOwner, aName);
|
||||
db.revisionTxn(
|
||||
'readwrite',
|
||||
function(aTxn, aRevisionStore) {
|
||||
debug("createFirstRevisionId - transaction success");
|
||||
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
if (cursor) {
|
||||
debug("First revision already created.");
|
||||
self.enableDataStore(aAppId, aName, aOwner);
|
||||
} else {
|
||||
// If the revision doesn't exist, let's create the first one.
|
||||
db.addRevision(aRevisionStore, 0, REVISION_VOID, function() {
|
||||
debug("First revision created.");
|
||||
self.enableDataStore(aAppId, aName, aOwner);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
enableDataStore: function(aAppId, aName, aOwner) {
|
||||
if (aName in this.stores && aAppId in this.stores[aName]) {
|
||||
this.stores[aName][aAppId].enabled = true;
|
||||
ppmm.broadcastAsyncMessage('datastore-first-revision-created',
|
||||
{ name: aName, owner: aOwner });
|
||||
}
|
||||
},
|
||||
|
||||
addPermissions: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
// When a new DataStore is installed, the permissions must be set for the
|
||||
// owner app.
|
||||
let permission = "indexedDB-chrome-" + aName + '|' + aOwner;
|
||||
this.resetPermissions(aAppId, aOrigin, aOwner, permission, aReadOnly);
|
||||
|
||||
// For any app that wants to have access to this DataStore we add the
|
||||
// permissions.
|
||||
if (aName in this.accessStores) {
|
||||
for (let appId in this.accessStores[aName]) {
|
||||
// ReadOnly is decided by the owner first.
|
||||
let readOnly = aReadOnly || this.accessStores[aName][appId].readOnly;
|
||||
this.resetPermissions(appId, this.accessStores[aName][appId].origin,
|
||||
this.accessStores[aName][appId].owner,
|
||||
permission, readOnly);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
addAccessPermissions: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
// When an app wants to have access to a DataStore, the permissions must be
|
||||
// set.
|
||||
if (!(aName in this.stores)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let appId in this.stores[aName]) {
|
||||
let permission = "indexedDB-chrome-" + aName + '|' + this.stores[aName][appId].owner;
|
||||
// The ReadOnly is decied by the owenr first.
|
||||
let readOnly = this.stores[aName][appId].readOnly || aReadOnly;
|
||||
this.resetPermissions(aAppId, aOrigin, aOwner, permission, readOnly);
|
||||
}
|
||||
},
|
||||
|
||||
resetPermissions: function(aAppId, aOrigin, aOwner, aPermission, aReadOnly) {
|
||||
debug("ResetPermissions - appId: " + aAppId + " - origin: " + aOrigin +
|
||||
" - owner: " + aOwner + " - permissions: " + aPermission +
|
||||
" - readOnly: " + aReadOnly);
|
||||
|
||||
let uri = Services.io.newURI(aOrigin, null, null);
|
||||
let principal = secMan.getAppCodebasePrincipal(uri, aAppId, false);
|
||||
|
||||
let result = permissionManager.testExactPermissionFromPrincipal(principal,
|
||||
aPermission + '-write');
|
||||
|
||||
if (aReadOnly && result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Write permission removed");
|
||||
permissionManager.removeFromPrincipal(principal, aPermission + '-write');
|
||||
} else if (!aReadOnly && result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Write permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission + '-write',
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
result = permissionManager.testExactPermissionFromPrincipal(principal,
|
||||
aPermission + '-read');
|
||||
if (result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Read permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission + '-read',
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
|
||||
if (result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Generic permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission,
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
},
|
||||
|
||||
getDataStores: function(aWindow, aName) {
|
||||
debug('getDataStores - aName: ' + aName);
|
||||
|
||||
let self = this;
|
||||
return new aWindow.Promise(function(resolve, reject) {
|
||||
// If this request comes from the main process, we have access to the
|
||||
// window, so we can skip the ipc communication.
|
||||
if (self.inParent) {
|
||||
let stores = self.getDataStoresInfo(aName, aWindow.document.nodePrincipal.appId);
|
||||
if (stores === null) {
|
||||
reject(new aWindow.DOMError("SecurityError", "Access denied"));
|
||||
return;
|
||||
}
|
||||
self.getDataStoreCreate(aWindow, resolve, stores);
|
||||
} else {
|
||||
// This method can be called in the child so we need to send a request
|
||||
// to the parent and create DataStore object here.
|
||||
new DataStoreServiceChild(aWindow, aName, function(aStores) {
|
||||
debug("DataStoreServiceChild success callback!");
|
||||
self.getDataStoreCreate(aWindow, resolve, aStores);
|
||||
}, function() {
|
||||
debug("DataStoreServiceChild error callback!");
|
||||
reject(new aWindow.DOMError("SecurityError", "Access denied"));
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getDataStoresInfo: function(aName, aAppId) {
|
||||
debug('GetDataStoresInfo');
|
||||
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
let app = appsService.getAppByLocalId(aAppId);
|
||||
if (!app) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let prefName = "dom.testing.datastore_enabled_for_hosted_apps";
|
||||
if (app.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED &&
|
||||
(Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
|
||||
!Services.prefs.getBoolPref(prefName))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let results = [];
|
||||
|
||||
if (aName in this.stores) {
|
||||
if (aAppId in this.stores[aName]) {
|
||||
results.push({ name: aName,
|
||||
owner: this.stores[aName][aAppId].owner,
|
||||
readOnly: false,
|
||||
enabled: this.stores[aName][aAppId].enabled });
|
||||
}
|
||||
|
||||
for (var i in this.stores[aName]) {
|
||||
if (i == aAppId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let access = this.getDataStoreAccess(aName, aAppId);
|
||||
if (!access) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let readOnly = this.stores[aName][i].readOnly || access.readOnly;
|
||||
results.push({ name: aName,
|
||||
owner: this.stores[aName][i].owner,
|
||||
readOnly: readOnly,
|
||||
enabled: this.stores[aName][i].enabled });
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
getDataStoreCreate: function(aWindow, aResolve, aStores) {
|
||||
debug("GetDataStoreCreate");
|
||||
|
||||
let results = new aWindow.Array();
|
||||
|
||||
if (!aStores.length) {
|
||||
aResolve(results);
|
||||
return;
|
||||
}
|
||||
|
||||
let pendingDataStores = [];
|
||||
|
||||
for (let i = 0; i < aStores.length; ++i) {
|
||||
if (!aStores[i].enabled) {
|
||||
pendingDataStores.push(aStores[i].owner);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pendingDataStores.length) {
|
||||
this.getDataStoreResolve(aWindow, aResolve, aStores);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aStores[0].name in this.pendingRequests)) {
|
||||
this.pendingRequests[aStores[0].name] = [];
|
||||
}
|
||||
|
||||
this.pendingRequests[aStores[0].name].push({ window: aWindow,
|
||||
resolve: aResolve,
|
||||
stores: aStores,
|
||||
pendingDataStores: pendingDataStores });
|
||||
},
|
||||
|
||||
getDataStoreResolve: function(aWindow, aResolve, aStores) {
|
||||
debug("GetDataStoreResolve");
|
||||
|
||||
let callbackPending = aStores.length;
|
||||
let results = new aWindow.Array();
|
||||
|
||||
if (!callbackPending) {
|
||||
aResolve(results);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < aStores.length; ++i) {
|
||||
let obj = new DataStore(aWindow, aStores[i].name,
|
||||
aStores[i].owner, aStores[i].readOnly);
|
||||
|
||||
let storeImpl = aWindow.DataStoreImpl._create(aWindow, obj);
|
||||
|
||||
let exposedStore = new aWindow.DataStore();
|
||||
exposedStore.setDataStoreImpl(storeImpl);
|
||||
|
||||
obj.exposedObject = exposedStore;
|
||||
|
||||
results.push(exposedStore);
|
||||
|
||||
obj.retrieveRevisionId(
|
||||
function() {
|
||||
--callbackPending;
|
||||
if (!callbackPending) {
|
||||
aResolve(results);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
getDataStoreAccess: function(aName, aAppId) {
|
||||
if (!(aName in this.accessStores) ||
|
||||
!(aAppId in this.accessStores[aName])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.accessStores[aName][aAppId];
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
debug('observe - aTopic: ' + aTopic);
|
||||
if (aTopic != 'webapps-clear-data') {
|
||||
return;
|
||||
}
|
||||
|
||||
let params =
|
||||
aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
|
||||
|
||||
// DataStore is explosed to apps, not browser content.
|
||||
if (params.browserOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
function isEmpty(aMap) {
|
||||
for (var key in aMap) {
|
||||
if (aMap.hasOwnProperty(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let key in this.stores) {
|
||||
if (params.appId in this.stores[key]) {
|
||||
this.deleteDatabase(key, this.stores[key][params.appId].owner);
|
||||
delete this.stores[key][params.appId];
|
||||
}
|
||||
|
||||
if (isEmpty(this.stores[key])) {
|
||||
delete this.stores[key];
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in this.accessStores) {
|
||||
if (params.appId in this.accessStores[key]) {
|
||||
delete this.accessStores[key][params.appId];
|
||||
}
|
||||
|
||||
if (isEmpty(this.accessStores[key])) {
|
||||
delete this.accessStores[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
deleteDatabase: function(aName, aOwner) {
|
||||
debug("delete database: " + aName);
|
||||
|
||||
let db = new DataStoreDB();
|
||||
db.init(aOwner, aName);
|
||||
db.delete();
|
||||
},
|
||||
|
||||
receiveMessage: function(aMsg) {
|
||||
debug("receiveMessage");
|
||||
let data = aMsg.json;
|
||||
|
||||
if (!(data.name in this.pendingRequests)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.pendingRequests[data.name].length;) {
|
||||
let pos = this.pendingRequests[data.name][i].pendingDataStores.indexOf(data.owner);
|
||||
if (pos != -1) {
|
||||
this.pendingRequests[data.name][i].pendingDataStores.splice(pos, 1);
|
||||
if (!this.pendingRequests[data.name][i].pendingDataStores.length) {
|
||||
this.getDataStoreResolve(this.pendingRequests[data.name][i].window,
|
||||
this.pendingRequests[data.name][i].resolve,
|
||||
this.pendingRequests[data.name][i].stores);
|
||||
this.pendingRequests[data.name].splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (!this.pendingRequests[data.name].length) {
|
||||
delete this.pendingRequests[data.name];
|
||||
}
|
||||
},
|
||||
|
||||
classID : DATASTORESERVICE_CID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataStoreService,
|
||||
Ci.nsIObserver]),
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: DATASTORESERVICE_CID,
|
||||
contractID: '@mozilla.org/datastore-service;1',
|
||||
interfaces: [Ci.nsIDataStoreService, Ci.nsIObserver],
|
||||
flags: Ci.nsIClassInfo.SINGLETON
|
||||
})
|
||||
};
|
||||
|
||||
/* DataStoreServiceChild */
|
||||
|
||||
function DataStoreServiceChild(aWindow, aName, aSuccessCb, aErrorCb) {
|
||||
debug("DataStoreServiceChild created");
|
||||
this.init(aWindow, aName, aSuccessCb, aErrorCb);
|
||||
}
|
||||
|
||||
DataStoreServiceChild.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
init: function(aWindow, aName, aSuccessCb, aErrorCb) {
|
||||
debug("DataStoreServiceChild init");
|
||||
this._successCb = aSuccessCb;
|
||||
this._errorCb = aErrorCb;
|
||||
this._name = aName;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return:OK",
|
||||
"DataStore:Get:Return:KO" ]);
|
||||
|
||||
cpmm.sendAsyncMessage("DataStore:Get",
|
||||
{ name: aName }, null, aWindow.document.nodePrincipal );
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("DataStoreServiceChild receiveMessage");
|
||||
|
||||
if (aMessage.data.name != this._name) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case 'DataStore:Get:Return:OK':
|
||||
this.destroyDOMRequestHelper();
|
||||
this._successCb(aMessage.data.stores);
|
||||
break;
|
||||
|
||||
case 'DataStore:Get:Return:KO':
|
||||
this.destroyDOMRequestHelper();
|
||||
this._errorCb();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataStoreService]);
|
@ -1,68 +0,0 @@
|
||||
/* 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"
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DataStoreServiceInternal"];
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStoreServiceInternal: ' + s + '\n');
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
|
||||
"@mozilla.org/datastore-service;1",
|
||||
"nsIDataStoreService");
|
||||
|
||||
this.DataStoreServiceInternal = {
|
||||
init: function() {
|
||||
debug("init");
|
||||
|
||||
let inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
if (inParent) {
|
||||
ppmm.addMessageListener("DataStore:Get", this);
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage");
|
||||
|
||||
if (aMessage.name != 'DataStore:Get') {
|
||||
return;
|
||||
}
|
||||
|
||||
let prefName = 'dom.testing.datastore_enabled_for_hosted_apps';
|
||||
if ((Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
|
||||
!Services.prefs.getBoolPref(prefName)) &&
|
||||
!aMessage.target.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = aMessage.data;
|
||||
|
||||
if (!aMessage.principal ||
|
||||
aMessage.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
|
||||
aMessage.target.sendAsyncMessage("DataStore:Get:Return:KO");
|
||||
return;
|
||||
}
|
||||
|
||||
msg.stores = dataStoreService.getDataStoresInfo(msg.name, aMessage.principal.appId);
|
||||
if (msg.stores === null) {
|
||||
aMessage.target.sendAsyncMessage("DataStore:Get:Return:KO");
|
||||
return;
|
||||
}
|
||||
aMessage.target.sendAsyncMessage("DataStore:Get:Return:OK", msg);
|
||||
}
|
||||
}
|
||||
|
||||
DataStoreServiceInternal.init();
|
@ -5,6 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDataStore.idl',
|
||||
'nsIDataStoreService.idl',
|
||||
]
|
||||
|
||||
@ -13,11 +14,15 @@ XPIDL_MODULE = 'dom_datastore'
|
||||
EXPORTS.mozilla.dom += [
|
||||
'DataStore.h',
|
||||
'DataStoreCursor.h',
|
||||
'DataStoreService.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'DataStore.cpp',
|
||||
'DataStoreCursor.cpp',
|
||||
'DataStoreDB.cpp',
|
||||
'DataStoreRevision.cpp',
|
||||
'DataStoreService.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
@ -26,17 +31,18 @@ LOCAL_INCLUDES += [
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'DataStore.manifest',
|
||||
'DataStoreService.js',
|
||||
'DataStoreImpl.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DataStoreChangeNotifier.jsm',
|
||||
'DataStoreCursorImpl.jsm',
|
||||
'DataStoreDB.jsm',
|
||||
'DataStoreImpl.jsm',
|
||||
'DataStoreServiceInternal.jsm',
|
||||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
23
dom/datastore/nsIDataStore.idl
Normal file
23
dom/datastore/nsIDataStore.idl
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMWindow;
|
||||
|
||||
// NOTE: This is a temporary interface.
|
||||
// It will be removed in the next patches for rewriting DataStore in C++.
|
||||
[scriptable, uuid(0b41fef5-14ba-48b0-923c-3d8fb64692ae)]
|
||||
interface nsIDataStore : nsISupports
|
||||
{
|
||||
void init(in nsIDOMWindow window,
|
||||
in DOMString name,
|
||||
in DOMString manifestURL,
|
||||
in boolean readOnly);
|
||||
|
||||
attribute jsval exposedObject;
|
||||
|
||||
void retrieveRevisionId(in jsval cb);
|
||||
};
|
@ -7,7 +7,7 @@
|
||||
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(bd02d09c-41ab-47b7-9319-57aa8e5059b0)]
|
||||
[scriptable, uuid(0a050c4f-d292-4a14-8712-09bc1019840a)]
|
||||
interface nsIDataStoreService : nsISupports
|
||||
{
|
||||
void installDataStore(in unsigned long appId,
|
||||
@ -24,12 +24,4 @@ interface nsIDataStoreService : nsISupports
|
||||
|
||||
nsISupports getDataStores(in nsIDOMWindow window,
|
||||
in DOMString name);
|
||||
|
||||
// This is an array of objects composed by:
|
||||
// - readOnly: boolean
|
||||
// - name: DOMString
|
||||
// - owner: DOMString
|
||||
// - enabled: true/false - true if this dataStore is ready to be used.
|
||||
jsval getDataStoresInfo(in DOMString name,
|
||||
in unsigned long appId);
|
||||
};
|
||||
|
34
dom/datastore/tests/file_bug957086.html
Normal file
34
dom/datastore/tests/file_bug957086.html
Normal file
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - bug 1008044</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a == b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is (stores.length, 1, "Correct number of Stores");
|
||||
is (stores[0].name, 'foo', "Correct name is received!");
|
||||
stores[0].get(42).then(function(something) {
|
||||
is (something, null, "Correct value");
|
||||
finish();
|
||||
}, cbError);
|
||||
}, cbError);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -29,6 +29,7 @@ support-files =
|
||||
file_basic_common.js
|
||||
file_sync_common.js
|
||||
file_bug1008044.html
|
||||
file_bug957086.html
|
||||
|
||||
[test_app_install.html]
|
||||
[test_readonly.html]
|
||||
@ -54,3 +55,4 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure; time out
|
||||
[test_oop_events.html]
|
||||
[test_transactions.html]
|
||||
[test_bug1008044.html]
|
||||
[test_bug957086.html]
|
||||
|
135
dom/datastore/tests/test_bug957086.html
Normal file
135
dom/datastore/tests/test_bug957086.html
Normal file
@ -0,0 +1,135 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - bug 957086</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gHostedManifestURL1 = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_bug957086.html&template=file_app2.template.webapp';
|
||||
var gHostedManifestURL2 = 'http://example.com/tests/dom/datastore/tests/file_app.sjs?testToken=file_bug957086.html';
|
||||
var gApps = [];
|
||||
|
||||
function cbError() {
|
||||
ok(false, "Error callback invoked");
|
||||
finish();
|
||||
}
|
||||
|
||||
function installApp(manifest) {
|
||||
var request = navigator.mozApps.install(manifest);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = function() {
|
||||
gApps.push(request.result);
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
function uninstallApp() {
|
||||
if (!gApps.length) {
|
||||
// All done.
|
||||
info("All done");
|
||||
runTest();
|
||||
return;
|
||||
}
|
||||
|
||||
// Uninstall the app.
|
||||
var request = navigator.mozApps.mgmt.uninstall(gApps.pop());
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = uninstallApp;
|
||||
}
|
||||
|
||||
function testApp() {
|
||||
var ifr = document.createElement('iframe');
|
||||
ifr.setAttribute('mozbrowser', 'true');
|
||||
ifr.setAttribute('mozapp', gApps[0].manifestURL);
|
||||
ifr.setAttribute('src', gApps[0].manifest.launch_path);
|
||||
var domParent = document.getElementById('container');
|
||||
|
||||
// Set us up to listen for messages from the app.
|
||||
var listener = function(e) {
|
||||
var message = e.detail.message;
|
||||
if (/^OK/.exec(message)) {
|
||||
ok(true, "Message from app: " + message);
|
||||
} else if (/KO/.exec(message)) {
|
||||
ok(false, "Message from app: " + message);
|
||||
} else if (/DONE/.exec(message)) {
|
||||
ok(true, "Messaging from app complete");
|
||||
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
|
||||
domParent.removeChild(ifr);
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
// This event is triggered when the app calls "alert".
|
||||
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
|
||||
domParent.appendChild(ifr);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Permissions
|
||||
function() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "browser", "allow": 1, "context": document },
|
||||
{ "type": "embed-apps", "allow": 1, "context": document },
|
||||
{ "type": "webapps-manage", "allow": 1, "context": document }], runTest);
|
||||
},
|
||||
|
||||
// Preferences
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.testing.ignore_ipc_principal", true],
|
||||
["dom.testing.datastore_enabled_for_hosted_apps", true]]}, runTest);
|
||||
},
|
||||
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
runTest();
|
||||
},
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
},
|
||||
|
||||
// Installing the app - access only
|
||||
function() { installApp(gHostedManifestURL1) },
|
||||
|
||||
// Installing the app - owner only
|
||||
function() { installApp(gHostedManifestURL2) },
|
||||
|
||||
// Run tests in app
|
||||
testApp,
|
||||
|
||||
// Uninstall the app
|
||||
uninstallApp
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -235,9 +235,6 @@ IDBFactory::Create(ContentParent* aContentParent,
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
|
||||
NS_ASSERTION(aContentParent, "Null ContentParent!");
|
||||
|
||||
NS_ASSERTION(!nsContentUtils::GetCurrentJSContext(), "Should be called from C++");
|
||||
|
||||
// We need to get this information before we push a null principal to avoid
|
||||
// IsCallerChrome() assertion in quota manager.
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
IDBFactory** aFactory);
|
||||
|
||||
// Called when using IndexedDB from a JS component or a JSM in a different
|
||||
// process.
|
||||
// process or from a C++ component.
|
||||
static nsresult Create(ContentParent* aContentParent,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
|
@ -327,7 +327,7 @@ IDBRequest::WrapObject(JSContext* aCx)
|
||||
}
|
||||
|
||||
JS::Value
|
||||
IDBRequest::GetResult(JSContext* aCx, mozilla::ErrorResult& aRv) const
|
||||
IDBRequest::GetResult(mozilla::ErrorResult& aRv) const
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
|
@ -132,7 +132,13 @@ public:
|
||||
}
|
||||
|
||||
JS::Value
|
||||
GetResult(JSContext* aCx, ErrorResult& aRv) const;
|
||||
GetResult(ErrorResult& aRv) const;
|
||||
|
||||
JS::Value
|
||||
GetResult(JSContext* aCx, ErrorResult& aRv) const
|
||||
{
|
||||
return GetResult(aRv);
|
||||
}
|
||||
|
||||
IDBTransaction*
|
||||
GetTransaction() const
|
||||
|
@ -24,7 +24,7 @@ interface nsIVariant;
|
||||
* @see <http://www.whatwg.org/html/#window>
|
||||
*/
|
||||
|
||||
[scriptable, uuid(fbefa573-0ba2-4d15-befb-d60277643a0b)]
|
||||
[scriptable, uuid(d4316591-d16e-405c-8093-b441cbef3230)]
|
||||
interface nsIDOMWindow : nsISupports
|
||||
{
|
||||
// the current browsing context
|
||||
@ -151,7 +151,11 @@ interface nsIDOMWindow : nsISupports
|
||||
}
|
||||
%}
|
||||
|
||||
attribute nsIDOMWindow opener;
|
||||
[implicit_jscontext, binaryname(ScriptableOpener)]
|
||||
attribute jsval opener;
|
||||
|
||||
[noscript, binaryname(Opener)]
|
||||
attribute nsIDOMWindow openerWindow;
|
||||
|
||||
/**
|
||||
* |frameElement| gets this window's <iframe> or <frame> element, if it has
|
||||
|
@ -142,6 +142,7 @@
|
||||
#include "nsDeviceStorage.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "JavaScriptChild.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
#include "mozilla/dom/telephony/PTelephonyChild.h"
|
||||
#include "mozilla/dom/time/DateCacheCleaner.h"
|
||||
#include "mozilla/net/NeckoMessageUtils.h"
|
||||
@ -768,6 +769,24 @@ ContentChild::RecvAudioChannelNotify()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvDataStoreNotify(const uint32_t& aAppId,
|
||||
const nsString& aName,
|
||||
const nsString& aManifestURL)
|
||||
{
|
||||
nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = service->EnableDataStore(aAppId, aName, aManifestURL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor)
|
||||
{
|
||||
|
@ -157,6 +157,10 @@ public:
|
||||
virtual bool
|
||||
RecvAudioChannelNotify() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvDataStoreNotify(const uint32_t& aAppId, const nsString& aName,
|
||||
const nsString& aManifestURL) MOZ_OVERRIDE;
|
||||
|
||||
virtual PTestShellChild* AllocPTestShellChild() MOZ_OVERRIDE;
|
||||
virtual bool DeallocPTestShellChild(PTestShellChild*) MOZ_OVERRIDE;
|
||||
virtual bool RecvPTestShellConstructor(PTestShellChild*) MOZ_OVERRIDE;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/dom/asmjscache/AsmJSCache.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
#include "mozilla/dom/ExternalHelperAppParent.h"
|
||||
#include "mozilla/dom/PFileDescriptorSetParent.h"
|
||||
#include "mozilla/dom/PCycleCollectWithLogsParent.h"
|
||||
@ -1504,6 +1505,7 @@ ContentParent::InitializeMembers()
|
||||
mNumDestroyingTabs = 0;
|
||||
mIsAlive = true;
|
||||
mSendPermissionUpdates = false;
|
||||
mSendDataStoreInfos = false;
|
||||
mCalledClose = false;
|
||||
mCalledCloseWithError = false;
|
||||
mCalledKillHard = false;
|
||||
@ -2085,6 +2087,26 @@ ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvDataStoreGetStores(
|
||||
const nsString& aName,
|
||||
const IPC::Principal& aPrincipal,
|
||||
InfallibleTArray<DataStoreSetting>* aValue)
|
||||
{
|
||||
nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = service->GetDataStoresFromIPC(aName, aPrincipal, aValue);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mSendDataStoreInfos = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvBroadcastVolume(const nsString& aVolumeName)
|
||||
{
|
||||
|
@ -162,10 +162,14 @@ public:
|
||||
|
||||
int32_t Pid();
|
||||
|
||||
bool NeedsPermissionsUpdate() {
|
||||
bool NeedsPermissionsUpdate() const {
|
||||
return mSendPermissionUpdates;
|
||||
}
|
||||
|
||||
bool NeedsDataStoreInfos() const {
|
||||
return mSendDataStoreInfos;
|
||||
}
|
||||
|
||||
BlobParent* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
|
||||
|
||||
/**
|
||||
@ -532,6 +536,11 @@ private:
|
||||
virtual bool RecvGetSystemMemory(const uint64_t& getterId) MOZ_OVERRIDE;
|
||||
virtual bool RecvBroadcastVolume(const nsString& aVolumeName) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvDataStoreGetStores(
|
||||
const nsString& aName,
|
||||
const IPC::Principal& aPrincipal,
|
||||
InfallibleTArray<DataStoreSetting>* aValue) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable) MOZ_OVERRIDE;
|
||||
@ -606,6 +615,7 @@ private:
|
||||
bool mIsAlive;
|
||||
|
||||
bool mSendPermissionUpdates;
|
||||
bool mSendDataStoreInfos;
|
||||
bool mIsForBrowser;
|
||||
bool mIsNuwaProcess;
|
||||
|
||||
|
@ -262,6 +262,14 @@ struct PrefSetting {
|
||||
MaybePrefValue userValue;
|
||||
};
|
||||
|
||||
struct DataStoreSetting {
|
||||
nsString name;
|
||||
nsString originURL;
|
||||
nsString manifestURL;
|
||||
bool readOnly;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
intr protocol PContent
|
||||
{
|
||||
parent opens PCompositor;
|
||||
@ -338,6 +346,9 @@ child:
|
||||
|
||||
async SpeakerManagerNotify();
|
||||
|
||||
async DataStoreNotify(uint32_t aAppId, nsString aName,
|
||||
nsString aManifestURL);
|
||||
|
||||
/**
|
||||
* Dump this process's GC and CC logs to the provided files.
|
||||
*
|
||||
@ -550,6 +561,9 @@ parent:
|
||||
async AudioChannelChangedNotification();
|
||||
async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden);
|
||||
|
||||
sync DataStoreGetStores(nsString aName, Principal aPrincipal)
|
||||
returns (DataStoreSetting[] dataStores);
|
||||
|
||||
async FilePathUpdateNotify(nsString aType,
|
||||
nsString aStorageName,
|
||||
nsString aFilepath,
|
||||
|
@ -108,3 +108,10 @@ dictionary DataStoreTask {
|
||||
DataStoreKey? id;
|
||||
any data;
|
||||
};
|
||||
|
||||
// For internal use.
|
||||
dictionary DataStoreRevisionData {
|
||||
DOMString revisionId = "";
|
||||
unsigned long objectId = 0;
|
||||
DOMString operation = "";
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ typedef any Transferable;
|
||||
[Replaceable, CrossOriginReadable] readonly attribute unsigned long length;
|
||||
//[Unforgeable, Throws, CrossOriginReadable] readonly attribute WindowProxy top;
|
||||
[Unforgeable, Throws, CrossOriginReadable] readonly attribute WindowProxy? top;
|
||||
[Throws, CrossOriginReadable] attribute WindowProxy? opener;
|
||||
[Throws, CrossOriginReadable] attribute any opener;
|
||||
//[Throws] readonly attribute WindowProxy parent;
|
||||
[Replaceable, Throws, CrossOriginReadable] readonly attribute WindowProxy? parent;
|
||||
[Throws] readonly attribute Element? frameElement;
|
||||
|
@ -141,54 +141,11 @@ gfxUtils::UnpremultiplyDataSurface(DataSourceSurface* aSurface)
|
||||
return dest;
|
||||
}
|
||||
|
||||
void
|
||||
gfxUtils::ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
|
||||
gfxImageSurface *aDestSurface) {
|
||||
if (!aDestSurface)
|
||||
aDestSurface = aSourceSurface;
|
||||
|
||||
MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
|
||||
aSourceSurface->Width() == aDestSurface->Width() &&
|
||||
aSourceSurface->Height() == aDestSurface->Height() &&
|
||||
aSourceSurface->Stride() == aDestSurface->Stride(),
|
||||
"Source and destination surfaces don't have identical characteristics");
|
||||
|
||||
MOZ_ASSERT(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
|
||||
"Source surface stride isn't tightly packed");
|
||||
|
||||
MOZ_ASSERT(aSourceSurface->Format() == gfxImageFormat::ARGB32 || aSourceSurface->Format() == gfxImageFormat::RGB24,
|
||||
"Surfaces must be ARGB32 or RGB24");
|
||||
|
||||
uint8_t *src = aSourceSurface->Data();
|
||||
uint8_t *dst = aDestSurface->Data();
|
||||
|
||||
uint32_t dim = aSourceSurface->Width() * aSourceSurface->Height();
|
||||
uint8_t *srcEnd = src + 4*dim;
|
||||
|
||||
if (src == dst) {
|
||||
uint8_t buffer[4];
|
||||
for (; src != srcEnd; src += 4) {
|
||||
buffer[0] = src[2];
|
||||
buffer[1] = src[1];
|
||||
buffer[2] = src[0];
|
||||
|
||||
src[0] = buffer[0];
|
||||
src[1] = buffer[1];
|
||||
src[2] = buffer[2];
|
||||
}
|
||||
} else {
|
||||
for (; src != srcEnd; src += 4, dst += 4) {
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxUtils::ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength)
|
||||
{
|
||||
MOZ_ASSERT((aLength % 4) == 0, "Loop below will pass srcEnd!");
|
||||
|
||||
uint8_t *src = aData;
|
||||
uint8_t *srcEnd = src + aLength;
|
||||
|
||||
|
@ -43,8 +43,6 @@ public:
|
||||
static void PremultiplyDataSurface(DataSourceSurface *aSurface);
|
||||
static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface);
|
||||
|
||||
static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
|
||||
gfxImageSurface *aDestSurface = nullptr);
|
||||
static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);
|
||||
|
||||
/**
|
||||
|
@ -302,6 +302,7 @@ typedef union jsval_layout
|
||||
uint32_t boo; // Don't use |bool| -- it must be four bytes.
|
||||
JSString *str;
|
||||
JSObject *obj;
|
||||
js::gc::Cell *cell;
|
||||
void *ptr;
|
||||
JSWhyMagic why;
|
||||
size_t word;
|
||||
|
@ -19,6 +19,11 @@
|
||||
#endif
|
||||
#include "gc/Tracer.h"
|
||||
|
||||
/* Perform validation of incremental marking in debug builds but not on B2G. */
|
||||
#if defined(DEBUG) && !defined(MOZ_B2G)
|
||||
#define JS_GC_MARKING_VALIDATION
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
struct ScriptAndCounts
|
||||
@ -410,7 +415,7 @@ class GCRuntime
|
||||
*/
|
||||
js::gc::ArenaHeader *arenasAllocatedDuringSweep;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef JS_GC_MARKING_VALIDATION
|
||||
js::gc::MarkingValidator *markingValidator;
|
||||
#endif
|
||||
|
||||
|
@ -192,6 +192,25 @@ function rsub_object(i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_mod_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_mod_number'));
|
||||
function rmod_number(i) {
|
||||
var x = i % 98;
|
||||
if (uceFault_mod_number(i) || uceFault_mod_number(i))
|
||||
assertEq(x, 1); /* 99 % 98 = 1 */
|
||||
return i;
|
||||
}
|
||||
|
||||
var uceFault_mod_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_mod_object'));
|
||||
function rmod_object(i) {
|
||||
var t = i;
|
||||
var o = { valueOf: function() { return t; } };
|
||||
var x = o % 98; /* computed with t == i, not 1000 */
|
||||
t = 1000;
|
||||
if(uceFault_mod_object(i) || uceFault_mod_object(i))
|
||||
assertEq(x, 1); /* 99 % 98 = 1 */
|
||||
return i;
|
||||
}
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
rbitnot_number(i);
|
||||
rbitnot_object(i);
|
||||
@ -212,6 +231,8 @@ for (i = 0; i < 100; i++) {
|
||||
rsub_number(i);
|
||||
rsub_float(i);
|
||||
rsub_object(i);
|
||||
rmod_number(i);
|
||||
rmod_object(i);
|
||||
}
|
||||
|
||||
// Test that we can refer multiple time to the same recover instruction, as well
|
||||
|
73
js/src/jit-test/tests/latin1/dependent.js
Normal file
73
js/src/jit-test/tests/latin1/dependent.js
Normal file
@ -0,0 +1,73 @@
|
||||
function testSubstrLatin1() {
|
||||
var s1 = toLatin1("abcdefghijklmnopqrstuvwxyz12345678900000a");
|
||||
|
||||
// Static strings.
|
||||
assertEq(s1.substr(s1.length - 1), "a");
|
||||
assertEq(s1.substr(s1.length - 2), "0a");
|
||||
assertEq(s1.substr(26, 3), "123");
|
||||
|
||||
// (Fat) inline strings.
|
||||
var s2 = s1.substr(3, 5);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2, "defgh");
|
||||
s2 = s1.substr(0, 20);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2, "abcdefghijklmnopqrst");
|
||||
|
||||
// Dependent string.
|
||||
s2 = s1.substr(1, s1.length - 2);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2.length, 39);
|
||||
assertEq(s2, "bcdefghijklmnopqrstuvwxyz12345678900000");
|
||||
|
||||
s2 = s2.substr(2).substr(1);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2, "efghijklmnopqrstuvwxyz12345678900000");
|
||||
}
|
||||
testSubstrLatin1();
|
||||
|
||||
function testSubstrTwoByte() {
|
||||
// Two byte string.
|
||||
var s1 = "abcdefghijklmnopqrstuvwxyz12345678900000a\u1480";
|
||||
assertEq(isLatin1(s1), false);
|
||||
|
||||
// Static string.
|
||||
var s2 = s1.substr(28, 1);
|
||||
assertEq(s2, "3");
|
||||
|
||||
// Inline string.
|
||||
s2 = s1.substr(3, 5);
|
||||
assertEq(s2, "defgh");
|
||||
|
||||
// Dependent string.
|
||||
s2 = s1.substr(2);
|
||||
assertEq(isLatin1(s2), false);
|
||||
assertEq(s2, "cdefghijklmnopqrstuvwxyz12345678900000a\u1480");
|
||||
|
||||
s2 = s2.substr(2).substr(1);
|
||||
assertEq(isLatin1(s2), false);
|
||||
assertEq(s2, "fghijklmnopqrstuvwxyz12345678900000a\u1480");
|
||||
}
|
||||
testSubstrTwoByte();
|
||||
|
||||
function testSubstring() {
|
||||
var s1 = toLatin1("abcdefghijklmnopqrstuvwxyz123456789000ab");
|
||||
var s2 = s1.substring(1, 8);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2, "bcdefgh");
|
||||
s2 = s1.substring(0, s1.length - 1);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2, "abcdefghijklmnopqrstuvwxyz123456789000a");
|
||||
}
|
||||
testSubstring();
|
||||
|
||||
function testSlice() {
|
||||
var s1 = toLatin1("abcdefghijklmnopqrstuvwxyz123456789000ABC");
|
||||
var s2 = s1.slice(1, 8);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2, "bcdefgh");
|
||||
s2 = s1.slice(0, -2);
|
||||
assertEq(isLatin1(s2), true);
|
||||
assertEq(s2, "abcdefghijklmnopqrstuvwxyz123456789000A");
|
||||
}
|
||||
testSlice();
|
31
js/src/jit-test/tests/latin1/other.js
Normal file
31
js/src/jit-test/tests/latin1/other.js
Normal file
@ -0,0 +1,31 @@
|
||||
var s1 = toLatin1("abcdefg12345");
|
||||
var s2 = toLatin1('foo"bar');
|
||||
|
||||
function test() {
|
||||
assertEq(s1.valueOf(), s1);
|
||||
|
||||
assertEq(s1.bold(), "<b>abcdefg12345</b>");
|
||||
assertEq(s1.fontsize("twoByte\u1400"), '<font size="twoByte\u1400">abcdefg12345</font>');
|
||||
assertEq(s1.anchor(s1), '<a name="abcdefg12345">abcdefg12345</a>');
|
||||
assertEq(s1.link(s2), '<a href="foo"bar">abcdefg12345</a>');
|
||||
|
||||
assertEq(s1.concat("abc"), "abcdefg12345abc");
|
||||
|
||||
var s3 = s1.concat(s1, s1);
|
||||
assertEq(isLatin1(s3), true);
|
||||
assertEq(s3, "abcdefg12345abcdefg12345abcdefg12345");
|
||||
|
||||
s3 = s1.concat("twoByte\u1400");
|
||||
assertEq(isLatin1(s3), false);
|
||||
assertEq(s3, "abcdefg12345twoByte\u1400");
|
||||
|
||||
assertEq(s1.codePointAt(3), 100);
|
||||
assertEq(s1.codePointAt(10), 52);
|
||||
assertEq(s1.codePointAt(12), undefined);
|
||||
|
||||
s3 = s1.repeat(5);
|
||||
assertEq(s3, "abcdefg12345abcdefg12345abcdefg12345abcdefg12345abcdefg12345");
|
||||
assertEq(isLatin1(s3), true);
|
||||
}
|
||||
test();
|
||||
test();
|
@ -5990,9 +5990,11 @@ static const RegisterSet AllRegsExceptSP =
|
||||
FloatRegisterSet(FloatRegisters::AllMask));
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
// The ARM system ABI also includes d15 in the non volatile float registers.
|
||||
// Also exclude lr (a.k.a. r14) as we preserve it manually)
|
||||
static const RegisterSet NonVolatileRegs =
|
||||
RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask),
|
||||
FloatRegisterSet(FloatRegisters::NonVolatileMask | (1 << FloatRegisters::d15)));
|
||||
RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask &
|
||||
~(uint32_t(1) << Registers::lr)),
|
||||
FloatRegisterSet(FloatRegisters::NonVolatileMask | (1 << FloatRegisters::d15)));
|
||||
#else
|
||||
static const RegisterSet NonVolatileRegs =
|
||||
RegisterSet(GeneralRegisterSet(Registers::NonVolatileMask),
|
||||
@ -6017,7 +6019,7 @@ LoadJSContextFromActivation(MacroAssembler &masm, Register activation, Register
|
||||
static void
|
||||
AssertStackAlignment(MacroAssembler &masm)
|
||||
{
|
||||
JS_ASSERT((AlignmentAtPrologue + masm.framePushed()) % StackAlignment == 0);
|
||||
JS_ASSERT((AlignmentAtAsmJSPrologue + masm.framePushed()) % StackAlignment == 0);
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
JS_ASSERT(IsPowerOfTwo(StackAlignment));
|
||||
@ -6042,7 +6044,7 @@ StackDecrementForCall(MacroAssembler &masm, unsigned bytesToPush)
|
||||
{
|
||||
// Include extra padding so that, after pushing the bytesToPush,
|
||||
// the stack is aligned for a call instruction.
|
||||
unsigned alreadyPushed = AlignmentAtPrologue + masm.framePushed();
|
||||
unsigned alreadyPushed = AlignmentAtAsmJSPrologue + masm.framePushed();
|
||||
return AlignBytes(alreadyPushed + bytesToPush, StackAlignment) - alreadyPushed;
|
||||
}
|
||||
|
||||
@ -6078,6 +6080,14 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
||||
// NB: GenerateExits assumes that masm.framePushed() == 0 before
|
||||
// PushRegsInMask(NonVolatileRegs).
|
||||
masm.setFramePushed(0);
|
||||
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
// Push lr without incrementing masm.framePushed since this push is
|
||||
// accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
|
||||
// pop.
|
||||
masm.push(lr);
|
||||
#endif // JS_CODEGEN_ARM
|
||||
|
||||
masm.PushRegsInMask(NonVolatileRegs);
|
||||
JS_ASSERT(masm.framePushed() == FramePushedAfterSave);
|
||||
|
||||
@ -6174,7 +6184,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
masm.move32(Imm32(true), ReturnReg);
|
||||
masm.abiret();
|
||||
masm.ret();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6328,8 +6338,12 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
masm.align(CodeAlignment);
|
||||
m.setInterpExitOffset(exitIndex);
|
||||
masm.setFramePushed(0);
|
||||
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.Push(lr);
|
||||
// Push lr without incrementing masm.framePushed since this push is
|
||||
// accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
|
||||
// pop.
|
||||
masm.push(lr);
|
||||
#endif
|
||||
|
||||
MIRType typeArray[] = { MIRType_Pointer, // cx
|
||||
@ -6346,7 +6360,7 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
||||
masm.reserveStack(stackDec);
|
||||
|
||||
// Fill the argument array.
|
||||
unsigned offsetToCallerStackArgs = AlignmentAtPrologue + masm.framePushed();
|
||||
unsigned offsetToCallerStackArgs = AlignmentAtAsmJSPrologue + masm.framePushed();
|
||||
unsigned offsetToArgv = StackArgBytes(invokeArgTypes) + MaybeRetAddr;
|
||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
|
||||
@ -6499,14 +6513,16 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Push(HeapReg);
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
// The lr register holds the return address and needs to be saved. The GlobalReg
|
||||
// (r10) and HeapReg (r11) also need to be restored before returning to asm.js code.
|
||||
// Push lr without incrementing masm.framePushed since this push is
|
||||
// accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
|
||||
// pop.
|
||||
masm.push(lr);
|
||||
|
||||
// The GlobalReg (r10) and HeapReg (r11) also need to be restored before
|
||||
// returning to asm.js code.
|
||||
// The NANReg also needs to be restored, but is a constant and is reloaded before
|
||||
// returning to asm.js code.
|
||||
masm.PushRegsInMask(RegisterSet(GeneralRegisterSet((1<<GlobalReg.code()) |
|
||||
(1<<HeapReg.code()) |
|
||||
(1<<lr.code())),
|
||||
FloatRegisterSet(uint32_t(0))));
|
||||
masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#endif
|
||||
|
||||
// The stack frame is used for the call into Ion and also for calls into C for OOL
|
||||
@ -6700,18 +6716,14 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
||||
|
||||
masm.bind(&done);
|
||||
masm.freeStack(stackDec);
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Pop(HeapReg);
|
||||
#endif
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
masm.ma_vimm(GenericNaN(), NANReg);
|
||||
masm.PopRegsInMask(RegisterSet(GeneralRegisterSet((1<<GlobalReg.code()) |
|
||||
(1<<HeapReg.code()) |
|
||||
(1<<pc.code())),
|
||||
FloatRegisterSet(uint32_t(0))));
|
||||
#else
|
||||
# if defined(JS_CODEGEN_X64)
|
||||
masm.Pop(HeapReg);
|
||||
# endif
|
||||
masm.ret();
|
||||
masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
|
||||
#endif
|
||||
masm.ret();
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
// oolConvert
|
||||
@ -6751,10 +6763,6 @@ GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
|
||||
masm.align(CodeAlignment);
|
||||
masm.bind(&m.stackOverflowLabel());
|
||||
|
||||
// The overflow check always occurs before the initial function-specific
|
||||
// stack-size adjustment. See CodeGenerator::generateAsmJSPrologue.
|
||||
masm.setFramePushed(AlignmentMidPrologue - AlignmentAtPrologue);
|
||||
|
||||
MIRTypeVector argTypes(m.cx());
|
||||
argTypes.infallibleAppend(MIRType_Pointer); // cx
|
||||
|
||||
@ -6924,7 +6932,7 @@ GenerateThrowExit(ModuleCompiler &m, Label *throwLabel)
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
masm.mov(ImmWord(0), ReturnReg);
|
||||
masm.abiret();
|
||||
masm.ret();
|
||||
|
||||
return !masm.oom();
|
||||
}
|
||||
|
@ -8328,6 +8328,27 @@ CodeGenerator::visitGetDOMProperty(LGetDOMProperty *ins)
|
||||
const Register PrivateReg = ToRegister(ins->getPrivReg());
|
||||
const Register ValueReg = ToRegister(ins->getValueReg());
|
||||
|
||||
Label haveValue;
|
||||
if (ins->mir()->valueMayBeInSlot()) {
|
||||
size_t slot = ins->mir()->domMemberSlotIndex();
|
||||
// It's a bit annoying to redo these slot calculations, which duplcate
|
||||
// LSlots and a few other things like that, but I'm not sure there's a
|
||||
// way to reuse those here.
|
||||
if (slot < JSObject::MAX_FIXED_SLOTS) {
|
||||
masm.loadValue(Address(ObjectReg, JSObject::getFixedSlotOffset(slot)),
|
||||
JSReturnOperand);
|
||||
} else {
|
||||
// It's a dynamic slot.
|
||||
slot -= JSObject::MAX_FIXED_SLOTS;
|
||||
// Use PrivateReg as a scratch register for the slots pointer.
|
||||
masm.loadPtr(Address(ObjectReg, JSObject::offsetOfSlots()),
|
||||
PrivateReg);
|
||||
masm.loadValue(Address(PrivateReg, slot*sizeof(js::Value)),
|
||||
JSReturnOperand);
|
||||
}
|
||||
masm.branchTestUndefined(Assembler::NotEqual, JSReturnOperand, &haveValue);
|
||||
}
|
||||
|
||||
DebugOnly<uint32_t> initialStack = masm.framePushed();
|
||||
|
||||
masm.checkStackAlignment();
|
||||
@ -8377,6 +8398,8 @@ CodeGenerator::visitGetDOMProperty(LGetDOMProperty *ins)
|
||||
}
|
||||
masm.adjustStack(IonDOMExitFrameLayout::Size());
|
||||
|
||||
masm.bind(&haveValue);
|
||||
|
||||
JS_ASSERT(masm.framePushed() == initialStack);
|
||||
return true;
|
||||
}
|
||||
@ -8660,7 +8683,7 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
|
||||
if (mir->spIncrement())
|
||||
masm.freeStack(mir->spIncrement());
|
||||
|
||||
JS_ASSERT((AlignmentAtPrologue + masm.framePushed()) % StackAlignment == 0);
|
||||
JS_ASSERT((AlignmentAtAsmJSPrologue + masm.framePushed()) % StackAlignment == 0);
|
||||
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
|
@ -8852,9 +8852,9 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
||||
if (isDOM && testShouldDOMCall(objTypes, commonGetter, JSJitInfo::Getter)) {
|
||||
const JSJitInfo *jitinfo = commonGetter->jitInfo();
|
||||
MInstruction *get;
|
||||
if (jitinfo->isInSlot) {
|
||||
if (jitinfo->isAlwaysInSlot) {
|
||||
// We can't use MLoadFixedSlot here because it might not have the
|
||||
// right aliasing behavior; we want to alias DOM setters.
|
||||
// right aliasing behavior; we want to alias DOM setters as needed.
|
||||
get = MGetDOMMember::New(alloc(), jitinfo, obj, guard);
|
||||
} else {
|
||||
get = MGetDOMProperty::New(alloc(), jitinfo, obj, guard);
|
||||
|
@ -251,7 +251,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
}
|
||||
}
|
||||
|
||||
// asm.js compilation handles its own IonContet-pushing
|
||||
// asm.js compilation handles its own IonContext-pushing
|
||||
struct AsmJSToken {};
|
||||
explicit MacroAssembler(AsmJSToken)
|
||||
: enoughMemory_(true),
|
||||
|
@ -4549,6 +4549,11 @@ class MMod : public MBinaryArithInstruction
|
||||
return unsigned_;
|
||||
}
|
||||
|
||||
bool writeRecoverData(CompactBufferWriter &writer) const;
|
||||
bool canRecoverOnBailout() const {
|
||||
return specialization_ < MIRType_Object;
|
||||
}
|
||||
|
||||
bool fallible() const;
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
@ -8660,9 +8665,12 @@ class MGetDOMProperty
|
||||
return info_->aliasSet();
|
||||
}
|
||||
size_t domMemberSlotIndex() const {
|
||||
MOZ_ASSERT(info_->isInSlot);
|
||||
MOZ_ASSERT(info_->isAlwaysInSlot || info_->isLazilyCachedInSlot);
|
||||
return info_->slotIndex;
|
||||
}
|
||||
bool valueMayBeInSlot() const {
|
||||
return info_->isLazilyCachedInSlot;
|
||||
}
|
||||
MDefinition *object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
@ -364,6 +364,33 @@ RSub::recover(JSContext *cx, SnapshotIterator &iter) const
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MMod::writeRecoverData(CompactBufferWriter &writer) const
|
||||
{
|
||||
MOZ_ASSERT(canRecoverOnBailout());
|
||||
writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod));
|
||||
return true;
|
||||
}
|
||||
|
||||
RMod::RMod(CompactBufferReader &reader)
|
||||
{ }
|
||||
|
||||
bool
|
||||
RMod::recover(JSContext *cx, SnapshotIterator &iter) const
|
||||
{
|
||||
RootedValue lhs(cx, iter.read());
|
||||
RootedValue rhs(cx, iter.read());
|
||||
RootedValue result(cx);
|
||||
|
||||
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
|
||||
if (!js::ModValues(cx, &lhs, &rhs, &result))
|
||||
return false;
|
||||
|
||||
iter.storeInstructionResult(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MNewObject::writeRecoverData(CompactBufferWriter &writer) const
|
||||
{
|
||||
|
@ -26,6 +26,7 @@ namespace jit {
|
||||
_(Ursh) \
|
||||
_(Add) \
|
||||
_(Sub) \
|
||||
_(Mod) \
|
||||
_(NewObject) \
|
||||
_(NewDerivedTypedObject)
|
||||
|
||||
@ -197,6 +198,18 @@ class RSub MOZ_FINAL : public RInstruction
|
||||
bool recover(JSContext *cx, SnapshotIterator &iter) const;
|
||||
};
|
||||
|
||||
class RMod MOZ_FINAL : public RInstruction
|
||||
{
|
||||
public:
|
||||
RINSTRUCTION_HEADER_(Mod)
|
||||
|
||||
virtual uint32_t numOperands() const {
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool recover(JSContext *cx, SnapshotIterator &iter) const;
|
||||
};
|
||||
|
||||
class RNewObject MOZ_FINAL : public RInstruction
|
||||
{
|
||||
private:
|
||||
|
@ -139,9 +139,7 @@ static const uint32_t StackAlignment = 8;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
static const bool StackKeptAligned = true;
|
||||
static const uint32_t NativeFrameSize = sizeof(void*);
|
||||
static const uint32_t AlignmentAtPrologue = 0;
|
||||
static const uint32_t AlignmentMidPrologue = 4;
|
||||
|
||||
static const uint32_t AlignmentAtAsmJSPrologue = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesFour;
|
||||
|
||||
|
@ -53,7 +53,7 @@ CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel)
|
||||
{
|
||||
JS_ASSERT(gen->compilingAsmJS());
|
||||
|
||||
masm.Push(lr);
|
||||
masm.push(lr);
|
||||
|
||||
// The asm.js over-recursed handler wants to be able to assume that SP
|
||||
// points to the return address, so perform the check after pushing lr but
|
||||
@ -85,18 +85,12 @@ CodeGeneratorARM::generateEpilogue()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gen->compilingAsmJS()) {
|
||||
// Pop the stack we allocated at the start of the function.
|
||||
if (gen->compilingAsmJS())
|
||||
masm.freeStack(frameDepth_);
|
||||
masm.Pop(pc);
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
//masm.as_bkpt();
|
||||
} else {
|
||||
// Pop the stack we allocated at the start of the function.
|
||||
else
|
||||
masm.freeStack(frameSize());
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
masm.ma_pop(pc);
|
||||
}
|
||||
JS_ASSERT(masm.framePushed() == 0);
|
||||
masm.pop(pc);
|
||||
masm.dumpPool();
|
||||
return true;
|
||||
}
|
||||
@ -1047,14 +1041,8 @@ CodeGeneratorARM::toMoveOperand(const LAllocation *a) const
|
||||
return MoveOperand(ToRegister(a));
|
||||
if (a->isFloatReg())
|
||||
return MoveOperand(ToFloatRegister(a));
|
||||
JS_ASSERT((ToStackOffset(a) & 3) == 0);
|
||||
int32_t offset = ToStackOffset(a);
|
||||
|
||||
// The way the stack slots work, we assume that everything from depth == 0 downwards is writable
|
||||
// however, since our frame is included in this, ensure that the frame gets skipped
|
||||
if (gen->compilingAsmJS())
|
||||
offset -= AlignmentMidPrologue;
|
||||
|
||||
JS_ASSERT((offset & 3) == 0);
|
||||
return MoveOperand(StackPointer, offset);
|
||||
}
|
||||
|
||||
|
@ -3867,7 +3867,7 @@ void MacroAssemblerARMCompat::checkStackAlignment()
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABIPre(uint32_t *stackAdjust)
|
||||
MacroAssemblerARMCompat::callWithABIPre(uint32_t *stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
JS_ASSERT(inCall_);
|
||||
|
||||
@ -3876,8 +3876,11 @@ MacroAssemblerARMCompat::callWithABIPre(uint32_t *stackAdjust)
|
||||
if (useHardFpABI())
|
||||
*stackAdjust += 2*((usedFloatSlots_ > NumFloatArgRegs) ? usedFloatSlots_ - NumFloatArgRegs : 0) * sizeof(intptr_t);
|
||||
#endif
|
||||
uint32_t alignmentAtPrologue = (callFromAsmJS) ? AlignmentAtAsmJSPrologue : 0;
|
||||
|
||||
if (!dynamicAlignment_) {
|
||||
*stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust, StackAlignment);
|
||||
*stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust + alignmentAtPrologue,
|
||||
StackAlignment);
|
||||
} else {
|
||||
// sizeof(intptr_t) account for the saved stack pointer pushed by setupUnalignedABICall
|
||||
*stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), StackAlignment);
|
||||
@ -4021,7 +4024,7 @@ void
|
||||
MacroAssemblerARMCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
|
||||
call(imm);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
@ -453,9 +453,9 @@ private:
|
||||
|
||||
class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
{
|
||||
bool inCall_;
|
||||
// Number of bytes the stack is adjusted inside a call to C. Calls to C may
|
||||
// not be nested.
|
||||
bool inCall_;
|
||||
uint32_t args_;
|
||||
// The actual number of arguments that were passed, used to assert that
|
||||
// the initial number of arguments declared was correct.
|
||||
@ -576,7 +576,9 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
}
|
||||
|
||||
void appendCallSite(const CallSiteDesc &desc) {
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_));
|
||||
// Add an extra sizeof(void*) to include the return address that was
|
||||
// pushed by the call instruction (see CallSite::stackDepth).
|
||||
enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + sizeof(void*)));
|
||||
}
|
||||
|
||||
void call(const CallSiteDesc &desc, const Register reg) {
|
||||
@ -1530,7 +1532,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
bool buildOOLFakeExitFrame(void *fakeReturnAddr);
|
||||
|
||||
private:
|
||||
void callWithABIPre(uint32_t *stackAdjust);
|
||||
void callWithABIPre(uint32_t *stackAdjust, bool callFromAsmJS = false);
|
||||
void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
|
||||
|
||||
public:
|
||||
|
@ -138,7 +138,7 @@ static const uint32_t CodeAlignment = 4;
|
||||
static const bool StackKeptAligned = true;
|
||||
// NativeFrameSize is the size of return adress on stack in AsmJS functions.
|
||||
static const uint32_t NativeFrameSize = sizeof(void*);
|
||||
static const uint32_t AlignmentAtPrologue = 0;
|
||||
static const uint32_t AlignmentAtAsmJSPrologue = 0;
|
||||
static const uint32_t AlignmentMidPrologue = NativeFrameSize;
|
||||
|
||||
static const Scale ScalePointer = TimesFour;
|
||||
|
@ -74,7 +74,7 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
|
||||
bool forceAlign = false;
|
||||
#endif
|
||||
if (gen->needsInitialStackAlignment() || forceAlign) {
|
||||
unsigned alignmentAtCall = AlignmentMidPrologue + frameDepth_;
|
||||
unsigned alignmentAtCall = AlignmentAtAsmJSPrologue + frameDepth_;
|
||||
if (unsigned rem = alignmentAtCall % StackAlignment) {
|
||||
frameInitialAdjustment_ = StackAlignment - rem;
|
||||
frameDepth_ += frameInitialAdjustment_;
|
||||
|
@ -183,8 +183,7 @@ static const uint32_t StackAlignment = 16;
|
||||
static const bool StackKeptAligned = false;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
static const uint32_t NativeFrameSize = sizeof(void*);
|
||||
static const uint32_t AlignmentAtPrologue = sizeof(void*);
|
||||
static const uint32_t AlignmentMidPrologue = AlignmentAtPrologue;
|
||||
static const uint32_t AlignmentAtAsmJSPrologue = sizeof(void*);
|
||||
|
||||
static const Scale ScalePointer = TimesEight;
|
||||
|
||||
|
@ -111,8 +111,7 @@ static const uint32_t StackAlignment = 4;
|
||||
static const bool StackKeptAligned = false;
|
||||
static const uint32_t CodeAlignment = 8;
|
||||
static const uint32_t NativeFrameSize = sizeof(void*);
|
||||
static const uint32_t AlignmentAtPrologue = sizeof(void*);
|
||||
static const uint32_t AlignmentMidPrologue = AlignmentAtPrologue;
|
||||
static const uint32_t AlignmentAtAsmJSPrologue = sizeof(void*);
|
||||
struct ImmTag : public Imm32
|
||||
{
|
||||
ImmTag(JSValueTag mask)
|
||||
|
@ -1880,12 +1880,18 @@ struct JSJitInfo {
|
||||
not be enough (e.g. in cases when it can
|
||||
throw). */
|
||||
// XXXbz should we have a JSValueType for the type of the member?
|
||||
uint32_t isInSlot : 1; /* True if this is a getter that can get a member
|
||||
from a slot of the "this" object directly. */
|
||||
uint32_t isAlwaysInSlot : 1; /* True if this is a getter that can always
|
||||
get the value from a slot of the "this"
|
||||
object. */
|
||||
uint32_t isLazilyCachedInSlot : 1; /* True if this is a getter that can
|
||||
sometimes (if the slot doesn't contain
|
||||
UndefinedValue()) get the value from a
|
||||
slot of the "this" object. */
|
||||
uint32_t isTypedMethod : 1; /* True if this is an instance of
|
||||
JSTypedMethodJitInfo. */
|
||||
uint32_t slotIndex : 12; /* If isInSlot is true, the index of the slot to
|
||||
get the value from. Otherwise 0. */
|
||||
uint32_t slotIndex : 11; /* If isAlwaysInSlot or isSometimesInSlot is
|
||||
true, the index of the slot to get the value
|
||||
from. Otherwise 0. */
|
||||
};
|
||||
|
||||
static_assert(sizeof(JSJitInfo) == (sizeof(void*) + 2 * sizeof(uint32_t)),
|
||||
@ -1943,7 +1949,7 @@ inline int CheckIsParallelNative(JSParallelNative parallelNative);
|
||||
*/
|
||||
#define JS_JITINFO_NATIVE_PARALLEL(infoName, parallelOp) \
|
||||
const JSJitInfo infoName = \
|
||||
{{JS_CAST_PARALLEL_NATIVE_TO(parallelOp, JSJitGetterOp)},0,0,JSJitInfo::ParallelNative,JSJitInfo::AliasEverything,JSVAL_TYPE_MISSING,false,false,false,false,0}
|
||||
{{JS_CAST_PARALLEL_NATIVE_TO(parallelOp, JSJitGetterOp)},0,0,JSJitInfo::ParallelNative,JSJitInfo::AliasEverything,JSVAL_TYPE_MISSING,false,false,false,false,false,0}
|
||||
|
||||
#define JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(infoName, wrapperName, serialOp) \
|
||||
bool wrapperName##_ParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, \
|
||||
|
@ -1086,7 +1086,7 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
|
||||
sweepKindIndex(0),
|
||||
abortSweepAfterCurrentGroup(false),
|
||||
arenasAllocatedDuringSweep(nullptr),
|
||||
#ifdef DEBUG
|
||||
#ifdef JS_GC_MARKING_VALIDATION
|
||||
markingValidator(nullptr),
|
||||
#endif
|
||||
interFrameGC(0),
|
||||
@ -3159,6 +3159,10 @@ class js::gc::MarkingValidator
|
||||
BitmapMap map;
|
||||
};
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef JS_GC_MARKING_VALIDATION
|
||||
|
||||
js::gc::MarkingValidator::MarkingValidator(GCRuntime *gc)
|
||||
: gc(gc),
|
||||
initialized(false)
|
||||
@ -3347,12 +3351,12 @@ js::gc::MarkingValidator::validate()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // JS_GC_MARKING_VALIDATION
|
||||
|
||||
void
|
||||
GCRuntime::computeNonIncrementalMarkingForValidation()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef JS_GC_MARKING_VALIDATION
|
||||
JS_ASSERT(!markingValidator);
|
||||
if (isIncremental && validate)
|
||||
markingValidator = js_new<MarkingValidator>(this);
|
||||
@ -3364,7 +3368,7 @@ GCRuntime::computeNonIncrementalMarkingForValidation()
|
||||
void
|
||||
GCRuntime::validateIncrementalMarking()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef JS_GC_MARKING_VALIDATION
|
||||
if (markingValidator)
|
||||
markingValidator->validate();
|
||||
#endif
|
||||
@ -3373,7 +3377,7 @@ GCRuntime::validateIncrementalMarking()
|
||||
void
|
||||
GCRuntime::finishMarkingValidation()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef JS_GC_MARKING_VALIDATION
|
||||
js_delete(markingValidator);
|
||||
markingValidator = nullptr;
|
||||
#endif
|
||||
@ -3382,7 +3386,7 @@ GCRuntime::finishMarkingValidation()
|
||||
static void
|
||||
AssertNeedsBarrierFlagsConsistent(JSRuntime *rt)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef JS_GC_MARKING_VALIDATION
|
||||
bool anyNeedsBarrier = false;
|
||||
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
|
||||
anyNeedsBarrier |= zone->needsBarrier();
|
||||
|
@ -4082,12 +4082,19 @@ js_NewDependentString(JSContext *cx, JSString *baseArg, size_t start, size_t len
|
||||
if (start == 0 && length == base->length())
|
||||
return base;
|
||||
|
||||
const jschar *chars = base->chars() + start;
|
||||
if (base->hasTwoByteChars()) {
|
||||
AutoCheckCannotGC nogc;
|
||||
const jschar *chars = base->twoByteChars(nogc) + start;
|
||||
if (JSLinearString *staticStr = cx->staticStrings().lookup(chars, length))
|
||||
return staticStr;
|
||||
} else {
|
||||
AutoCheckCannotGC nogc;
|
||||
const Latin1Char *chars = base->latin1Chars(nogc) + start;
|
||||
if (JSLinearString *staticStr = cx->staticStrings().lookup(chars, length))
|
||||
return staticStr;
|
||||
}
|
||||
|
||||
if (JSLinearString *staticStr = cx->staticStrings().lookup(chars, length))
|
||||
return staticStr;
|
||||
|
||||
return JSDependentString::new_(cx, base, chars, length);
|
||||
return JSDependentString::new_(cx, base, start, length);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
|
@ -5250,7 +5250,8 @@ static const JSJitInfo dom_x_getterinfo = {
|
||||
JSVAL_TYPE_UNKNOWN, /* returnType */
|
||||
true, /* isInfallible. False in setters. */
|
||||
true, /* isMovable */
|
||||
false, /* isInSlot */
|
||||
false, /* isAlwaysInSlot */
|
||||
false, /* isLazilyCachedInSlot */
|
||||
false, /* isTypedMethod */
|
||||
0 /* slotIndex */
|
||||
};
|
||||
@ -5264,7 +5265,8 @@ static const JSJitInfo dom_x_setterinfo = {
|
||||
JSVAL_TYPE_UNKNOWN, /* returnType */
|
||||
false, /* isInfallible. False in setters. */
|
||||
false, /* isMovable. */
|
||||
false, /* isInSlot */
|
||||
false, /* isAlwaysInSlot */
|
||||
false, /* isLazilyCachedInSlot */
|
||||
false, /* isTypedMethod */
|
||||
0 /* slotIndex */
|
||||
};
|
||||
@ -5278,7 +5280,8 @@ static const JSJitInfo doFoo_methodinfo = {
|
||||
JSVAL_TYPE_UNKNOWN, /* returnType */
|
||||
false, /* isInfallible. False in setters. */
|
||||
false, /* isMovable */
|
||||
false, /* isInSlot */
|
||||
false, /* isAlwaysInSlot */
|
||||
false, /* isLazilyCachedInSlot */
|
||||
false, /* isTypedMethod */
|
||||
0 /* slotIndex */
|
||||
};
|
||||
|
@ -19,27 +19,37 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
template <AllowGC allowGC, typename CharT>
|
||||
static MOZ_ALWAYS_INLINE JSInlineString *
|
||||
AllocateFatInlineString(ThreadSafeContext *cx, size_t len, CharT **chars)
|
||||
{
|
||||
MOZ_ASSERT(JSFatInlineString::lengthFits<CharT>(len));
|
||||
|
||||
if (JSInlineString::lengthFits<CharT>(len)) {
|
||||
JSInlineString *str = JSInlineString::new_<allowGC>(cx);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
*chars = str->init<CharT>(len);
|
||||
return str;
|
||||
}
|
||||
|
||||
JSFatInlineString *str = JSFatInlineString::new_<allowGC>(cx);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
*chars = str->init<CharT>(len);
|
||||
return str;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE JSInlineString *
|
||||
NewFatInlineString(ThreadSafeContext *cx, JS::Latin1Chars chars)
|
||||
{
|
||||
size_t len = chars.length();
|
||||
JS_ASSERT(JSFatInlineString::twoByteLengthFits(len));
|
||||
|
||||
JSInlineString *str;
|
||||
jschar *p;
|
||||
if (JSInlineString::twoByteLengthFits(len)) {
|
||||
str = JSInlineString::new_<allowGC>(cx);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
p = str->initTwoByte(len);
|
||||
} else {
|
||||
JSFatInlineString *fatstr = JSFatInlineString::new_<allowGC>(cx);
|
||||
if (!fatstr)
|
||||
return nullptr;
|
||||
p = fatstr->initTwoByte(len);
|
||||
str = fatstr;
|
||||
}
|
||||
JSInlineString *str = AllocateFatInlineString<allowGC>(cx, len, &p);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
p[i] = static_cast<jschar>(chars[i]);
|
||||
@ -51,34 +61,39 @@ template <AllowGC allowGC>
|
||||
static MOZ_ALWAYS_INLINE JSInlineString *
|
||||
NewFatInlineString(ExclusiveContext *cx, JS::TwoByteChars chars)
|
||||
{
|
||||
size_t len = chars.length();
|
||||
|
||||
/*
|
||||
* Don't bother trying to find a static atom; measurement shows that not
|
||||
* many get here (for one, Atomize is catching them).
|
||||
*/
|
||||
JS_ASSERT(JSFatInlineString::twoByteLengthFits(len));
|
||||
|
||||
JSInlineString *str;
|
||||
size_t len = chars.length();
|
||||
jschar *storage;
|
||||
if (JSInlineString::twoByteLengthFits(len)) {
|
||||
str = JSInlineString::new_<allowGC>(cx);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
storage = str->initTwoByte(len);
|
||||
} else {
|
||||
JSFatInlineString *fatstr = JSFatInlineString::new_<allowGC>(cx);
|
||||
if (!fatstr)
|
||||
return nullptr;
|
||||
storage = fatstr->initTwoByte(len);
|
||||
str = fatstr;
|
||||
}
|
||||
JSInlineString *str = AllocateFatInlineString<allowGC>(cx, len, &storage);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
|
||||
mozilla::PodCopy(storage, chars.start().get(), len);
|
||||
storage[len] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static MOZ_ALWAYS_INLINE JSInlineString *
|
||||
NewFatInlineString(ExclusiveContext *cx, Handle<JSLinearString*> base, size_t start, size_t length)
|
||||
{
|
||||
MOZ_ASSERT(JSFatInlineString::lengthFits<CharT>(length));
|
||||
|
||||
CharT *chars;
|
||||
JSInlineString *s = AllocateFatInlineString<CanGC>(cx, length, &chars);
|
||||
if (!s)
|
||||
return nullptr;
|
||||
|
||||
AutoCheckCannotGC nogc;
|
||||
mozilla::PodCopy(chars, base->chars<CharT>(nogc) + start, length);
|
||||
chars[length] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline void
|
||||
StringWriteBarrierPost(js::ThreadSafeContext *maybecx, JSString **strp)
|
||||
{
|
||||
@ -139,52 +154,55 @@ JSRope::markChildren(JSTracer *trc)
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void
|
||||
JSDependentString::init(js::ThreadSafeContext *cx, JSLinearString *base, const jschar *chars,
|
||||
JSDependentString::init(js::ThreadSafeContext *cx, JSLinearString *base, size_t start,
|
||||
size_t length)
|
||||
{
|
||||
JS_ASSERT(!js::IsPoisonedPtr(base));
|
||||
MOZ_ASSERT(!js::IsPoisonedPtr(base));
|
||||
MOZ_ASSERT(start + length <= base->length());
|
||||
d.u1.length = length;
|
||||
d.u1.flags = DEPENDENT_FLAGS;
|
||||
d.s.u2.nonInlineCharsTwoByte = chars;
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (base->hasLatin1Chars()) {
|
||||
d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
|
||||
d.s.u2.nonInlineCharsLatin1 = base->latin1Chars(nogc) + start;
|
||||
} else {
|
||||
d.u1.flags = DEPENDENT_FLAGS;
|
||||
d.s.u2.nonInlineCharsTwoByte = base->twoByteChars(nogc) + start;
|
||||
}
|
||||
d.s.u3.base = base;
|
||||
js::StringWriteBarrierPost(cx, reinterpret_cast<JSString **>(&d.s.u3.base));
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE JSLinearString *
|
||||
JSDependentString::new_(js::ExclusiveContext *cx,
|
||||
JSLinearString *baseArg, const jschar *chars, size_t length)
|
||||
JSDependentString::new_(js::ExclusiveContext *cx, JSLinearString *baseArg, size_t start,
|
||||
size_t length)
|
||||
{
|
||||
/* Try to avoid long chains of dependent strings. */
|
||||
while (baseArg->isDependent())
|
||||
while (baseArg->isDependent()) {
|
||||
start += baseArg->asDependent().baseOffset();
|
||||
baseArg = baseArg->asDependent().base();
|
||||
|
||||
JS_ASSERT(baseArg->isFlat());
|
||||
|
||||
/*
|
||||
* The chars we are pointing into must be owned by something in the chain
|
||||
* of dependent or undepended strings kept alive by our base pointer.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
for (JSLinearString *b = baseArg; ; b = b->base()) {
|
||||
if (chars >= b->chars() && chars < b->chars() + b->length() &&
|
||||
length <= b->length() - (chars - b->chars()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(start + length <= baseArg->length());
|
||||
MOZ_ASSERT(baseArg->isFlat());
|
||||
|
||||
/*
|
||||
* Do not create a string dependent on inline chars from another string,
|
||||
* both to avoid the awkward moving-GC hazard this introduces and because it
|
||||
* is more efficient to immediately undepend here.
|
||||
*/
|
||||
if (JSFatInlineString::twoByteLengthFits(length))
|
||||
return js::NewFatInlineString<js::CanGC>(cx, JS::TwoByteChars(chars, length));
|
||||
bool useFatInline = baseArg->hasTwoByteChars()
|
||||
? JSFatInlineString::twoByteLengthFits(length)
|
||||
: JSFatInlineString::latin1LengthFits(length);
|
||||
if (useFatInline) {
|
||||
JS::Rooted<JSLinearString*> base(cx, baseArg);
|
||||
if (baseArg->hasLatin1Chars())
|
||||
return js::NewFatInlineString<JS::Latin1Char>(cx, base, start, length);
|
||||
return js::NewFatInlineString<jschar>(cx, base, start, length);
|
||||
}
|
||||
|
||||
JSDependentString *str = (JSDependentString *)js_NewGCString<js::NoGC>(cx);
|
||||
if (str) {
|
||||
str->init(cx, baseArg, chars, length);
|
||||
str->init(cx, baseArg, start, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -193,7 +211,7 @@ JSDependentString::new_(js::ExclusiveContext *cx,
|
||||
str = (JSDependentString *)js_NewGCString<js::CanGC>(cx);
|
||||
if (!str)
|
||||
return nullptr;
|
||||
str->init(cx, base, chars, length);
|
||||
str->init(cx, base, start, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -285,6 +303,34 @@ JSFatInlineString::initLatin1(size_t length)
|
||||
return d.inlineStorageLatin1;
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE JS::Latin1Char *
|
||||
JSInlineString::init<JS::Latin1Char>(size_t length)
|
||||
{
|
||||
return initLatin1(length);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE jschar *
|
||||
JSInlineString::init<jschar>(size_t length)
|
||||
{
|
||||
return initTwoByte(length);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE JS::Latin1Char *
|
||||
JSFatInlineString::init<JS::Latin1Char>(size_t length)
|
||||
{
|
||||
return initLatin1(length);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE jschar *
|
||||
JSFatInlineString::init<jschar>(size_t length)
|
||||
{
|
||||
return initTwoByte(length);
|
||||
}
|
||||
|
||||
template <js::AllowGC allowGC>
|
||||
MOZ_ALWAYS_INLINE JSFatInlineString *
|
||||
JSFatInlineString::new_(js::ThreadSafeContext *cx)
|
||||
|
@ -627,6 +627,10 @@ class JSLinearString : public JSString
|
||||
MOZ_ALWAYS_INLINE
|
||||
const jschar *chars() const;
|
||||
|
||||
template<typename CharT>
|
||||
MOZ_ALWAYS_INLINE
|
||||
const CharT *chars(const JS::AutoCheckCannotGC &nogc) const;
|
||||
|
||||
MOZ_ALWAYS_INLINE
|
||||
const JS::Latin1Char *latin1Chars(const JS::AutoCheckCannotGC &nogc) const;
|
||||
|
||||
@ -659,7 +663,7 @@ class JSDependentString : public JSLinearString
|
||||
friend class JSString;
|
||||
JSFlatString *undepend(js::ExclusiveContext *cx);
|
||||
|
||||
void init(js::ThreadSafeContext *cx, JSLinearString *base, const jschar *chars,
|
||||
void init(js::ThreadSafeContext *cx, JSLinearString *base, size_t start,
|
||||
size_t length);
|
||||
|
||||
/* Vacuous and therefore unimplemented. */
|
||||
@ -669,9 +673,22 @@ class JSDependentString : public JSLinearString
|
||||
/* Hide chars(), nonInlineChars() is more efficient. */
|
||||
const jschar *chars() const MOZ_DELETE;
|
||||
|
||||
/* The offset of this string's chars in base->chars(). */
|
||||
size_t baseOffset() const {
|
||||
MOZ_ASSERT(JSString::isDependent());
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
size_t offset;
|
||||
if (hasTwoByteChars())
|
||||
offset = twoByteChars(nogc) - base()->twoByteChars(nogc);
|
||||
else
|
||||
offset = latin1Chars(nogc) - base()->latin1Chars(nogc);
|
||||
MOZ_ASSERT(offset < base()->length());
|
||||
return offset;
|
||||
}
|
||||
|
||||
public:
|
||||
static inline JSLinearString *new_(js::ExclusiveContext *cx, JSLinearString *base,
|
||||
const jschar *chars, size_t length);
|
||||
size_t start, size_t length);
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSDependentString) == sizeof(JSString));
|
||||
@ -770,6 +787,9 @@ class JSInlineString : public JSFlatString
|
||||
inline jschar *initTwoByte(size_t length);
|
||||
inline JS::Latin1Char *initLatin1(size_t length);
|
||||
|
||||
template <typename CharT>
|
||||
inline CharT *init(size_t length);
|
||||
|
||||
inline void resetLength(size_t length);
|
||||
|
||||
MOZ_ALWAYS_INLINE
|
||||
@ -800,6 +820,9 @@ class JSInlineString : public JSFlatString
|
||||
return length <= MAX_LENGTH_TWO_BYTE;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
static bool lengthFits(size_t length);
|
||||
|
||||
static size_t offsetOfInlineStorage() {
|
||||
return offsetof(JSInlineString, d.inlineStorageTwoByte);
|
||||
}
|
||||
@ -859,6 +882,9 @@ class JSFatInlineString : public JSInlineString
|
||||
inline jschar *initTwoByte(size_t length);
|
||||
inline JS::Latin1Char *initLatin1(size_t length);
|
||||
|
||||
template <typename CharT>
|
||||
inline CharT *init(size_t length);
|
||||
|
||||
static bool latin1LengthFits(size_t length) {
|
||||
return length <= MAX_LENGTH_LATIN1;
|
||||
}
|
||||
@ -866,6 +892,9 @@ class JSFatInlineString : public JSInlineString
|
||||
return length <= MAX_LENGTH_TWO_BYTE;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
static bool lengthFits(size_t length);
|
||||
|
||||
/* Only called by the GC for strings with the FINALIZE_FAT_INLINE_STRING kind. */
|
||||
|
||||
MOZ_ALWAYS_INLINE void finalize(js::FreeOp *fop);
|
||||
@ -1045,7 +1074,8 @@ class StaticStrings
|
||||
static bool isStatic(JSAtom *atom);
|
||||
|
||||
/* Return null if no static atom exists for the given (chars, length). */
|
||||
JSAtom *lookup(const jschar *chars, size_t length) {
|
||||
template <typename CharT>
|
||||
JSAtom *lookup(const CharT *chars, size_t length) {
|
||||
switch (length) {
|
||||
case 1:
|
||||
if (chars[0] < UNIT_STATIC_LIMIT)
|
||||
@ -1264,6 +1294,48 @@ JSLinearString::nonInlineChars(const JS::AutoCheckCannotGC &nogc) const
|
||||
return nonInlineLatin1Chars(nogc);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE const jschar *
|
||||
JSLinearString::chars(const JS::AutoCheckCannotGC &nogc) const
|
||||
{
|
||||
return twoByteChars(nogc);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE const JS::Latin1Char *
|
||||
JSLinearString::chars(const JS::AutoCheckCannotGC &nogc) const
|
||||
{
|
||||
return latin1Chars(nogc);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
JSInlineString::lengthFits<JS::Latin1Char>(size_t length)
|
||||
{
|
||||
return latin1LengthFits(length);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
JSInlineString::lengthFits<jschar>(size_t length)
|
||||
{
|
||||
return twoByteLengthFits(length);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
JSFatInlineString::lengthFits<JS::Latin1Char>(size_t length)
|
||||
{
|
||||
return latin1LengthFits(length);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
JSFatInlineString::lengthFits<jschar>(size_t length)
|
||||
{
|
||||
return twoByteLengthFits(length);
|
||||
}
|
||||
|
||||
template<>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
JSString::setNonInlineChars(const jschar *chars)
|
||||
|
@ -1674,6 +1674,10 @@ ContainerState::FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex)
|
||||
break;
|
||||
}
|
||||
|
||||
if (item->IsInvisibleInRect(appUnitRect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nscolor color;
|
||||
if (item->IsUniform(mBuilder, &color) && NS_GET_A(color) == 255)
|
||||
return color;
|
||||
|
@ -1709,6 +1709,15 @@ nsDisplayItem::ZIndex() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayItem::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion)
|
||||
{
|
||||
return !mVisibleRect.IsEmpty() &&
|
||||
!IsInvisibleInRect(aVisibleRegion->GetBounds());
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) {
|
||||
@ -2646,26 +2655,20 @@ nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayOutline::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) {
|
||||
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
|
||||
aAllowVisibleRegionExpansion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect)
|
||||
{
|
||||
const nsStyleOutline* outline = mFrame->StyleOutline();
|
||||
nsRect borderBox(ToReferenceFrame(), mFrame->GetSize());
|
||||
if (borderBox.Contains(aVisibleRegion->GetBounds()) &&
|
||||
if (borderBox.Contains(aRect) &&
|
||||
!nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) {
|
||||
if (outline->mOutlineOffset >= 0) {
|
||||
// the visible region is entirely inside the border-rect, and the outline
|
||||
// isn't rendered inside the border-rect, so the outline is not visible
|
||||
return false;
|
||||
// aRect is entirely inside the border-rect, and the outline isn't
|
||||
// rendered inside the border-rect, so the outline is not visible.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2725,30 +2728,24 @@ nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayBorder::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) {
|
||||
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
|
||||
aAllowVisibleRegionExpansion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect)
|
||||
{
|
||||
nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
|
||||
ToReferenceFrame();
|
||||
const nsStyleBorder *styleBorder;
|
||||
if (paddingRect.Contains(aVisibleRegion->GetBounds()) &&
|
||||
if (paddingRect.Contains(aRect) &&
|
||||
!(styleBorder = mFrame->StyleBorder())->IsBorderImageLoaded() &&
|
||||
!nsLayoutUtils::HasNonZeroCorner(styleBorder->mBorderRadius)) {
|
||||
// the visible region is entirely inside the content rect, and no part
|
||||
// aRect is entirely inside the content rect, and no part
|
||||
// of the border is rendered inside the content rect, so we are not
|
||||
// visible
|
||||
// Skip this if there's a border-image (which draws a background
|
||||
// too) or if there is a border-radius (which makes the border draw
|
||||
// further in).
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDisplayItemGeometry*
|
||||
@ -2879,6 +2876,24 @@ nsDisplayBoxShadowOuter::GetBoundsInternal() {
|
||||
ToReferenceFrame();
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect& aRect)
|
||||
{
|
||||
nsPoint origin = ToReferenceFrame();
|
||||
nsRect frameRect(origin, mFrame->GetSize());
|
||||
if (!frameRect.Contains(aRect))
|
||||
return false;
|
||||
|
||||
// the visible region is entirely inside the border-rect, and box shadows
|
||||
// never render within the border-rect (unless there's a border radius).
|
||||
nscoord twipsRadii[8];
|
||||
bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
|
||||
if (!hasBorderRadii)
|
||||
return true;
|
||||
|
||||
return RoundedRectContainsRect(frameRect, twipsRadii, aRect);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
@ -2890,21 +2905,7 @@ nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
// Store the actual visible region
|
||||
mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
|
||||
|
||||
nsPoint origin = ToReferenceFrame();
|
||||
nsRect visibleBounds = aVisibleRegion->GetBounds();
|
||||
nsRect frameRect(origin, mFrame->GetSize());
|
||||
if (!frameRect.Contains(visibleBounds))
|
||||
return true;
|
||||
|
||||
// the visible region is entirely inside the border-rect, and box shadows
|
||||
// never render within the border-rect (unless there's a border radius).
|
||||
nscoord twipsRadii[8];
|
||||
bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
|
||||
if (!hasBorderRadii)
|
||||
return false;
|
||||
|
||||
return !RoundedRectContainsRect(frameRect, twipsRadii, visibleBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -933,6 +933,14 @@ public:
|
||||
*aSnap = false;
|
||||
return nsRect(ToReferenceFrame(), Frame()->GetSize());
|
||||
}
|
||||
/**
|
||||
* Returns true if nothing will be rendered inside aRect, false if uncertain.
|
||||
* aRect is assumed to be contained in this item's bounds.
|
||||
*/
|
||||
virtual bool IsInvisibleInRect(const nsRect& aRect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns the result of GetBounds intersected with the item's clip.
|
||||
* The intersection is approximate since rounded corners are not taking into
|
||||
@ -1191,8 +1199,7 @@ public:
|
||||
*/
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion)
|
||||
{ return !mVisibleRect.IsEmpty(); }
|
||||
const nsRect& aAllowVisibleRegionExpansion);
|
||||
|
||||
/**
|
||||
* Try to merge with the other item (which is below us in the display
|
||||
@ -2022,11 +2029,9 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool IsInvisibleInRect(const nsRect& aRect) MOZ_OVERRIDE;
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
|
||||
NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
|
||||
|
||||
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
|
||||
@ -2344,6 +2349,7 @@ public:
|
||||
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
|
||||
virtual bool IsInvisibleInRect(const nsRect& aRect) MOZ_OVERRIDE;
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
|
||||
@ -2430,11 +2436,9 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool IsInvisibleInRect(const nsRect& aRect) MOZ_OVERRIDE;
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
|
||||
NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE)
|
||||
};
|
||||
|
||||
|
@ -230,6 +230,8 @@ static void Shutdown();
|
||||
|
||||
#include "AudioChannelService.h"
|
||||
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
|
||||
#include "mozilla/dom/power/PowerManagerService.h"
|
||||
#include "mozilla/dom/alarm/AlarmHalService.h"
|
||||
#include "mozilla/dom/time/TimeService.h"
|
||||
@ -589,10 +591,15 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(Geolocation, Init)
|
||||
#define NS_AUDIOCHANNEL_SERVICE_CID \
|
||||
{ 0xf712e983, 0x048a, 0x443f, { 0x88, 0x02, 0xfc, 0xc3, 0xd9, 0x27, 0xce, 0xac }}
|
||||
|
||||
#define NS_DATASTORE_SERVICE_CID \
|
||||
{ 0x0d4285fe, 0xf1b3, 0x49fa, { 0xbc, 0x51, 0xa4, 0xa8, 0x3f, 0x0a, 0xaf, 0x85 }}
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AudioChannelService, AudioChannelService::GetAudioChannelService)
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DataStoreService, DataStoreService::GetOrCreate)
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(FakeSpeechRecognitionService)
|
||||
#endif
|
||||
@ -742,6 +749,7 @@ NS_DEFINE_NAMED_CID(NS_TEXTSERVICESDOCUMENT_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_GEOLOCATION_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_GEOLOCATION_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_AUDIOCHANNEL_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DATASTORE_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_FOCUSMANAGER_CID);
|
||||
NS_DEFINE_NAMED_CID(CSPSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_CSPCONTEXT_CID);
|
||||
@ -1030,6 +1038,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
||||
{ &kNS_GEOLOCATION_SERVICE_CID, false, nullptr, nsGeolocationServiceConstructor },
|
||||
{ &kNS_GEOLOCATION_CID, false, nullptr, GeolocationConstructor },
|
||||
{ &kNS_AUDIOCHANNEL_SERVICE_CID, false, nullptr, AudioChannelServiceConstructor },
|
||||
{ &kNS_DATASTORE_SERVICE_CID, false, nullptr, DataStoreServiceConstructor },
|
||||
{ &kNS_FOCUSMANAGER_CID, false, nullptr, CreateFocusManager },
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
{ &kNS_FAKE_SPEECH_RECOGNITION_SERVICE_CID, false, nullptr, FakeSpeechRecognitionServiceConstructor },
|
||||
@ -1185,6 +1194,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
||||
{ "@mozilla.org/geolocation/service;1", &kNS_GEOLOCATION_SERVICE_CID },
|
||||
{ "@mozilla.org/geolocation;1", &kNS_GEOLOCATION_CID },
|
||||
{ "@mozilla.org/audiochannel/service;1", &kNS_AUDIOCHANNEL_SERVICE_CID },
|
||||
{ "@mozilla.org/datastore-service;1", &kNS_DATASTORE_SERVICE_CID },
|
||||
{ "@mozilla.org/focus-manager;1", &kNS_FOCUSMANAGER_CID },
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
{ NS_SPEECH_RECOGNITION_SERVICE_CONTRACTID_PREFIX "fake", &kNS_FAKE_SPEECH_RECOGNITION_SERVICE_CID },
|
||||
|
@ -65,6 +65,7 @@
|
||||
#include "ActiveLayerTracker.h"
|
||||
|
||||
#include "AudioChannelService.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULPopupManager.h"
|
||||
@ -411,6 +412,8 @@ nsLayoutStatics::Shutdown()
|
||||
|
||||
AudioChannelService::Shutdown();
|
||||
|
||||
DataStoreService::Shutdown();
|
||||
|
||||
ContentParent::ShutDown();
|
||||
|
||||
nsRefreshDriver::Shutdown();
|
||||
|
@ -958,6 +958,24 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsFrameList::Enumerator oc(GetChildList(kOverflowContainersList));
|
||||
for (; !oc.AtEnd(); oc.Next()) {
|
||||
MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(oc.get()));
|
||||
}
|
||||
nsFrameList::Enumerator eoc(GetChildList(kExcessOverflowContainersList));
|
||||
for (; !eoc.AtEnd(); eoc.Next()) {
|
||||
MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(eoc.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
nsOverflowAreas ocBounds;
|
||||
nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
|
||||
if (GetPrevInFlow()) {
|
||||
ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0,
|
||||
ocStatus);
|
||||
}
|
||||
|
||||
//------------ Handle Incremental Reflow -----------------
|
||||
|
||||
ReflowConfig config = ChooseColumnStrategy(aReflowState);
|
||||
@ -994,15 +1012,19 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
|
||||
aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE,
|
||||
"Column set should be complete if the available height is unconstrained");
|
||||
|
||||
// Merge overflow container bounds and status.
|
||||
aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
|
||||
NS_MergeReflowStatusInto(&aStatus, ocStatus);
|
||||
|
||||
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus, false);
|
||||
|
||||
aDesiredSize.mCarriedOutBottomMargin = carriedOutBottomMargin;
|
||||
|
||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
|
||||
|
||||
NS_ASSERTION(NS_FRAME_IS_FULLY_COMPLETE(aStatus) ||
|
||||
aReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE,
|
||||
"Column set should be complete if the available height is unconstrained");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIFrameInlines.h" // for methods used by IS_TRUE_OVERFLOW_CONTAINER
|
||||
|
||||
class nsColumnSetFrame : public nsContainerFrame {
|
||||
public:
|
||||
@ -51,8 +52,11 @@ public:
|
||||
}
|
||||
|
||||
virtual nsresult StealFrame(nsIFrame* aChild, bool aForceNormal) MOZ_OVERRIDE
|
||||
{ // nsColumnSetFrame keeps overflow containers in main child list
|
||||
return nsContainerFrame::StealFrame(aChild, true);
|
||||
{
|
||||
// nsColumnSetFrame keeps true overflow containers in the normal flow
|
||||
// child lists (i.e. the principal and overflow lists).
|
||||
return nsContainerFrame::StealFrame(aChild,
|
||||
IS_TRUE_OVERFLOW_CONTAINER(aChild));
|
||||
}
|
||||
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
|
||||
|
@ -1798,22 +1798,9 @@ static void AdjustViews(nsIFrame* aFrame)
|
||||
}
|
||||
|
||||
static bool
|
||||
CanScrollWithBlitting(nsIFrame* aFrame)
|
||||
NeedToInvalidateOnScroll(nsIFrame* aFrame)
|
||||
{
|
||||
if (aFrame->GetStateBits() & NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL)
|
||||
return false;
|
||||
|
||||
for (nsIFrame* f = aFrame; f;
|
||||
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
|
||||
if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) ||
|
||||
f->IsFrameOfType(nsIFrame::eSVG) ||
|
||||
f->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) {
|
||||
return false;
|
||||
}
|
||||
if (nsLayoutUtils::IsPopup(f))
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
return (aFrame->GetStateBits() & NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL) != 0;
|
||||
}
|
||||
|
||||
bool ScrollFrameHelper::IsIgnoringViewportClipping() const
|
||||
@ -1900,14 +1887,12 @@ void ScrollFrameHelper::ScrollVisual(nsPoint aOldScrolledFramePos)
|
||||
AdjustViews(mScrolledFrame);
|
||||
// We need to call this after fixing up the view positions
|
||||
// to be consistent with the frame hierarchy.
|
||||
bool canScrollWithBlitting = CanScrollWithBlitting(mOuter);
|
||||
bool needToInvalidateOnScroll = NeedToInvalidateOnScroll(mOuter);
|
||||
mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
|
||||
if (IsScrollingActive()) {
|
||||
if (!canScrollWithBlitting) {
|
||||
MarkInactive();
|
||||
}
|
||||
if (IsScrollingActive() && needToInvalidateOnScroll) {
|
||||
MarkInactive();
|
||||
}
|
||||
if (canScrollWithBlitting) {
|
||||
if (!needToInvalidateOnScroll) {
|
||||
MarkActive();
|
||||
}
|
||||
|
||||
@ -2196,9 +2181,8 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
|
||||
scrollParts.AppendElement(kid);
|
||||
}
|
||||
|
||||
mozilla::layers::FrameMetrics::ViewID scrollTargetId = aCreateLayer
|
||||
? nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent())
|
||||
: mozilla::layers::FrameMetrics::NULL_SCROLL_ID;
|
||||
mozilla::layers::FrameMetrics::ViewID scrollTargetId =
|
||||
nsLayoutUtils::FindOrCreateIDFor(mScrolledFrame->GetContent());
|
||||
|
||||
scrollParts.Sort(HoveredStateComparator());
|
||||
|
||||
@ -2216,11 +2200,16 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
|
||||
flags |= nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR;
|
||||
}
|
||||
|
||||
// Always create layers for overlay scrollbars so that we don't create a
|
||||
// giant layer covering the whole scrollport if both scrollbars are visible.
|
||||
bool isOverlayScrollbar = (flags != 0) && overlayScrollbars;
|
||||
bool createLayer = aCreateLayer || isOverlayScrollbar;
|
||||
|
||||
// DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into
|
||||
// partList.PositionedDescendants().
|
||||
::AppendToTop(aBuilder, aLists,
|
||||
partList.PositionedDescendants(), scrollParts[i],
|
||||
aCreateLayer, flags, scrollTargetId, aPositioned);
|
||||
createLayer, flags, scrollTargetId, aPositioned);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2418,7 +2407,7 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
if (aBuilder->IsPaintingToWindow()) {
|
||||
mScrollPosAtLastPaint = GetScrollPosition();
|
||||
if (IsScrollingActive() && !CanScrollWithBlitting(mOuter)) {
|
||||
if (IsScrollingActive() && NeedToInvalidateOnScroll(mOuter)) {
|
||||
MarkInactive();
|
||||
}
|
||||
if (IsScrollingActive()) {
|
||||
@ -2469,7 +2458,8 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
if (addScrollBars) {
|
||||
// Add overlay scrollbars.
|
||||
AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, true, true);
|
||||
AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
|
||||
createLayersForScrollbars, true);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -2661,9 +2651,8 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
scrolledContent.BorderBackground()->AppendNewToBottom(layerItem);
|
||||
}
|
||||
// Now display overlay scrollbars and the resizer, if we have one.
|
||||
// Always create layers for these, so that we don't create a giant layer
|
||||
// covering the whole scrollport if both scrollbars are visible.
|
||||
AppendScrollPartsTo(aBuilder, aDirtyRect, scrolledContent, true, true);
|
||||
AppendScrollPartsTo(aBuilder, aDirtyRect, scrolledContent,
|
||||
createLayersForScrollbars, true);
|
||||
scrolledContent.MoveTo(aLists);
|
||||
}
|
||||
|
||||
|
@ -473,10 +473,19 @@ int32_t nsCSSSelector::CalcWeightWithoutNegations() const
|
||||
{
|
||||
int32_t weight = 0;
|
||||
|
||||
MOZ_ASSERT(!IsPseudoElement() ||
|
||||
mPseudoType >= nsCSSPseudoElements::ePseudo_PseudoElementCount ||
|
||||
(!mIDList && !mClassList && !mAttrList),
|
||||
"if pseudo-elements can have ID, class or attribute selectors "
|
||||
#ifdef MOZ_XUL
|
||||
MOZ_ASSERT(!(IsPseudoElement() &&
|
||||
PseudoType() != nsCSSPseudoElements::ePseudo_XULTree &&
|
||||
mClassList),
|
||||
"If non-XUL-tree pseudo-elements can have class selectors "
|
||||
"after them, specificity calculation must be updated");
|
||||
#else
|
||||
MOZ_ASSERT(!(IsPseudoElement() && mClassList),
|
||||
"If pseudo-elements can have class selectors "
|
||||
"after them, specificity calculation must be updated");
|
||||
#endif
|
||||
MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)),
|
||||
"If pseudo-elements can have id or attribute selectors "
|
||||
"after them, specificity calculation must be updated");
|
||||
|
||||
if (nullptr != mCasedTag) {
|
||||
@ -488,6 +497,13 @@ int32_t nsCSSSelector::CalcWeightWithoutNegations() const
|
||||
list = list->mNext;
|
||||
}
|
||||
list = mClassList;
|
||||
#ifdef MOZ_XUL
|
||||
// XUL tree pseudo-elements abuse mClassList to store some private
|
||||
// data; ignore that.
|
||||
if (PseudoType() == nsCSSPseudoElements::ePseudo_XULTree) {
|
||||
list = nullptr;
|
||||
}
|
||||
#endif
|
||||
while (nullptr != list) {
|
||||
weight += 0x000100;
|
||||
list = list->mNext;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user