This commit is contained in:
Ryan VanderMeulen 2014-04-08 18:17:58 -04:00
Родитель e53b2c5ade 7271837f38
Коммит f7f6976e6e
188 изменённых файлов: 3913 добавлений и 1161 удалений

Просмотреть файл

@ -922,11 +922,47 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
-moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-arrow");
background: transparent;
border: none;
transition: opacity 300ms;
transform: scale(.7);
opacity: 0;
transition-property: transform, opacity;
transition-duration: 0.15s;
transition-timing-function: ease;
/* The popup inherits -moz-image-region from the button, must reset it */
-moz-image-region: auto;
}
#BMB_bookmarksPopup[animate="open"] {
transform: none;
opacity: 1.0;
}
#BMB_bookmarksPopup[arrowposition="after_start"] {
transform-origin: 20px top;
}
#BMB_bookmarksPopup[arrowposition="after_end"] {
transform-origin: calc(100% - 20px) top;
}
#BMB_bookmarksPopup[arrowposition="before_start"] {
transform-origin: 20px bottom;
}
#BMB_bookmarksPopup[arrowposition="before_end"] {
transform-origin: calc(100% - 20px) bottom;
}
#BMB_bookmarksPopup[arrowposition="after_start"][animate="cancel"],
#BMB_bookmarksPopup[arrowposition="before_end"][animate="cancel"] {
transform: scale(.7) skew(30deg, 20deg);
}
#BMB_bookmarksPopup[arrowposition="after_end"][animate="cancel"],
#BMB_bookmarksPopup[arrowposition="before_start"][animate="cancel"] {
transform: scale(.7) skew(-30deg, -20deg);
}
/* Customize mode */
#navigator-toolbox,
#browser-bottombox,

Просмотреть файл

@ -879,10 +879,13 @@ function test() {
Services.obs.addObserver(XPInstallObserver, "addon-install-failed", false);
Services.obs.addObserver(XPInstallObserver, "addon-install-complete", false);
PopupNotifications.transitionsEnabled = false;
registerCleanupFunction(function() {
// Make sure no more test parts run in case we were timed out
TESTS = [];
PopupNotifications.panel.removeEventListener("popupshown", check_notification, false);
PopupNotifications.transitionsEnabled = true;
AddonManager.getAllInstalls(function(aInstalls) {
aInstalls.forEach(function(aInstall) {

Просмотреть файл

@ -12,14 +12,17 @@ function test() {
waitForFocus(function () {
let PN = newWin.PopupNotifications;
PN.transitionsEnabled = false;
try {
let notification = PN.show(newWin.gBrowser.selectedBrowser, "some-notification", "Some message");
ok(notification, "showed the notification");
ok(PN.isPanelOpen, "panel is open");
is(PN.panel.anchorNode, newWin.gBrowser.selectedTab, "notification is correctly anchored to the tab");
PN.panel.hidePopup();
} catch (ex) {
ok(false, "threw exception: " + ex);
}
PN.transitionsEnabled = true;
newWin.close();
finish();
}, newWin);

Просмотреть файл

@ -8,6 +8,10 @@ function test() {
ok(PopupNotifications, "PopupNotifications object exists");
ok(PopupNotifications.panel, "PopupNotifications panel exists");
// Disable transitions as they slow the test down and we want to click the
// mouse buttons in a predictable location.
PopupNotifications.transitionsEnabled = false;
registerCleanupFunction(cleanUp);
runNextTest();
@ -19,6 +23,7 @@ function cleanUp() {
for (var eventName in gActiveListeners)
PopupNotifications.panel.removeEventListener(eventName, gActiveListeners[eventName], false);
PopupNotifications.buttonDelay = PREF_SECURITY_DELAY_INITIAL;
PopupNotifications.transitionsEnabled = true;
}
const PREF_SECURITY_DELAY_INITIAL = Services.prefs.getIntPref("security.notification_enable_delay");

Просмотреть файл

@ -7,6 +7,7 @@
type="arrow"
hidden="true"
flip="slide"
animate="false"
position="bottomcenter topright"
noautofocus="true">
<panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView">

Просмотреть файл

@ -6,12 +6,16 @@ const isOSX = (Services.appinfo.OS === "Darwin");
let originalWindowWidth;
registerCleanupFunction(function() {
overflowPanel.removeAttribute("animate");
window.resizeTo(originalWindowWidth, window.outerHeight);
});
// Right-click on an item within the overflow panel should
// show a context menu with options to move it.
add_task(function() {
overflowPanel.setAttribute("animate", "false");
originalWindowWidth = window.outerWidth;
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");

Просмотреть файл

@ -526,6 +526,9 @@
var position = this.alignmentPosition;
var offset = this.alignmentOffset;
this.setAttribute("arrowposition", position);
// if this panel has a "sliding" arrow, we may have previously set margins...
arrowbox.style.removeProperty("transform");
if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
@ -578,6 +581,7 @@
<handlers>
<handler event="popupshowing" phase="target"><![CDATA[
this.adjustArrowPosition();
this.setAttribute("animate", "open");
]]></handler>
<handler event="popupshown" phase="target"><![CDATA[
this.setAttribute("panelopen", "true");
@ -604,11 +608,15 @@
this.style.removeProperty("pointer-events");
}
]]></handler>
<handler event="popuphiding" phase="target"><![CDATA[
this.setAttribute("animate", "cancel");
]]></handler>
<handler event="popuphidden" phase="target"><![CDATA[
this.removeAttribute("panelopen");
if (this.getAttribute("disablepointereventsfortransition") == "true") {
this.style.pointerEvents = 'none';
}
this.removeAttribute("animate");
]]></handler>
</handlers>
</binding>

Просмотреть файл

@ -17,6 +17,7 @@ add_task(function testPopup() {
function* checkPopupContextMenu() {
let dropmarker = document.getAnonymousElementByAttribute(bookmarksMenuButton, "anonid", "dropmarker");
BMB_menuPopup.setAttribute("style", "transition: none;");
let popupShownPromise = onPopupEvent(BMB_menuPopup, "shown");
EventUtils.synthesizeMouseAtCenter(dropmarker, {});
info("Waiting for bookmarks menu to be shown.");
@ -28,6 +29,7 @@ function* checkPopupContextMenu() {
ok(!newBookmarkItem.hasAttribute("disabled"), "New bookmark item shouldn't be disabled");
let contextMenuHiddenPromise = onPopupEvent(contextMenu, "hidden");
contextMenu.hidePopup();
BMB_menuPopup.removeAttribute("style");
info("Waiting for context menu on bookmarks menu to be hidden.");
yield contextMenuHiddenPromise;
let popupHiddenPromise = onPopupEvent(BMB_menuPopup, "hidden");

Просмотреть файл

@ -103,6 +103,7 @@ let PanelFactory = {
let panel = doc.createElement("panel");
panel.setAttribute("hidden", true);
panel.setAttribute("ignorekeys", true);
panel.setAttribute("animate", false);
panel.setAttribute("consumeoutsideclicks", options.get("consumeOutsideClick"));
panel.setAttribute("noautofocus", options.get("noAutoFocus"));

Просмотреть файл

@ -276,6 +276,8 @@ function test() {
return;
}
PopupNotifications.transitionsEnabled = false;
registerCleanupFunction(cleanUp);
ok(sitw.SignInToWebsiteUX, "SignInToWebsiteUX object exists");
@ -313,6 +315,8 @@ function cleanUp() {
info("cleanup");
resetState();
PopupNotifications.transitionsEnabled = true;
for (let topic in gActiveObservers)
Services.obs.removeObserver(gActiveObservers[topic], topic);
for (let eventName in gActiveListeners)

Просмотреть файл

@ -23,6 +23,10 @@ let tests = [
let icon = document.getElementById("UITourTooltipIcon");
let buttons = document.getElementById("UITourTooltipButtons");
// Disable the animation to prevent the mouse clicks from hitting the main
// window during the transition instead of the buttons in the popup.
popup.setAttribute("animate", "false");
popup.addEventListener("popupshown", function onPopupShown() {
popup.removeEventListener("popupshown", onPopupShown);
@ -150,6 +154,7 @@ let tests = [
is(gContentWindow.callbackResult, "target", "target callback called");
is(gContentWindow.callbackData.target, "appMenu", "target callback was from the appMenu");
is(gContentWindow.callbackData.type, "popupshown", "target callback was from the mousedown");
popup.removeAttribute("animate");
done();
});
});

Просмотреть файл

@ -4895,7 +4895,7 @@ dnl ========================================================
dnl = GNOME component (mozgnome)
dnl ========================================================
if test "$MOZ_ENABLE_GTK2"
if test "$MOZ_ENABLE_GTK"
then
MOZ_ENABLE_GNOME_COMPONENT=1
fi

Просмотреть файл

@ -3664,17 +3664,7 @@ nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult)
JS::Value
nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aRv)
{
const nsID* iid = aIID->GetID();
nsCOMPtr<nsISupports> result;
JS::Rooted<JS::Value> v(aCx, JSVAL_NULL);
aRv = GetInterface(*iid, getter_AddRefs(result));
NS_ENSURE_FALSE(aRv.Failed(), JSVAL_NULL);
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
JSAutoCompartment ac(aCx, wrapper);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, wrapper));
aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
return aRv.Failed() ? JSVAL_NULL : v;
return dom::GetInterface(aCx, this, aIID, aRv);
}
nsXMLHttpRequestUpload*

Просмотреть файл

@ -25,8 +25,8 @@ var frame = document.getElementById("i");
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var viewer =
SpecialPowers.wrap(frame.contentWindow
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor))
SpecialPowers.wrap(frame.contentWindow)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
.contentViewer

Просмотреть файл

@ -1,5 +1,3 @@
SpecialPowers.setBoolPref("media.webspeech.synth.enabled", true);
var gSpeechRegistry = SpecialPowers.Cc["@mozilla.org/synth-voice-registry;1"]
.getService(SpecialPowers.Ci.nsISynthVoiceRegistry);
@ -170,7 +168,6 @@ function synthCleanup() {
.getService(SpecialPowers.Ci.nsISyncMessageSender);
mm.sendSyncMessage('test:SpeechSynthesis:ipcSynthCleanup');
}
SpecialPowers.clearUserPref("media.webspeech.synth.enabled");
}
function synthTestQueue(aTestArgs, aEndFunc) {

Просмотреть файл

@ -0,0 +1,84 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 525444: Web Speech API check all classes are present</title>
<script type="application/javascript">
window.SimpleTest = parent.SimpleTest;
window.is = parent.is;
window.isnot = parent.isnot;
window.ok = parent.ok;
</script>
<script type="application/javascript" src="common.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 525444 **/
synthAddVoice('TestSpeechServiceNoAudio', 'Bob Marley', 'en-JM', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Amy Winehouse', 'en-GB', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Leonard Cohen', 'en-CA', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Celine Dion', 'fr-CA', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Julieta Venegas', 'es-MX', true);
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
// SpeechSynthesisUtterance is the only type that has a constructor
// and writable properties
ok(SpeechSynthesisUtterance, "SpeechSynthesisUtterance exists in global scope");
var ssu = new SpeechSynthesisUtterance("hello world");
is(typeof ssu, "object", "SpeechSynthesisUtterance instance is an object");
is(ssu.text, "hello world", "SpeechSynthesisUtterance.text is correct");
is(ssu.volume, 1, "SpeechSynthesisUtterance.volume default is correct");
is(ssu.rate, 1, "SpeechSynthesisUtterance.rate default is correct");
is(ssu.pitch, 1, "SpeechSynthesisUtterance.pitch default is correct");
ssu.lang = "he-IL";
ssu.volume = 0.5;
ssu.rate = 2.0;
ssu.pitch = 1.5;
is(ssu.lang, "he-IL", "SpeechSynthesisUtterance.lang is correct");
is(ssu.volume, 0.5, "SpeechSynthesisUtterance.volume is correct");
is(ssu.rate, 2.0, "SpeechSynthesisUtterance.rate is correct");
is(ssu.pitch, 1.5, "SpeechSynthesisUtterance.pitch is correct");
// Test for singleton instance hanging off of window.
ok(speechSynthesis, "speechSynthesis exists in global scope");
is(typeof speechSynthesis, "object", "speechSynthesis instance is an object");
is(typeof speechSynthesis.speak, "function", "speechSynthesis.speak is a function");
is(typeof speechSynthesis.cancel, "function", "speechSynthesis.cancel is a function");
is(typeof speechSynthesis.pause, "function", "speechSynthesis.pause is a function");
is(typeof speechSynthesis.resume, "function", "speechSynthesis.resume is a function");
is(typeof speechSynthesis.getVoices, "function", "speechSynthesis.getVoices is a function");
is(typeof speechSynthesis.pending, "boolean", "speechSynthesis.pending is a boolean");
is(typeof speechSynthesis.speaking, "boolean", "speechSynthesis.speaking is a boolean");
is(typeof speechSynthesis.paused, "boolean", "speechSynthesis.paused is a boolean");
var voices1 = speechSynthesis.getVoices();
var voices2 = speechSynthesis.getVoices();
ok(voices1.length == voices2.length, "Voice count matches");
for (var i in voices1) {
ok(voices1[i] == voices2[i], "Voice instance matches");
}
synthCleanup();
SimpleTest.finish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html lang="en-US">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 525444: Web Speech API, check speech synth queue</title>
<script type="application/javascript">
window.SimpleTest = parent.SimpleTest;
window.is = parent.is;
window.isnot = parent.isnot;
window.ok = parent.ok;
</script>
<script type="application/javascript" src="common.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 525444 **/
var englishJamaican = synthAddVoice('TestSpeechServiceNoAudio',
'Bob Marley', 'en-JM', true);
var englishBritish = synthAddVoice('TestSpeechServiceNoAudio',
'Amy Winehouse', 'en-GB', true);
var englishCanadian = synthAddVoice('TestSpeechServiceNoAudio',
'Leonard Cohen', 'en-CA', true);
var frenchCanadian = synthAddVoice('TestSpeechServiceNoAudio',
'Celine Dion', 'fr-CA', true);
var spanishMexican = synthAddVoice('TestSpeechServiceNoAudio',
'Julieta Venegas', 'es-MX', true);
synthSetDefault(englishBritish, true);
synthTestQueue(
[[{text: "Hello, world."},
{ uri: englishBritish }],
[{text: "Bonjour tout le monde .", lang: "fr", rate: 0.5, pitch: 0.75},
{ uri: frenchCanadian, rate: 0.5, pitch: 0.75}],
[{text: "How are you doing?", lang: "en-GB"},
{ rate: 1, pitch: 1, uri: englishBritish}],
[{text: "¡hasta mañana", lang: "es-ES"},
{ uri: spanishMexican }]],
function () {
synthSetDefault(englishJamaican, true);
var test_data = [[{text: "I shot the sheriff."},
{ uri: englishJamaican }]];
var voices = speechSynthesis.getVoices();
for (var i in voices) {
test_data.push([{text: "Hello world", voice: voices[i]},
{uri: voices[i].voiceURI}]);
}
synthTestQueue(test_data,
function () {
synthCleanup();
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 650295: Web Speech API check all classes are present</title>
<script type="application/javascript">
window.SimpleTest = parent.SimpleTest;
window.info = parent.info;
window.is = parent.is;
window.isnot = parent.isnot;
window.ok = parent.ok;
</script>
<script type="application/javascript" src="common.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 525444 **/
synthAddVoice('TestSpeechServiceWithAudio', 'Male 1', 'en-GB', true);
var gotStartEvent = false;
var gotBoundaryEvent = false;
var utterance = new SpeechSynthesisUtterance("Hello, world!");
utterance.addEventListener('start', function(e) {
ok(speechSynthesis.speaking, "speechSynthesis is speaking.");
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
gotStartEvent = true;
});
utterance.addEventListener('end', function(e) {
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
ok(gotStartEvent, "Got 'start' event.");
info('end ' + e.elapsedTime);
synthCleanup();
SimpleTest.finish();
});
speechSynthesis.speak(utterance);
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,6 +1,10 @@
[DEFAULT]
skip-if = e10s
support-files = common.js
support-files =
common.js
file_setup.html
file_speech_queue.html
file_speech_simple.html
[test_setup.html]
[test_speech_queue.html]

Просмотреть файл

@ -7,12 +7,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
<meta charset="utf-8">
<title>Test for Bug 525444: Web Speech API check all classes are present</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
<p id="display"></p>
<iframe id="testFrame"></iframe>
<div id="content" style="display: none">
</div>
@ -21,57 +21,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
/** Test for Bug 525444 **/
synthAddVoice('TestSpeechServiceNoAudio', 'Bob Marley', 'en-JM', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Amy Winehouse', 'en-GB', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Leonard Cohen', 'en-CA', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Celine Dion', 'fr-CA', true);
synthAddVoice('TestSpeechServiceNoAudio', 'Julieta Venegas', 'es-MX', true);
SimpleTest.waitForExplicitFinish();
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
function() { document.getElementById("testFrame").src = "file_setup.html"; });
// SpeechSynthesisUtterance is the only type that has a constructor
// and writable properties
ok(SpeechSynthesisUtterance, "SpeechSynthesisUtterance exists in global scope");
var ssu = new SpeechSynthesisUtterance("hello world");
is(typeof ssu, "object", "SpeechSynthesisUtterance instance is an object");
is(ssu.text, "hello world", "SpeechSynthesisUtterance.text is correct");
is(ssu.volume, 1, "SpeechSynthesisUtterance.volume default is correct");
is(ssu.rate, 1, "SpeechSynthesisUtterance.rate default is correct");
is(ssu.pitch, 1, "SpeechSynthesisUtterance.pitch default is correct");
ssu.lang = "he-IL";
ssu.volume = 0.5;
ssu.rate = 2.0;
ssu.pitch = 1.5;
is(ssu.lang, "he-IL", "SpeechSynthesisUtterance.lang is correct");
is(ssu.volume, 0.5, "SpeechSynthesisUtterance.volume is correct");
is(ssu.rate, 2.0, "SpeechSynthesisUtterance.rate is correct");
is(ssu.pitch, 1.5, "SpeechSynthesisUtterance.pitch is correct");
// Test for singleton instance hanging off of window.
ok(speechSynthesis, "speechSynthesis exists in global scope");
is(typeof speechSynthesis, "object", "speechSynthesis instance is an object");
is(typeof speechSynthesis.speak, "function", "speechSynthesis.speak is a function");
is(typeof speechSynthesis.cancel, "function", "speechSynthesis.cancel is a function");
is(typeof speechSynthesis.pause, "function", "speechSynthesis.pause is a function");
is(typeof speechSynthesis.resume, "function", "speechSynthesis.resume is a function");
is(typeof speechSynthesis.getVoices, "function", "speechSynthesis.getVoices is a function");
is(typeof speechSynthesis.pending, "boolean", "speechSynthesis.pending is a boolean");
is(typeof speechSynthesis.speaking, "boolean", "speechSynthesis.speaking is a boolean");
is(typeof speechSynthesis.paused, "boolean", "speechSynthesis.paused is a boolean");
var voices1 = speechSynthesis.getVoices();
var voices2 = speechSynthesis.getVoices();
ok(voices1.length == voices2.length, "Voice count matches");
for (var i in voices1) {
ok(voices1[i] == voices2[i], "Voice instance matches");
}
synthCleanup();
</script>
</pre>
</body>

Просмотреть файл

@ -13,6 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
<p id="display"></p>
<iframe id="testFrame"></iframe>
<div id="content" style="display: none">
</div>
@ -23,46 +24,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
SimpleTest.waitForExplicitFinish();
var englishJamaican = synthAddVoice('TestSpeechServiceNoAudio',
'Bob Marley', 'en-JM', true);
var englishBritish = synthAddVoice('TestSpeechServiceNoAudio',
'Amy Winehouse', 'en-GB', true);
var englishCanadian = synthAddVoice('TestSpeechServiceNoAudio',
'Leonard Cohen', 'en-CA', true);
var frenchCanadian = synthAddVoice('TestSpeechServiceNoAudio',
'Celine Dion', 'fr-CA', true);
var spanishMexican = synthAddVoice('TestSpeechServiceNoAudio',
'Julieta Venegas', 'es-MX', true);
synthSetDefault(englishBritish, true);
synthTestQueue(
[[{text: "Hello, world."},
{ uri: englishBritish }],
[{text: "Bonjour tout le monde .", lang: "fr", rate: 0.5, pitch: 0.75},
{ uri: frenchCanadian, rate: 0.5, pitch: 0.75}],
[{text: "How are you doing?", lang: "en-GB"},
{ rate: 1, pitch: 1, uri: englishBritish}],
[{text: "¡hasta mañana", lang: "es-ES"},
{ uri: spanishMexican }]],
function () {
synthSetDefault(englishJamaican, true);
var test_data = [[{text: "I shot the sheriff."},
{ uri: englishJamaican }]];
var voices = speechSynthesis.getVoices();
for (var i in voices) {
test_data.push([{text: "Hello world", voice: voices[i]},
{uri: voices[i].voiceURI}]);
}
synthTestQueue(test_data,
function () {
synthCleanup();
SimpleTest.finish();
});
});
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
function() { document.getElementById("testFrame").src = "file_speech_queue.html"; });
</script>
</pre>

Просмотреть файл

@ -13,6 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650295
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
<p id="display"></p>
<iframe id="testFrame"></iframe>
<div id="content" style="display: none">
</div>
@ -23,29 +24,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=650295
SimpleTest.waitForExplicitFinish();
synthAddVoice('TestSpeechServiceWithAudio', 'Male 1', 'en-GB', true);
var gotStartEvent = false;
var gotBoundaryEvent = false;
var utterance = new SpeechSynthesisUtterance("Hello, world!");
utterance.addEventListener('start', function(e) {
ok(speechSynthesis.speaking, "speechSynthesis is speaking.");
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
gotStartEvent = true;
});
utterance.addEventListener('end', function(e) {
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
ok(gotStartEvent, "Got 'start' event.");
info('end ' + e.elapsedTime);
synthCleanup();
SimpleTest.finish();
});
speechSynthesis.speak(utterance);
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
function() { document.getElementById("testFrame").src = "file_speech_simple.html"; });
</script>
</pre>

Просмотреть файл

@ -297,7 +297,7 @@ nsXULPopupListener::ClosePopup()
// fire events during destruction.
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm)
pm->HidePopup(mPopupContent, false, true, true);
pm->HidePopup(mPopupContent, false, true, true, false);
mPopupContent = nullptr; // release the popup
}
} // ClosePopup

Просмотреть файл

@ -142,7 +142,8 @@ this.OperatorAppsRegistry = {
let orgDir = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsIFile);
orgDir.initWithPath(aOrg);
if (!orgDir.isDirectory()) {
if (!orgDir.exists() || !orgDir.isDirectory()) {
debug(aOrg + " does not exist or is not a directory");
return;
}
@ -168,7 +169,7 @@ this.OperatorAppsRegistry = {
entry.copyTo(dstDir, entry.leafName);
} else {
yield this._copyDirectory(entry.path,
Path.join(aDst, entry.name));
Path.join(aDst, entry.leafName));
}
}
} catch (e) {

Просмотреть файл

@ -182,7 +182,6 @@ static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
#define WINDOW_SCRIPTABLE_FLAGS \
(nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_POSTCREATE | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_ENUMERATE | \
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
nsIXPCScriptable::IS_GLOBAL_OBJECT | \
@ -1855,7 +1854,7 @@ nsWindowSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
#ifdef DEBUG
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == nullptr,
NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == obj,
"Multiple wrappers created for global object!");
#endif
@ -3399,26 +3398,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
_retval);
}
NS_IMETHODIMP
nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
JSObject *obj)
{
// Since this call is virtual, the exact rooting hazard static analysis is
// not able to determine that it happens during finalization and should be
// ignored. Moreover, the analysis cannot discover and validate the
// potential targets of the virtual call to OnFinalize below because of the
// indirection through nsCOMMPtr. Thus, we annotate the analysis here so
// that it does not report OnFinalize as GCing with |obj| on stack.
JS::AutoAssertNoGC nogc;
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
sgo->OnFinalize(obj);
return NS_OK;
}
NS_IMETHODIMP
nsWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval)

Просмотреть файл

@ -270,8 +270,6 @@ public:
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, uint32_t flags,
JSObject **objp, bool *_retval) MOZ_OVERRIDE;
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop,
JSObject *obj) MOZ_OVERRIDE;
NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval) MOZ_OVERRIDE;

Просмотреть файл

@ -1371,7 +1371,6 @@ nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
if (aWindow->mCachedXBLPrototypeHandlers &&
aWindow->mCachedXBLPrototypeHandlers->Count() > 0) {
aWindow->mCachedXBLPrototypeHandlers->Clear();
mozilla::DropJSObjects(aWindow);
}
}
@ -1617,17 +1616,11 @@ nsGlobalWindow::FreeInnerObjects()
// nsGlobalWindow::nsISupports
//*****************************************************************************
#define OUTER_WINDOW_ONLY \
if (IsOuterWindow()) {
#define END_OUTER_WINDOW_ONLY \
foundInterface = 0; \
} else
DOMCI_DATA(Window, nsGlobalWindow)
// QueryInterface implementation for nsGlobalWindow
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
// Make sure this matches the cast in nsGlobalWindow::FromWrapper()
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
@ -1660,9 +1653,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
OUTER_WINDOW_ONLY
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
END_OUTER_WINDOW_ONLY
NS_INTERFACE_MAP_END
@ -1722,6 +1712,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
@ -1769,6 +1760,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
@ -1779,6 +1771,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
@ -1828,6 +1821,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
#ifdef DEBUG
@ -1857,6 +1851,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
TraceData data = { aCallbacks, aClosure };
tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
}
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
bool
@ -1902,12 +1897,12 @@ nsGlobalWindow::EnsureScriptEnvironment()
return NS_ERROR_FAILURE;
}
if (outer->mJSObject) {
if (outer->GetWrapperPreserveColor()) {
return NS_OK;
}
NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
"mJSObject is null, but we have an inner window?");
"No cached wrapper, but we have an inner window?");
// If this window is a [i]frame, don't bother GC'ing when the frame's context
// is destroyed since a GC will happen when the frameset or host document is
@ -1942,9 +1937,40 @@ nsGlobalWindow::GetGlobalJSObject()
void
nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc)
{
if (mJSObject) {
JS_CallTenuredObjectTracer(aTrc, &mJSObject, "active window global");
TraceWrapper(aTrc, "active window global");
}
/* static */
JSObject*
nsGlobalWindow::OuterObject(JSContext* aCx, JS::HandleObject aObj)
{
nsGlobalWindow *origWin;
UNWRAP_OBJECT(Window, aObj, origWin);
nsGlobalWindow *win = origWin->GetOuterWindowInternal();
if (!win) {
// If we no longer have an outer window. No code should ever be
// running on a window w/o an outer, which means this hook should
// never be called when we have no outer. But just in case, return
// null to prevent leaking an inner window to code in a different
// window.
NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
return nullptr;
}
JS::Rooted<JSObject*> winObj(aCx, win->FastGetGlobalJSObject());
MOZ_ASSERT(winObj);
// Note that while |wrapper| is same-compartment with cx, the outer window
// might not be. If we're running script in an inactive scope and evalute
// |this|, the outer window is actually a cross-compartment wrapper. So we
// need to wrap here.
if (!JS_WrapObject(aCx, &winObj)) {
NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
return nullptr;
}
return winObj;
}
bool
@ -2127,7 +2153,7 @@ WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
aWindow->SuspendTimeouts();
// When a global goes into the bfcache, we disable script.
xpc::Scriptability::Get(aWindow->mJSObject).SetDocShellAllowsScript(false);
xpc::Scriptability::Get(aWindow->GetWrapperPreserveColor()).SetDocShellAllowsScript(false);
}
WindowStateHolder::~WindowStateHolder()
@ -2165,7 +2191,6 @@ CreateNativeGlobalForInner(JSContext* aCx,
nsGlobalWindow* aNewInner,
nsIURI* aURI,
nsIPrincipal* aPrincipal,
JS::TenuredHeap<JSObject*>& aNativeGlobal,
nsIXPConnectJSObjectHolder** aHolder)
{
MOZ_ASSERT(aCx);
@ -2193,20 +2218,15 @@ CreateNativeGlobalForInner(JSContext* aCx,
uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
nsRefPtr<nsIXPConnectJSObjectHolder> jsholder;
nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
aCx, ToSupports(aNewInner),
aPrincipal, flags, options, getter_AddRefs(jsholder));
aPrincipal, flags, options, aHolder);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(jsholder);
aNativeGlobal = jsholder->GetJSObject();
jsholder.forget(aHolder);
// Set the location information for the new global, so that tools like
// about:memory may use that information
MOZ_ASSERT(aNativeGlobal.getPtr());
xpc::SetLocationForGlobal(aNativeGlobal, aURI);
MOZ_ASSERT(aNewInner->GetWrapperPreserveColor());
xpc::SetLocationForGlobal(aNewInner->GetWrapperPreserveColor(), aURI);
return NS_OK;
}
@ -2336,22 +2356,23 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
JS::Rooted<JSObject*> newInnerGlobal(cx);
if (reUseInnerWindow) {
// We're reusing the current inner window.
NS_ASSERTION(!currentInner->IsFrozen(),
"We should never be reusing a shared inner window");
newInnerWindow = currentInner;
newInnerGlobal = currentInner->GetWrapperPreserveColor();
if (aDocument != oldDoc) {
JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject);
JS::ExposeObjectToActiveJS(obj);
JS::ExposeObjectToActiveJS(newInnerGlobal);
}
// We're reusing the inner window, but this still counts as a navigation,
// so all expandos and such defined on the outer window should go away. Force
// all Xray wrappers to be recomputed.
JS::ExposeObjectToActiveJS(mJSObject);
JS::Rooted<JSObject*> rootedObject(cx, mJSObject);
JS::Rooted<JSObject*> rootedObject(cx, GetWrapperPreserveColor());
JS::ExposeObjectToActiveJS(rootedObject);
if (!JS_RefreshCrossCompartmentWrappers(cx, rootedObject)) {
return NS_ERROR_FAILURE;
}
@ -2361,7 +2382,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// match the new document.
// NB: We don't just call currentInner->RefreshCompartmentPrincipals() here
// because we haven't yet set its mDoc to aDocument.
JSCompartment *compartment = js::GetObjectCompartment(currentInner->mJSObject);
JSCompartment *compartment = js::GetObjectCompartment(newInnerGlobal);
#ifdef DEBUG
bool sameOrigin = false;
nsIPrincipal *existing =
@ -2374,18 +2395,17 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
} else {
if (aState) {
newInnerWindow = wsh->GetInnerWindow();
newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
mInnerWindowHolder = wsh->GetInnerWindowHolder();
NS_ASSERTION(newInnerWindow, "Got a state without inner window");
} else if (thisChrome) {
newInnerWindow = new nsGlobalChromeWindow(this);
} else if (mIsModalContentWindow) {
newInnerWindow = new nsGlobalModalWindow(this);
} else {
newInnerWindow = new nsGlobalWindow(this);
}
if (thisChrome) {
newInnerWindow = new nsGlobalChromeWindow(this);
} else if (mIsModalContentWindow) {
newInnerWindow = new nsGlobalModalWindow(this);
} else {
newInnerWindow = new nsGlobalWindow(this);
}
if (!aState) {
// Freeze the outer window and null out the inner window so
// that initializing classes on the new inner doesn't end up
// reaching into the old inner window for classes etc.
@ -2405,10 +2425,11 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
rv = CreateNativeGlobalForInner(cx, newInnerWindow,
aDocument->GetDocumentURI(),
aDocument->NodePrincipal(),
newInnerWindow->mJSObject,
getter_AddRefs(mInnerWindowHolder));
NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerWindow->mJSObject && mInnerWindowHolder,
"Failed to get script global and holder");
newInnerGlobal = mInnerWindowHolder->GetJSObject();
NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
"Failed to get script global");
mCreatingInnerWindow = false;
createdInnerWindow = true;
@ -2417,7 +2438,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NS_ENSURE_SUCCESS(rv, rv);
}
if (currentInner && currentInner->mJSObject) {
if (currentInner && currentInner->GetWrapperPreserveColor()) {
if (oldDoc == aDocument) {
// Move the navigator from the old inner window to the new one since
// this is a document.write. This is safe from a same-origin point of
@ -2449,32 +2470,32 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
mInnerWindow = newInnerWindow;
if (!mJSObject) {
JS::Rooted<JSObject*> global(cx, newInnerWindow->FastGetGlobalJSObject());
JS::Rooted<JSObject*> outer(cx, NewOuterWindowProxy(cx, global, thisChrome));
if (!GetWrapperPreserveColor()) {
JS::Rooted<JSObject*> outer(cx,
NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
js::SetProxyExtra(outer, 1, JS::ObjectValue(*newInnerGlobal));
// Inform the nsJSContext, which is the canonical holder of the outer.
mContext->SetWindowProxy(outer);
mContext->DidInitializeContext();
mJSObject = mContext->GetWindowProxy();
SetWrapper(mJSObject);
SetWrapper(mContext->GetWindowProxy());
} else {
JS::ExposeObjectToActiveJS(newInnerWindow->mJSObject);
JS::Rooted<JSObject*> global(cx, newInnerWindow->mJSObject);
JS::ExposeObjectToActiveJS(newInnerGlobal);
JS::Rooted<JSObject*> outerObject(cx,
NewOuterWindowProxy(cx, global, thisChrome));
NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
if (!outerObject) {
NS_ERROR("out of memory");
return NS_ERROR_FAILURE;
}
js::SetProxyExtra(mJSObject, 0, js::PrivateValue(nullptr));
JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr));
JS::Rooted<JSObject*> obj(cx, mJSObject);
outerObject = xpc::TransplantObject(cx, obj, outerObject);
if (!outerObject) {
NS_ERROR("unable to transplant wrappers, probably OOM");
@ -2483,41 +2504,38 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
js::SetProxyExtra(outerObject, 0, js::PrivateValue(ToSupports(this)));
mJSObject = outerObject;
SetWrapper(mJSObject);
SetWrapper(outerObject);
{
JSAutoCompartment ac(cx, mJSObject);
JSAutoCompartment ac(cx, outerObject);
JS::Rooted<JSObject*> obj(cx, mJSObject);
JS::Rooted<JSObject*> newParent(cx, newInnerWindow->mJSObject);
JS_SetParent(cx, obj, newParent);
JS_SetParent(cx, outerObject, newInnerGlobal);
// Inform the nsJSContext, which is the canonical holder of the outer.
mContext->SetWindowProxy(obj);
mContext->SetWindowProxy(outerObject);
NS_ASSERTION(!JS_IsExceptionPending(cx),
"We might overwrite a pending exception!");
XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj);
XPCWrappedNativeScope* scope = xpc::GetObjectScope(outerObject);
if (scope->mWaiverWrapperMap) {
scope->mWaiverWrapperMap->Reparent(cx, newParent);
scope->mWaiverWrapperMap->Reparent(cx, newInnerGlobal);
}
}
}
// Enter the new global's compartment.
JSAutoCompartment ac(cx, mJSObject);
JSAutoCompartment ac(cx, GetWrapperPreserveColor());
// Set scriptability based on the state of the docshell.
bool allow = GetDocShell()->GetCanExecuteScripts();
xpc::Scriptability::Get(mJSObject).SetDocShellAllowsScript(allow);
xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
// If we created a new inner window above, we need to do the last little bit
// of initialization now that the dust has settled.
if (createdInnerWindow) {
nsIXPConnect *xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerWindow->mJSObject,
nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal,
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
@ -2526,8 +2544,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
}
if (!aState) {
if (!JS_DefineProperty(cx, newInnerWindow->mJSObject, "window",
OBJECT_TO_JSVAL(mJSObject),
if (!JS_DefineProperty(cx, newInnerGlobal, "window",
OBJECT_TO_JSVAL(GetWrapperPreserveColor()),
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
NS_ERROR("can't create the 'window' property");
@ -2536,7 +2554,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
}
}
JSAutoCompartment ac(cx, mJSObject);
JSAutoCompartment ac(cx, GetWrapperPreserveColor());
if (!aState && !reUseInnerWindow) {
// Loading a new page and creating a new inner window, *not*
@ -2544,17 +2562,12 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// Now that both the the inner and outer windows are initialized
// let the script context do its magic to hook them together.
MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
#ifdef DEBUG
JS::Rooted<JSObject*> newInnerJSObject(cx,
newInnerWindow->FastGetGlobalJSObject());
#endif
MOZ_ASSERT(mContext->GetWindowProxy() == mJSObject);
#ifdef DEBUG
JS::Rooted<JSObject*> rootedJSObject(cx, mJSObject);
JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
JS::Rooted<JSObject*> proto1(cx), proto2(cx);
JS_GetPrototype(cx, rootedJSObject, &proto1);
JS_GetPrototype(cx, newInnerJSObject, &proto2);
JS_GetPrototype(cx, newInnerGlobal, &proto2);
NS_ASSERTION(proto1 == proto2,
"outer and inner globals should have the same prototype");
#endif
@ -2583,14 +2596,14 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// make sure the cached document property gets updated.
// XXXmarkh - tell other languages about this?
JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject);
JS::Rooted<JSObject*> obj(cx, currentInner->GetWrapperPreserveColor());
::JS_DeleteProperty(cx, obj, "document");
}
} else {
newInnerWindow->InnerSetNewDocument(aDocument);
// Initialize DOM classes etc on the inner window.
JS::Rooted<JSObject*> obj(cx, newInnerWindow->mJSObject);
JS::Rooted<JSObject*> obj(cx, newInnerGlobal);
rv = mContext->InitClasses(obj);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -2600,7 +2613,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// calling Block() and throwing away the key.
nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(aDocument->GetChannel());
if (jarChannel && jarChannel->GetIsUnsafe()) {
xpc::Scriptability::Get(newInnerWindow->mJSObject).Block();
xpc::Scriptability::Get(newInnerGlobal).Block();
}
if (mArguments) {
@ -2619,7 +2632,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// We wait to fire the debugger hook until the window is all set up and hooked
// up with the outer. See bug 969156.
if (createdInnerWindow) {
JS::Rooted<JSObject*> global(cx, newInnerWindow->mJSObject);
JS::Rooted<JSObject*> global(cx, newInnerWindow->GetWrapper());
JS_FireOnNewGlobalObject(cx, global);
}
@ -2788,8 +2801,7 @@ nsGlobalWindow::DetachFromDocShell()
// DetachFromDocShell means the window is being torn down. Drop our
// reference to the script context, allowing it to be deleted
// later. Meanwhile, keep our weak reference to the script object
// (mJSObject) so that it can be retrieved later (until it is
// finalized by the JS GC).
// so that it can be retrieved later (until it is finalized by the JS GC).
NS_ASSERTION(mTimeouts.isEmpty(), "Uh, outer window holds timeouts!");
@ -3212,20 +3224,12 @@ nsGlobalWindow::DispatchDOMEvent(WidgetEvent* aEvent,
aEventStatus);
}
void
nsGlobalWindow::OnFinalize(JSObject* aObject)
{
if (aObject == mJSObject) {
mJSObject = nullptr;
}
}
void
nsGlobalWindow::PoisonOuterWindowProxy(JSObject *aObject)
{
MOZ_ASSERT(IsOuterWindow());
if (aObject == mJSObject) {
mJSObject.setToCrashOnTouch();
if (aObject == GetWrapperPreserveColor()) {
PoisonWrapper();
}
}
@ -3273,7 +3277,7 @@ nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
AutoPushJSContext cx(ctx->GetNativeContext());
NS_ENSURE_TRUE(cx, NS_ERROR_NOT_INITIALIZED);
JS::Rooted<JSObject*> obj(cx, mJSObject);
JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
return GetContextInternal()->SetProperty(obj, "arguments", aArguments);
}
@ -4389,10 +4393,10 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* 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,
// wapped into the current compartment so that for Xrays we define on the 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.
// wrapped into the current compartment so that for Xrays we define on the
// 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);
@ -4413,8 +4417,8 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener, ErrorResult& aError)
return;
}
JS::Rooted<JSObject*> thisObj(cx, mJSObject);
if (!mJSObject) {
JS::Rooted<JSObject*> thisObj(cx, GetWrapperPreserveColor());
if (!thisObj) {
aError.Throw(NS_ERROR_UNEXPECTED);
return;
}
@ -5098,8 +5102,8 @@ nsGlobalWindow::RequestAnimationFrame(const nsIDocument::FrameRequestCallbackHol
return 0;
}
if (mJSObject) {
js::NotifyAnimationActivity(mJSObject);
if (GetWrapperPreserveColor()) {
js::NotifyAnimationActivity(GetWrapperPreserveColor());
}
int32_t handle;
@ -5660,7 +5664,7 @@ nsGlobalWindow::DispatchResizeEvent(const nsIntSize& aSize)
}
AutoSafeJSContext cx;
JSAutoCompartment ac(cx, mJSObject);
JSAutoCompartment ac(cx, GetWrapperPreserveColor());
DOMWindowResizeEventDetail detail;
detail.mWidth = aSize.width;
detail.mHeight = aSize.height;
@ -5697,7 +5701,7 @@ nsGlobalWindow::RefreshCompartmentPrincipal()
{
FORWARD_TO_INNER(RefreshCompartmentPrincipal, (), /* void */ );
JS_SetCompartmentPrincipals(js::GetObjectCompartment(mJSObject),
JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
nsJSPrincipals::get(mDoc->NodePrincipal()));
}
@ -8655,10 +8659,7 @@ nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
{
if (!mCachedXBLPrototypeHandlers) {
mCachedXBLPrototypeHandlers = new nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>();
}
if (!mCachedXBLPrototypeHandlers->Count()) {
mozilla::HoldJSObjects(this);
PreserveWrapper(ToSupports(this));
}
mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
@ -10407,6 +10408,12 @@ nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
}
JS::Value
nsGlobalWindow::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aError)
{
return dom::GetInterface(aCx, this, aIID, aError);
}
void
nsGlobalWindow::FireOfflineStatusEvent()
{
@ -12540,7 +12547,7 @@ nsGlobalWindow::SaveWindowState()
{
NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
if (!mContext || !mJSObject) {
if (!mContext || !GetWrapperPreserveColor()) {
// The window may be getting torn down; don't bother saving state.
return nullptr;
}
@ -12570,7 +12577,7 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState)
{
NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
if (!mContext || !mJSObject) {
if (!mContext || !GetWrapperPreserveColor()) {
// The window may be getting torn down; don't bother restoring state.
return NS_OK;
}
@ -13421,13 +13428,9 @@ nsGlobalWindow::GetMessageManager(ErrorResult& aError)
// nsGlobalModalWindow implementation
// QueryInterface implementation for nsGlobalModalWindow
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(nsGlobalModalWindow,
nsGlobalWindow,
mReturnValue)
DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)
NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
@ -13436,6 +13439,25 @@ NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
JS::Value
nsGlobalWindow::GetDialogArguments(JSContext* aCx, ErrorResult& aError)
{
FORWARD_TO_OUTER_OR_THROW(GetDialogArguments, (aCx, aError), aError,
JS::UndefinedValue());
MOZ_ASSERT(IsModalContentWindow(),
"This should only be called on modal windows!");
// This does an internal origin check, and returns undefined if the subject
// does not subsumes the origin of the arguments.
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
JSAutoCompartment ac(aCx, wrapper);
JS::Rooted<JS::Value> args(aCx);
mDialogArguments->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
&args, aError);
return args;
}
NS_IMETHODIMP
nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
{
@ -13447,6 +13469,25 @@ nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
return mDialogArguments->Get(nsContentUtils::GetSubjectPrincipal(), aArguments);
}
JS::Value
nsGlobalWindow::GetReturnValue(JSContext* aCx, ErrorResult& aError)
{
FORWARD_TO_OUTER_OR_THROW(GetReturnValue, (aCx, aError), aError,
JS::UndefinedValue());
MOZ_ASSERT(IsModalContentWindow(),
"This should only be called on modal windows!");
JS::Rooted<JS::Value> returnValue(aCx);
if (mReturnValue) {
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
JSAutoCompartment ac(aCx, wrapper);
mReturnValue->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
&returnValue, aError);
}
return returnValue;
}
NS_IMETHODIMP
nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
{
@ -13461,6 +13502,27 @@ nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
return mReturnValue->Get(nsContentUtils::GetSubjectPrincipal(), aRetVal);
}
void
nsGlobalWindow::SetReturnValue(JSContext* aCx,
JS::Handle<JS::Value> aReturnValue,
ErrorResult& aError)
{
FORWARD_TO_OUTER_OR_THROW(SetReturnValue, (aCx, aReturnValue, aError),
aError, );
MOZ_ASSERT(IsModalContentWindow(),
"This should only be called on modal windows!");
nsCOMPtr<nsIVariant> returnValue;
aError =
nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue,
getter_AddRefs(returnValue));
if (!aError.Failed()) {
mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
returnValue);
}
}
NS_IMETHODIMP
nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
{
@ -13471,6 +13533,20 @@ nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
return NS_OK;
}
/* static */
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();
}
NS_IMETHODIMP
nsGlobalWindow::GetConsole(JSContext* aCx,
JS::MutableHandle<JS::Value> aConsole)
@ -13481,8 +13557,8 @@ nsGlobalWindow::GetConsole(JSContext* aCx,
return rv.ErrorCode();
}
JS::Rooted<JSObject*> thisObj(aCx, mJSObject);
if (!mJSObject) {
JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
if (!thisObj) {
return NS_ERROR_UNEXPECTED;
}
@ -13497,8 +13573,8 @@ nsGlobalWindow::GetConsole(JSContext* aCx,
NS_IMETHODIMP
nsGlobalWindow::SetConsole(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
JS::Rooted<JSObject*> thisObj(aCx, mJSObject);
if (!mJSObject) {
JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
if (!thisObj) {
return NS_ERROR_UNEXPECTED;
}

Просмотреть файл

@ -84,6 +84,7 @@ class nsIDOMCrypto;
class nsIDOMOfflineResourceList;
class nsIScrollableFrame;
class nsIControllers;
class nsIJSID;
class nsIScriptContext;
class nsIScriptTimeoutHandler;
class nsIWebBrowserChrome;
@ -277,6 +278,16 @@ public:
result.forget(aResult);
return NS_OK;
}
void Get(JSContext* aCx, JS::Handle<JSObject*> aScope, nsIPrincipal* aSubject,
JS::MutableHandle<JS::Value> aResult, mozilla::ErrorResult& aError)
{
if (aSubject->Subsumes(mOrigin)) {
aError = nsContentUtils::XPConnect()->VariantToJS(aCx, aScope,
mValue, aResult);
} else {
aResult.setUndefined();
}
}
virtual ~DialogValueHolder() {}
private:
nsCOMPtr<nsIPrincipal> mOrigin;
@ -348,8 +359,9 @@ public:
// nsIScriptGlobalObject
JSObject *FastGetGlobalJSObject() const
{
return mJSObject;
return GetWrapperPreserveColor();
}
void TraceGlobalJSObject(JSTracer* aTrc);
virtual nsresult EnsureScriptEnvironment();
@ -357,10 +369,11 @@ public:
virtual nsIScriptContext *GetScriptContext();
void PoisonOuterWindowProxy(JSObject *aObject);
virtual void OnFinalize(JSObject* aObject);
virtual bool IsBlackForCC(bool aTracingNeeded = true);
static JSObject* OuterObject(JSContext* aCx, JS::HandleObject aObj);
// nsIScriptObjectPrincipal
virtual nsIPrincipal* GetPrincipal();
@ -581,6 +594,9 @@ public:
return mIsChrome;
}
using nsPIDOMWindow::IsModalContentWindow;
static bool IsModalContentWindow(JSContext* aCx, JSObject* aGlobal);
// GetScrollFrame does not flush. Callers should do it themselves as needed,
// depending on which info they actually want off the scrollable frame.
nsIScrollableFrame *GetScrollFrame();
@ -982,6 +998,14 @@ public:
mozilla::dom::Element* aPanel,
mozilla::ErrorResult& aError);
JS::Value GetDialogArguments(JSContext* aCx, mozilla::ErrorResult& aError);
JS::Value GetReturnValue(JSContext* aCx, mozilla::ErrorResult& aError);
void SetReturnValue(JSContext* aCx, JS::Handle<JS::Value> aReturnValue,
mozilla::ErrorResult& aError);
JS::Value GetInterface(JSContext* aCx, nsIJSID* aIID,
mozilla::ErrorResult& aError);
protected:
// Array of idle observers that are notified of idle events.
nsTObserverArray<IdleObserverHolder> mIdleObservers;
@ -1440,6 +1464,9 @@ protected:
// For |window.dialogArguments|, via |showModalDialog|.
nsRefPtr<DialogValueHolder> mDialogArguments;
// Only used in the outer.
nsRefPtr<DialogValueHolder> mReturnValue;
nsRefPtr<mozilla::dom::Navigator> mNavigator;
nsRefPtr<nsScreen> mScreen;
nsRefPtr<nsDOMWindowList> mFrames;
@ -1485,9 +1512,6 @@ protected:
// These member variables are used on both inner and the outer windows.
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
// The JS global object. Global objects are always allocated tenured.
JS::TenuredHeap<JSObject*> mJSObject;
typedef nsCOMArray<nsIDOMStorageEvent> nsDOMStorageEventArray;
nsDOMStorageEventArray mPendingStorageEvents;
@ -1639,12 +1663,6 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMMODALCONTENTWINDOW
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
protected:
// For use by outer windows only.
nsRefPtr<DialogValueHolder> mReturnValue;
};
/* factory function */

Просмотреть файл

@ -33,8 +33,8 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
#define NS_ISCRIPTGLOBALOBJECT_IID \
{ 0x6995e1ff, 0x9fc5, 0x44a7, \
{ 0xbd, 0x7c, 0xe7, 0xcd, 0x44, 0x47, 0x22, 0x87 } }
{ 0x876f83bd, 0x6314, 0x460a, \
{ 0xa0, 0x45, 0x1c, 0x8f, 0x46, 0x2f, 0xb8, 0xe1 } }
/**
* The global object which keeps a script context for each supported script
@ -67,15 +67,6 @@ public:
return GetScriptContext();
}
/**
* Called when the global script for a language is finalized, typically as
* part of its GC process. By the time this call is made, the
* nsIScriptContext for the language has probably already been removed.
* After this call, the passed object is dead - which should generally be the
* same object the global is using for a global for that language.
*/
virtual void OnFinalize(JSObject* aObject) = 0;
/**
* Handle a script error. Generally called by a script context.
*/

Просмотреть файл

@ -11,8 +11,8 @@
#include "js/Id.h" // must come before js/RootingAPI.h
#include "js/Value.h" // must come before js/RootingAPI.h
#include "js/RootingAPI.h"
#include "js/Tracer.h"
struct JSTracer;
class XPCWrappedNativeScope;
#define NS_WRAPPERCACHE_IID \
@ -222,6 +222,21 @@ public:
void ReleaseWrapper(void* aScriptObjectHolder);
protected:
void TraceWrapper(JSTracer* aTrc, const char* name)
{
if (mWrapper) {
JS_CallHeapObjectTracer(aTrc, &mWrapper, name);
}
}
void PoisonWrapper()
{
if (mWrapper) {
mWrapper.setToCrashOnTouch();
}
}
private:
JSObject *GetWrapperJSObject() const
{

Просмотреть файл

@ -25,10 +25,6 @@
class nsWrapperCache;
// nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't
// try to use it without fixing that first.
class nsGlobalWindow;
namespace mozilla {
namespace dom {
@ -442,12 +438,6 @@ GetWrapperCache(nsWrapperCache* cache)
return cache;
}
inline nsWrapperCache*
GetWrapperCache(nsGlobalWindow*)
{
return nullptr;
}
inline nsWrapperCache*
GetWrapperCache(void* p)
{

Просмотреть файл

@ -815,13 +815,20 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
// Get the object. It might be a security wrapper, in which case we do a checked
// unwrap.
JS::Rooted<JSObject*> origObj(cx, &thisv.toObject());
JSObject* obj = js::CheckedUnwrap(origObj);
JSObject* obj = js::CheckedUnwrap(origObj, /* stopAtOuter = */ false);
if (!obj) {
JS_ReportError(cx, "Permission denied to access object");
return false;
}
nsISupports* native = UnwrapDOMObjectToISupports(obj);
// Switch this to UnwrapDOMObjectToISupports once our global objects are
// using new bindings.
JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*obj));
nsISupports* native = nullptr;
nsCOMPtr<nsISupports> nativeRef;
xpc_qsUnwrapArg<nsISupports>(cx, val, &native,
static_cast<nsISupports**>(getter_AddRefs(nativeRef)),
&val);
if (!native) {
return Throw(cx, NS_ERROR_FAILURE);
}
@ -862,6 +869,29 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
return true;
}
JS::Value
GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
nsWrapperCache* aCache, nsIJSID* aIID, ErrorResult& aError)
{
const nsID* iid = aIID->GetID();
nsRefPtr<nsISupports> result;
aError = aRequestor->GetInterface(*iid, getter_AddRefs(result));
if (aError.Failed()) {
return JS::NullValue();
}
JS::Rooted<JSObject*> wrapper(aCx, aCache->GetWrapper());
JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(wrapper));
JS::Rooted<JS::Value> v(aCx, JSVAL_NULL);
if (!WrapObject(aCx, global, result, iid, &v)) {
aError.Throw(NS_ERROR_FAILURE);
return JS::NullValue();
}
return v;
}
bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
{

Просмотреть файл

@ -34,6 +34,7 @@
#include "nsWrapperCacheInlines.h"
class nsIJSID;
class nsPIDOMWindow;
extern nsresult
@ -1606,6 +1607,17 @@ WantsQueryInterface
}
};
JS::Value
GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
nsWrapperCache* aCache, nsIJSID* aIID, ErrorResult& aError);
template<class T>
JS::Value
GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID, ErrorResult& aError)
{
return GetInterfaceImpl(aCx, aThis, aThis, aIID, aError);
}
bool
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);

Просмотреть файл

@ -53,7 +53,8 @@ def isTypeCopyConstructible(type):
def wantsAddProperty(desc):
return (desc.concrete and
desc.wrapperCache and
not desc.interface.getExtendedAttribute("Global"))
not (desc.workers and
desc.interface.getExtendedAttribute("Global")))
# We'll want to insert the indent at the beginnings of lines, but we
@ -330,9 +331,46 @@ class CGDOMJSClass(CGThing):
callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
classFlags = "JSCLASS_IS_DOMJSCLASS | "
classExtensionAndObjectOps = """\
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
"""
if self.descriptor.interface.getExtendedAttribute("Global"):
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
traceHook = "JS_GlobalObjectTraceHook"
if not self.descriptor.workers:
classExtensionAndObjectOps = """\
{
nsGlobalWindow::OuterObject, /* outerObject */
nullptr, /* innerObject */
nullptr, /* iteratorObject */
false, /* isWrappedNative */
nullptr /* weakmapKeyDelegateOp */
},
{
nullptr, /* lookupGeneric */
nullptr, /* lookupProperty */
nullptr, /* lookupElement */
nullptr, /* defineGeneric */
nullptr, /* defineProperty */
nullptr, /* defineElement */
nullptr, /* getGeneric */
nullptr, /* getProperty */
nullptr, /* getElement */
nullptr, /* setGeneric */
nullptr, /* setProperty */
nullptr, /* setElement */
nullptr, /* getGenericAttributes */
nullptr, /* setGenericAttributes */
nullptr, /* deleteProperty */
nullptr, /* deleteElement */
nullptr, /* watch */
nullptr, /* unwatch */
nullptr, /* slice */
nullptr, /* enumerate */
JS_ObjectToOuterObject /* thisObject */
}
"""
else:
classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
@ -366,8 +404,7 @@ class CGDOMJSClass(CGThing):
nullptr, /* construct */
${trace}, /* trace */
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
$*{classExtensionAndObjectOps}
},
$*{descriptor}
};
@ -380,6 +417,7 @@ class CGDOMJSClass(CGThing):
finalize=FINALIZE_HOOK_NAME,
call=callHook,
trace=traceHook,
classExtensionAndObjectOps=classExtensionAndObjectOps,
descriptor=DOMClass(self.descriptor))

Просмотреть файл

@ -29,6 +29,7 @@ const CONTACTS_SENDMORE_MINIMUM = 5;
// Keep in sync with the interfaces.
const PROPERTIES = [
"name", "honorificPrefix", "givenName", "additionalName", "familyName",
"phoneticGivenName", "phoneticFamilyName",
"honorificSuffix", "nickname", "photo", "category", "org", "jobTitle",
"bday", "note", "anniversary", "sex", "genderIdentity", "key", "adr", "email",
"url", "impp", "tel"

Просмотреть файл

@ -22,7 +22,7 @@ Cu.importGlobalProperties(["indexedDB"]);
/* all exported symbols need to be bound to this on B2G - Bug 961777 */
this.DB_NAME = "contacts";
this.DB_VERSION = 19;
this.DB_VERSION = 20;
this.STORE_NAME = "contacts";
this.SAVED_GETALL_STORE_NAME = "getallcache";
const CHUNK_SIZE = 20;
@ -169,6 +169,10 @@ ContactDB.prototype = {
objectStore.createIndex("category", "properties.category", { multiEntry: true });
objectStore.createIndex("email", "search.email", { multiEntry: true });
objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenNameLowerCase", "search.phoneticGivenName", { multiEntry: true });
aDb.createObjectStore(SAVED_GETALL_STORE_NAME);
aDb.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
}
@ -705,6 +709,17 @@ ContactDB.prototype = {
next();
},
function upgrade19to20() {
if (DEBUG) debug("upgrade19to20 create schema(phonetic)");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenNameLowerCase", "search.phoneticGivenName", { multiEntry: true });
next();
},
];
let index = aOldVersion;
@ -824,6 +839,8 @@ ContactDB.prototype = {
tel: [],
exactTel: [],
parsedTel: [],
phoneticFamilyName: [],
phoneticGivenName: [],
};
for (let field in aContact.properties) {
@ -1115,6 +1132,21 @@ ContactDB.prototype = {
}, null, aErrorCb);
},
getSortByParam: function CDB_getSortByParam(aFindOptions) {
switch (aFindOptions.sortBy) {
case "familyName":
return [ "familyName", "givenName" ];
case "givenName":
return [ "givenName" , "familyName" ];
case "phoneticFamilyName":
return [ "phoneticFamilyName" , "phoneticGivenName" ];
case "phoneticGivenName":
return [ "phoneticGivenName" , "phoneticFamilyName" ];
default:
return [ "givenName" , "familyName" ];
}
},
/*
* Sorting the contacts by sortBy field. aSortBy can either be familyName or givenName.
* If 2 entries have the same sortyBy field or no sortBy field is present, we continue
@ -1125,7 +1157,7 @@ ContactDB.prototype = {
return;
if (aFindOptions.sortBy != "undefined") {
const sortOrder = aFindOptions.sortOrder;
const sortBy = aFindOptions.sortBy == "familyName" ? [ "familyName", "givenName" ] : [ "givenName" , "familyName" ];
const sortBy = this.getSortByParam(aFindOptions);
aResults.sort(function (a, b) {
let x, y;

Просмотреть файл

@ -90,6 +90,8 @@ var properties1 = {
name: ["Test1 TestFamilyName", "Test2 Wagner"],
familyName: ["TestFamilyName","Wagner"],
givenName: ["Test1","Test2"],
phoneticFamilyName: ["TestphoneticFamilyName1","TestphoneticFamilyName2"],
phoneticGivenName: ["TestphoneticGivenName1","TestphoneticGivenName2"],
nickname: ["nicktest"],
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
adr: [adr1],
@ -100,6 +102,8 @@ var properties2 = {
name: ["dummyHonorificPrefix dummyGivenName dummyFamilyName dummyHonorificSuffix", "dummyHonorificPrefix2"],
familyName: ["dummyFamilyName"],
givenName: ["dummyGivenName"],
phoneticFamilyName: ["dummyphoneticFamilyName"],
phoneticGivenName: ["dummyphoneticGivenName"],
honorificPrefix: ["dummyHonorificPrefix","dummyHonorificPrefix2"],
honorificSuffix: ["dummyHonorificSuffix"],
additionalName: ["dummyadditionalName"],
@ -120,6 +124,86 @@ var properties2 = {
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
};
// To test sorting(CJK)
var c9 = {
phoneticFamilyName: ["a"],
phoneticGivenName: ["a"],
};
var c10 = {
phoneticFamilyName: ["b"],
phoneticGivenName: ["b"],
};
var c11 = {
phoneticFamilyName: ["c","a","b"],
phoneticGivenName: ["c","a","b"],
};
var c12 = {
phoneticFamilyName: ["c","a","c"],
phoneticGivenName: ["c","a","c"],
};
var c13 = {
phoneticFamilyName: [],
phoneticGivenName: [],
};
var c14 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var c15 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var c16 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var properties3 = {
// please keep capital letters at the start of these names
name: ["Taro Yamada", "Ichiro Suzuki"],
familyName: ["Yamada","Suzuki"],
givenName: ["Taro","Ichiro"],
phoneticFamilyName: ["TestPhoneticFamilyYamada","TestPhoneticFamilySuzuki"],
phoneticGivenName: ["TestPhoneticGivenTaro","TestPhoneticGivenIchiro"],
nickname: ["phoneticNicktest"],
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
adr: [adr1],
email: [{type: ["work"], value: "x@y.com"}],
};
var properties4 = {
name: ["dummyHonorificPrefix dummyTaro dummyYamada dummyHonorificSuffix", "dummyHonorificPrefix2"],
familyName: ["dummyYamada"],
givenName: ["dummyTaro"],
phoneticFamilyName: ["dummyTestPhoneticFamilyYamada"],
phoneticGivenName: ["dummyTestPhoneticGivenTaro"],
honorificPrefix: ["dummyPhoneticHonorificPrefix","dummyPhoneticHonorificPrefix2"],
honorificSuffix: ["dummyPhoneticHonorificSuffix"],
additionalName: ["dummyPhoneticAdditionalName"],
nickname: ["dummyPhoneticNickname"],
tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
adr: [adr1, adr2],
impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
org: ["org1", "org2"],
jobTitle: ["boss", "superboss"],
note: ["test note"],
category: ["cat1", "cat2"],
url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
bday: new Date("1980, 12, 01"),
anniversary: new Date("2000, 12, 01"),
sex: "male",
genderIdentity: "test",
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
};
var sample_id1;
var sample_id2;
@ -265,6 +349,8 @@ function checkContacts(contact1, contact2) {
checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
checkStrArray(contact1.phoneticFamilyName, contact2.phoneticFamilyName, "Same phoneticFamilyName");
checkStrArray(contact1.phoneticGivenName, contact2.phoneticGivenName, "Same phoneticGivenName");
checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
checkCategory(contact1.category, contact2.category);

Просмотреть файл

@ -745,6 +745,8 @@ var steps = [
name: [],
familyName: [],
givenName: [],
phoneticFamilyName: [],
phoneticGivenName: [],
nickname: [],
tel: [],
adr: [],
@ -825,6 +827,301 @@ var steps = [
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact");
createResult1 = new mozContact(properties3);
req = mozContacts.save(createResult1)
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact2");
createResult2 = new mozContact(properties4);
req = mozContacts.save(createResult2);
req.onsuccess = function () {
ok(createResult2.id, "The contact now has an ID.");
sample_id2 = createResult2.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({sortBy: "phoneticFamilyName"});
req.onsuccess = function () {
is(req.result.length, 2, "Found exactly 2 contact.");
checkContacts(req.result[1], properties3);
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Searching contacts by query1");
var options = {filterBy: ["phoneticGivenName", "email"],
filterOp: "startsWith",
filterValue: properties3.phoneticGivenName[0].substring(0, 3)}
req = mozContacts.find(options)
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, createResult1);
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Searching contacts by query2");
var options = {filterBy: ["phoneticGivenName", "email"],
filterOp: "startsWith",
filterValue: properties4.phoneticGivenName[0].substring(0, 3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.adr.length, 2, "Adr length 2");
checkContacts(findResult1, createResult2);
next();
}
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Adding 20 contacts");
for (var i=0; i<19; i++) {
createResult1 = new mozContact(properties3);
req = mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
};
req.onerror = onFailure;
};
createResult1 = new mozContact(properties3);
req = mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkStrArray(createResult1.name, properties3.name, "Same Name");
checkCount(20, "20 contacts in DB", next);
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find(defaultOptions);
req.onsuccess = function () {
is(req.result.length, 20, "20 Entries.");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts2");
var options = {filterBy: ["phoneticGivenName"],
filterOp: "startsWith",
filterValue: properties3.phoneticGivenName[0].substring(0, 3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 20, "20 Entries.");
checkContacts(createResult1, req.result[19]);
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts3");
var options = {filterBy: ["phoneticGivenName", "tel", "email"],
filterOp: "startsWith",
filterValue: properties3.phoneticGivenName[0].substring(0, 3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 20, "20 Entries.");
checkContacts(createResult1, req.result[10]);
next();
}
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Testing clone contact");
createResult1 = new mozContact(properties3);
req = mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkStrArray(createResult1.phoneticFamilyName, properties3.phoneticFamilyName, "Same phoneticFamilyName");
checkStrArray(createResult1.phoneticGivenName, properties3.phoneticGivenName, "Same phoneticGivenName");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({sortBy: "phoneticGivenName"});
req.onsuccess = function () {
is(req.result.length, 1, "1 Entries.");
next();
}
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c11);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c11, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c10);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c10, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c12);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c12, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c9);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c9, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "ascending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 4, "4 results");
checkContacts(req.result[0], c9);
checkContacts(req.result[1], c10);
checkContacts(req.result[2], c11);
checkContacts(req.result[3], c12);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "descending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 4, "4 results");
checkContacts(req.result[0], c12);
checkContacts(req.result[1], c11);
checkContacts(req.result[2], c10);
checkContacts(req.result[3], c9);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c13);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c13, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting with empty string");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "ascending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 5, "5 results");
checkContacts(req.result[0], c13);
checkContacts(req.result[1], c9);
checkContacts(req.result[2], c10);
checkContacts(req.result[3], c11);
checkContacts(req.result[4], c12);
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c15);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c15, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c14);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c14, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c16);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c16, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
// Android does not support published/updated fields. Skip this.
if (isAndroid) {
next();
return;
}
ok(true, "Test sorting with published");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "descending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 3, "3 results");
ok(req.result[0].published < req.result[1].published, "Right sorting order");
ok(req.result[1].published < req.result[2].published, "Right sorting order");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "all done!\n");
SimpleTest.finish();

Просмотреть файл

@ -13,10 +13,7 @@ var gGotNotHandlingDrop = false;
SimpleTest.waitForExplicitFinish();
function fireEvent(target, event) {
var utils =
window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
SpecialPowers.wrap(utils).dispatchDOMEventViaPresShell(target, event, true);
SpecialPowers.DOMWindowUtils.dispatchDOMEventViaPresShell(target, event, true);
}
function fireDrop(element, shouldAllowDrop, shouldAllowOnlyChromeDrop) {

Просмотреть файл

@ -10,6 +10,9 @@ const notificationID = "indexedDB-permissions-prompt";
function test()
{
waitForExplicitFinish();
PopupNotifications.transitionsEnabled = false;
// We want a prompt.
setPermission(testPageURL, "indexedDB", "allow");
executeSoon(test1);
@ -69,6 +72,7 @@ function test2()
gBrowser.removeCurrentTab();
unregisterAllPopupEventHandlers();
removePermission(testPageURL, "indexedDB");
PopupNotifications.transitionsEnabled = true;
executeSoon(finish);
});

Просмотреть файл

@ -11,6 +11,7 @@ function test()
{
waitForExplicitFinish();
// We want the prompt.
PopupNotifications.transitionsEnabled = false;
setPermission(testPageURL, "indexedDB", "allow");
executeSoon(test1);
}
@ -68,6 +69,7 @@ function test2()
gBrowser.selectedBrowser.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing = false;
unregisterAllPopupEventHandlers();
gBrowser.removeCurrentTab();
PopupNotifications.transitionsEnabled = true;
executeSoon(test3);
});

Просмотреть файл

@ -12,6 +12,7 @@ function test()
{
waitForExplicitFinish();
requestLongerTimeout(10);
PopupNotifications.transitionsEnabled = false;
removePermission(testPageURL, "indexedDB-unlimited");
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
executeSoon(test1);
@ -108,6 +109,7 @@ function test2()
unregisterAllPopupEventHandlers();
removePermission(testPageURL, "indexedDB");
Services.prefs.clearUserPref("dom.indexedDB.warningQuota");
PopupNotifications.transitionsEnabled = true;
executeSoon(finish);
});
executeSoon(function() { dispatchEvent("indexedDB-done"); });

Просмотреть файл

@ -12,6 +12,7 @@ function test()
{
waitForExplicitFinish();
requestLongerTimeout(10);
PopupNotifications.transitionsEnabled = false;
removePermission(testPageURL, "indexedDB-unlimited");
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
executeSoon(test1);
@ -43,6 +44,7 @@ function test1()
gBrowser.removeCurrentTab();
unregisterAllPopupEventHandlers();
addMoreTest1Count = seenPopupCount;
PopupNotifications.transitionsEnabled = true;
executeSoon(finish);
});
executeSoon(function() { dispatchEvent("indexedDB-done"); });

Просмотреть файл

@ -12,6 +12,7 @@ function test()
{
waitForExplicitFinish();
requestLongerTimeout(10);
PopupNotifications.transitionsEnabled = false;
removePermission(testPageURL, "indexedDB-unlimited");
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
executeSoon(test1);
@ -54,6 +55,7 @@ function test1()
"Correct permission set");
gBrowser.removeCurrentTab();
unregisterAllPopupEventHandlers();
PopupNotifications.transitionsEnabled = true;
executeSoon(finish);
});
executeSoon(function() { dispatchEvent("indexedDB-done"); });

Просмотреть файл

@ -12,6 +12,7 @@ function test()
{
waitForExplicitFinish();
requestLongerTimeout(10);
PopupNotifications.transitionsEnabled = false;
removePermission(testPageURL, "indexedDB-unlimited");
Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
executeSoon(test1);
@ -48,6 +49,7 @@ function test1()
gBrowser.removeCurrentTab();
unregisterAllPopupEventHandlers();
addMoreTest1Count = seenPopupCount;
PopupNotifications.transitionsEnabled = true;
executeSoon(test2);
});
executeSoon(function() { dispatchEvent("indexedDB-done"); });

Просмотреть файл

@ -43,8 +43,7 @@ var ConsoleObserver = {
// Close the window.
gBrowser.removeTab(tab, {animate: false});
// Ensure actual window destruction is not delayed (too long).
window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
SpecialPowers.DOMWindowUtils.garbageCollect();
// Ensure "inner-window-destroyed" event is processed,
// so the storage cache is cleared.
executeSoon(function () {

Просмотреть файл

@ -135,10 +135,7 @@ function messageReceiver(evt) {
function handleTestEnd() {
function gc() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.garbageCollect();
SpecialPowers.DOMWindowUtils.garbageCollect();
}
if (numTestsSet1) {
if (!--numTestsSet1) {

Просмотреть файл

@ -22,8 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=397571
/** Test for Bug 397571 **/
// Get the interface
var utils = window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
var utils = SpecialPowers.DOMWindowUtils.SpecialPowers_wrappedObject;
// Try to call functions without privileges
var success = false;

Просмотреть файл

@ -4,7 +4,7 @@
<script>
function go() {
is(SpecialPowers.wrap(window).location.toString(), location.toString(), "sanity");
is(SpecialPowers.Cu.getClassName(window, /* aUnwrap = */ true), "ModalContentWindow", "We are modal");
ok("returnValue" in window && "dialogArguments" in window, "We are modal");
var iwin = document.getElementById('ifr').contentWindow;
is(SpecialPowers.Cu.getClassName(iwin, /* aUnwrap = */ true), "Window", "Descendant frames should not be modal");

Просмотреть файл

@ -1224,11 +1224,11 @@ function createInterfaceMap(isXBLScope) {
var interfaceMap = {};
function addInterfaces(interfaces, shouldExpect)
function addInterfaces(interfaces)
{
for (var entry of interfaces) {
if (typeof(entry) === "string") {
interfaceMap[entry] = shouldExpect;
interfaceMap[entry] = true;
} else if ((entry.nightly === !isNightly) ||
(entry.xbl === !isXBLScope) ||
(entry.desktop === !isDesktop) ||
@ -1238,13 +1238,19 @@ function createInterfaceMap(isXBLScope) {
(entry.permission && !hasPermission(entry.permission))) {
interfaceMap[entry.name] = false;
} else {
interfaceMap[entry.name] = shouldExpect;
interfaceMap[entry.name] = true;
}
}
}
addInterfaces(ecmaGlobals, true);
addInterfaces(interfaceNamesInGlobalScope, true);
addInterfaces(ecmaGlobals);
addInterfaces(interfaceNamesInGlobalScope);
if (isXBLScope) {
// We expose QueryInterface to XBL scopes. It's not an interface but we
// need to handle it because it's an own property of the global and the
// property name starts with an uppercase letter.
interfaceMap["QueryInterface"] = true;
}
return interfaceMap;
}

Просмотреть файл

@ -44,8 +44,10 @@ dictionary ContactProperties {
sequence<DOMString>? name;
sequence<DOMString>? honorificPrefix;
sequence<DOMString>? givenName;
sequence<DOMString>? phoneticGivenName;
sequence<DOMString>? additionalName;
sequence<DOMString>? familyName;
sequence<DOMString>? phoneticFamilyName;
sequence<DOMString>? honorificSuffix;
sequence<DOMString>? nickname;
sequence<DOMString>? category;
@ -81,8 +83,10 @@ interface mozContact {
[Cached, Pure] attribute sequence<DOMString>? name;
[Cached, Pure] attribute sequence<DOMString>? honorificPrefix;
[Cached, Pure] attribute sequence<DOMString>? givenName;
[Cached, Pure] attribute sequence<DOMString>? phoneticGivenName;
[Cached, Pure] attribute sequence<DOMString>? additionalName;
[Cached, Pure] attribute sequence<DOMString>? familyName;
[Cached, Pure] attribute sequence<DOMString>? phoneticFamilyName;
[Cached, Pure] attribute sequence<DOMString>? honorificSuffix;
[Cached, Pure] attribute sequence<DOMString>? nickname;
[Cached, Pure] attribute sequence<DOMString>? category;

Просмотреть файл

@ -86,6 +86,7 @@ TreeWalker implements LegacyQueryInterface;
UndoManager implements LegacyQueryInterface;
ValidityState implements LegacyQueryInterface;
WebSocket implements LegacyQueryInterface;
Window implements LegacyQueryInterface;
XMLHttpRequest implements LegacyQueryInterface;
XMLHttpRequestUpload implements LegacyQueryInterface;
XMLSerializer implements LegacyQueryInterface;

Просмотреть файл

@ -16,6 +16,7 @@
*/
interface ApplicationCache;
interface IID;
interface MozFrameRequestCallback;
interface nsIBrowserDOMWindow;
interface nsIMessageBroadcaster;
@ -225,6 +226,14 @@ interface SpeechSynthesisGetter {
Window implements SpeechSynthesisGetter;
#endif
// http://www.whatwg.org/specs/web-apps/current-work/
[NoInterfaceObject]
interface WindowModal {
[Throws, Func="nsGlobalWindow::IsModalContentWindow"] readonly attribute any dialogArguments;
[Throws, Func="nsGlobalWindow::IsModalContentWindow"] attribute any returnValue;
};
Window implements WindowModal;
// Mozilla-specific stuff
partial interface Window {
//[NewObject, Throws] CSSStyleDeclaration getDefaultComputedStyle(Element elt, optional DOMString pseudoElt = "");
@ -341,6 +350,8 @@ partial interface Window {
[Replaceable, Throws] readonly attribute object? content;
[ChromeOnly, Throws] readonly attribute object? __content;
[Throws, ChromeOnly] any getInterface(IID iid);
};
Window implements TouchEventHandlers;

Просмотреть файл

@ -22,7 +22,8 @@ var iframe = document.getElementById("load-frame");
function enableJS() allowJS(true, iframe);
function disableJS() allowJS(false, iframe);
function allowJS(allow, frame) {
SpecialPowers.wrap(frame.contentWindow.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor))
SpecialPowers.wrap(frame.contentWindow)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
.allowJavascript = allow;

Просмотреть файл

@ -36,7 +36,8 @@ function editDoc() {
function getSpellCheckSelection() {
var Ci = SpecialPowers.Ci;
var win = editDoc().defaultView;
var editingSession = SpecialPowers.wrap(win.QueryInterface(Ci.nsIInterfaceRequestor))
var editingSession = SpecialPowers.wrap(win)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession);

Просмотреть файл

@ -53,7 +53,8 @@ function runTest() {
editdoc.designMode='on';
// Hold the reference to the editor
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
editor = SpecialPowers.wrap(editframe)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession)
@ -72,7 +73,8 @@ function runTest() {
editdoc.body.contentEditable = true;
// Hold the reference to the editor
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
editor = SpecialPowers.wrap(editframe)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession)
@ -89,7 +91,8 @@ function runTest() {
editdoc.designMode = "off";
// Hold the reference to the editor
editor = SpecialPowers.wrap(editframe.QueryInterface(Ci.nsIInterfaceRequestor))
editor = SpecialPowers.wrap(editframe)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession)

Просмотреть файл

@ -48,6 +48,29 @@ CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize,
}
}
void
CopyBGRXSurfaceDataToPackedBGRArray(uint8_t* aSrc, uint8_t* aDst,
IntSize aSrcSize, int32_t aSrcStride)
{
int packedStride = aSrcSize.width * 3;
uint8_t* srcPx = aSrc;
uint8_t* dstPx = aDst;
for (int row = 0; row < aSrcSize.height; ++row) {
for (int col = 0; col < aSrcSize.height; ++col) {
dstPx[0] = srcPx[0];
dstPx[1] = srcPx[1];
dstPx[2] = srcPx[2];
// srcPx[3] (unused or alpha component) dropped on floor
srcPx += 4;
dstPx += 3;
}
srcPx = aSrc += aSrcStride;
dstPx = aDst += packedStride;
}
}
uint8_t*
SurfaceToPackedBGRA(DataSourceSurface *aSurface)
{
@ -82,5 +105,37 @@ SurfaceToPackedBGRA(DataSourceSurface *aSurface)
return imageBuffer;
}
uint8_t*
SurfaceToPackedBGR(DataSourceSurface *aSurface)
{
SurfaceFormat format = aSurface->GetFormat();
MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8, "Format not supported");
if (format != SurfaceFormat::B8G8R8X8) {
// To support B8G8R8A8 we'd need to un-pre-multiply alpha
return nullptr;
}
IntSize size = aSurface->GetSize();
uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * 3 * sizeof(uint8_t)];
if (!imageBuffer) {
return nullptr;
}
DataSourceSurface::MappedSurface map;
if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
delete [] imageBuffer;
return nullptr;
}
CopyBGRXSurfaceDataToPackedBGRArray(map.mData, imageBuffer, size,
map.mStride);
aSurface->Unmap();
return imageBuffer;
}
}
}

Просмотреть файл

@ -30,5 +30,17 @@ CopySurfaceDataToPackedArray(uint8_t* aSrc, uint8_t* aDst, IntSize aSrcSize,
uint8_t*
SurfaceToPackedBGRA(DataSourceSurface *aSurface);
/**
* Convert aSurface to a packed buffer in BGR format. The pixel data is
* returned in a buffer allocated with new uint8_t[].
*
* This function is currently only intended for use with surfaces of format
* SurfaceFormat::B8G8R8X8 since the X components of the pixel data are simply
* dropped (no attempt is made to un-pre-multiply alpha from the color
* components).
*/
uint8_t*
SurfaceToPackedBGR(DataSourceSurface *aSurface);
}
}

Просмотреть файл

@ -15,6 +15,7 @@
#include <X11/Xutil.h>
#include "mozilla/MathAlgorithms.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/X11Util.h"
#include "prenv.h"
@ -1188,15 +1189,21 @@ GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
return glContext.forget();
}
static nsRefPtr<GLContext> gGlobalContext;
// TODO move that out of static initializaion
static bool gUseContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
static StaticRefPtr<GLContext> gGlobalContext;
GLContext*
GLContextProviderGLX::GetGlobalContext()
{
static bool checkedContextSharing = false;
static bool useContextSharing = false;
if (!checkedContextSharing) {
useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
checkedContextSharing = true;
}
// TODO: get GLX context sharing to work well with multiple threads
if (!gUseContextSharing) {
if (!useContextSharing) {
return nullptr;
}
@ -1205,7 +1212,11 @@ GLContextProviderGLX::GetGlobalContext()
triedToCreateContext = true;
gfxIntSize dummySize = gfxIntSize(16, 16);
gGlobalContext = CreateOffscreenPixmapContext(dummySize);
// StaticPtr doesn't support assignments from already_AddRefed,
// so use a temporary nsRefPtr to make the reference counting
// fall out correctly.
nsRefPtr<GLContext> holder = CreateOffscreenPixmapContext(dummySize);
gGlobalContext = holder;
}
return gGlobalContext;

Просмотреть файл

@ -284,19 +284,26 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
RefPtr<TextureClient> result;
#if defined(MOZ_WIDGET_GONK) || defined(XP_WIN)
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
#endif
#ifdef XP_WIN
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
aSizeHint.width <= maxTextureSize &&
aSizeHint.height <= maxTextureSize &&
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
result = new TextureClientD3D11(aFormat, aTextureFlags);
}
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
aMoz2DBackend == gfx::BackendType::CAIRO &&
aAllocator->IsSameProcess() &&
aSizeHint.width <= maxTextureSize &&
aSizeHint.height <= maxTextureSize &&
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
@ -337,7 +344,6 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
if (!DisableGralloc(aFormat, aSizeHint)) {
// Don't allow Gralloc texture clients to exceed the maximum texture size.
// BufferTextureClients have code to handle tiling the surface client-side.
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
aTextureFlags);

Просмотреть файл

@ -173,6 +173,9 @@ TextureClientD3D11::~TextureClientD3D11()
bool
TextureClientD3D11::Lock(OpenMode aMode)
{
if (!mTexture) {
return false;
}
MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
LockD3DTexture(mTexture.get());
mIsLocked = true;
@ -190,6 +193,7 @@ void
TextureClientD3D11::Unlock()
{
MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
if (mDrawTarget) {
// see the comment on TextureClientDrawTarget::GetAsDrawTarget.
// This DrawTarget is internal to the TextureClient and is only exposed to the
@ -210,6 +214,10 @@ TextureClientD3D11::GetAsDrawTarget()
{
MOZ_ASSERT(mIsLocked, "Calling TextureClient::GetAsDrawTarget without locking :(");
if (!mTexture) {
return nullptr;
}
if (mDrawTarget) {
return mDrawTarget;
}
@ -224,7 +232,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
mSize = aSize;
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
CD3D10_TEXTURE2D_DESC newDesc(SurfaceFormatToDXGIFormat(mFormat),
CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
aSize.width, aSize.height, 1, 1,
D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
@ -332,10 +340,10 @@ DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
IntPoint* aSrcOffset)
{
// Right now we only support null aDestRegion and aSrcOffset (which means)
// full surface update. Incremental update is only used on Mac so it is
// not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
// Right now we only support full surface update. If aDestRegion is provided,
// It will be ignored. Incremental update with a source offset is only used
// on Mac so it is not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aSrcOffset);
MOZ_ASSERT(aSurface);
if (!mCompositor || !mCompositor->GetDevice()) {

Просмотреть файл

@ -376,10 +376,10 @@ DataTextureSourceD3D9::Update(gfx::DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
gfx::IntPoint* aSrcOffset)
{
// Right now we only support null aDestRegion and aSrcOffset (which means
// full surface update). Incremental update is only used on Mac so it is
// not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
// Right now we only support full surface update. If aDestRegion is provided,
// It will be ignored. Incremental update with a source offset is only used
// on Mac so it is not clear that we ever will need to support it for D3D.
MOZ_ASSERT(!aSrcOffset);
if (!mCompositor || !mCompositor->device()) {
NS_WARNING("No D3D device to update the texture.");

Просмотреть файл

@ -394,7 +394,6 @@ GrallocTextureHostOGL::GetAsSurface() {
TemporaryRef<gfx::DataSourceSurface>
GrallocTextureSourceOGL::GetAsSurface() {
MOZ_ASSERT(gl());
if (!IsValid()) {
return nullptr;
}

Просмотреть файл

@ -25,8 +25,7 @@ var layoutCSSBranch = prefService.getBranch("layout.css.");
var oldVal = layoutCSSBranch.getCharPref("devPixelsPerPx");
try {
var domWindowUtils = window.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIDOMWindowUtils);
var domWindowUtils = SpecialPowers.DOMWindowUtils;
var devPxPerCSSPx = domWindowUtils.screenPixelsPerCSSPixel;
layoutCSSBranch.setCharPref("devPixelsPerPx", "2");

Просмотреть файл

@ -351,6 +351,14 @@ gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
aLength);
}
gfxFontEntry*
gfxAndroidPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName)
{
return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,
aFontName);
}
TemporaryRef<ScaledFont>
gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
{

Просмотреть файл

@ -49,6 +49,8 @@ public:
virtual gfxPlatformFontList* CreatePlatformFontList();
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const uint8_t *aFontData, uint32_t aLength);
virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName);
virtual void GetCommonFallbackFonts(const uint32_t aCh,
int32_t aRunScript,

Просмотреть файл

@ -1386,7 +1386,7 @@ struct FullFontNameSearch {
{ }
nsString mFullName;
gfxFontEntry *mFontEntry;
FT2FontEntry *mFontEntry;
};
// callback called for each family name, based on the assumption that the
@ -1400,17 +1400,22 @@ FindFullName(nsStringHashKey::KeyType aKey,
// does the family name match up to the length of the family name?
const nsString& family = aFontFamily->Name();
nsString fullNameFamily;
data->mFullName.Left(fullNameFamily, family.Length());
// if so, iterate over faces in this family to see if there is a match
if (family.Equals(fullNameFamily)) {
if (family.Equals(fullNameFamily, nsCaseInsensitiveStringComparator())) {
nsTArray<nsRefPtr<gfxFontEntry> >& fontList = aFontFamily->GetFontList();
int index, len = fontList.Length();
for (index = 0; index < len; index++) {
if (fontList[index]->Name().Equals(data->mFullName)) {
data->mFontEntry = fontList[index];
gfxFontEntry* fe = fontList[index];
if (!fe) {
continue;
}
if (fe->Name().Equals(data->mFullName,
nsCaseInsensitiveStringComparator())) {
data->mFontEntry = static_cast<FT2FontEntry*>(fe);
return PL_DHASH_STOP;
}
}
@ -1428,7 +1433,32 @@ gfxFT2FontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
mFontFamilies.Enumerate(FindFullName, &data);
return data.mFontEntry;
if (!data.mFontEntry) {
return nullptr;
}
// Clone the font entry so that we can then set its style descriptors
// from the proxy rather than the actual font.
// Ensure existence of mFTFace in the original entry
data.mFontEntry->CairoFontFace();
if (!data.mFontEntry->mFTFace) {
return nullptr;
}
FT2FontEntry* fe =
FT2FontEntry::CreateFontEntry(data.mFontEntry->mFTFace,
data.mFontEntry->mFilename.get(),
data.mFontEntry->mFTFontIndex,
data.mFontEntry->Name(), nullptr);
if (fe) {
fe->mItalic = aProxyEntry->mItalic;
fe->mWeight = aProxyEntry->mWeight;
fe->mStretch = aProxyEntry->mStretch;
fe->mIsUserFont = fe->mIsLocalUserFont = true;
}
return fe;
}
gfxFontFamily*

Просмотреть файл

@ -7,6 +7,8 @@
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "gfxDrawable.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "nsRegion.h"
#include "yuv_convert.h"
#include "ycbcr_to_rgb565.h"
@ -848,6 +850,76 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData,
}
}
/* static */ TemporaryRef<DataSourceSurface>
gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
SurfaceFormat aFormat)
{
MOZ_ASSERT(aFormat != aSurface->GetFormat(),
"Unnecessary - and very expersive - surface format conversion");
Rect bounds(0, 0, aSurface->GetSize().width, aSurface->GetSize().height);
if (aSurface->GetType() != SurfaceType::DATA) {
// If the surface is NOT of type DATA then its data is not mapped into main
// memory. Format conversion is probably faster on the GPU, and by doing it
// there we can avoid any expensive uploads/readbacks except for (possibly)
// a single readback due to the unavoidable GetDataSurface() call. Using
// CreateOffscreenContentDrawTarget ensures the conversion happens on the
// GPU.
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(aSurface->GetSize(), aFormat);
// Using DrawSurface() here rather than CopySurface() because CopySurface
// is optimized for memcpy and therefore isn't good for format conversion.
// Using OP_OVER since in our case it's equivalent to OP_SOURCE and
// generally more optimized.
dt->DrawSurface(aSurface, bounds, bounds, DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_OVER));
RefPtr<SourceSurface> surface = dt->Snapshot();
return surface->GetDataSurface();
}
// If the surface IS of type DATA then it may or may not be in main memory
// depending on whether or not it has been mapped yet. We have no way of
// knowing, so we can't be sure if it's best to create a data wrapping
// DrawTarget for the conversion or an offscreen content DrawTarget. We could
// guess it's not mapped and create an offscreen content DrawTarget, but if
// it is then we'll end up uploading the surface data, and most likely the
// caller is going to be accessing the resulting surface data, resulting in a
// readback (both very expensive operations). Alternatively we could guess
// the data is mapped and create a data wrapping DrawTarget and, if the
// surface is not in main memory, then we will incure a readback. The latter
// of these two "wrong choices" is the least costly (a readback, vs an
// upload and a readback), and more than likely the DATA surface that we've
// been passed actually IS in main memory anyway. For these reasons it's most
// likely best to create a data wrapping DrawTarget here to do the format
// conversion.
RefPtr<DataSourceSurface> dataSurface =
Factory::CreateDataSourceSurface(aSurface->GetSize(), aFormat);
DataSourceSurface::MappedSurface map;
if (!dataSurface ||
!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
return nullptr;
}
RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForData(BackendType::CAIRO,
map.mData,
dataSurface->GetSize(),
map.mStride,
aFormat);
if (!dt) {
dataSurface->Unmap();
return nullptr;
}
// Using DrawSurface() here rather than CopySurface() because CopySurface
// is optimized for memcpy and therefore isn't good for format conversion.
// Using OP_OVER since in our case it's equivalent to OP_SOURCE and
// generally more optimized.
dt->DrawSurface(aSurface, bounds, bounds, DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_OVER));
dataSurface->Unmap();
return dataSurface.forget();
}
#ifdef MOZ_DUMP_PAINTING
/* static */ void
gfxUtils::WriteAsPNG(DrawTarget* aDT, const char* aFile)

Просмотреть файл

@ -9,6 +9,8 @@
#include "gfxTypes.h"
#include "GraphicsFilter.h"
#include "imgIContainer.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
class gfxDrawable;
class nsIntRegion;
@ -22,8 +24,12 @@ class PlanarYCbCrData;
class gfxUtils {
public:
typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
typedef mozilla::gfx::IntPoint IntPoint;
typedef mozilla::gfx::Matrix Matrix;
typedef mozilla::gfx::SourceSurface SourceSurface;
typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
/*
* Premultiply or Unpremultiply aSourceSurface, writing the result
* to aDestSurface or back into aSourceSurface if aDestSurface is null.
@ -155,6 +161,51 @@ public:
unsigned char* aDestBuffer,
int32_t aStride);
/**
* Creates a copy of aSurface, but having the SurfaceFormat aFormat.
*
* This function always creates a new surface. Do not call it if aSurface's
* format is the same as aFormat. Such a non-conversion would just be an
* unnecessary and wasteful copy (this function asserts to prevent that).
*
* This function is intended to be called by code that needs to access the
* pixel data of the surface, but doesn't want to have lots of branches
* to handle different pixel data formats (code which would become out of
* date if and when new formats are added). Callers can use this function
* to copy the surface to a specified format so that they only have to
* handle pixel data in that one format.
*
* WARNING: There are format conversions that will not be supported by this
* function. It very much depends on what the Moz2D backends support. If
* the temporary B8G8R8A8 DrawTarget that this function creates has a
* backend that supports DrawSurface() calls passing a surface with
* aSurface's format it will work. Otherwise it will not.
*
* *** IMPORTANT PERF NOTE ***
*
* This function exists partly because format conversion is fraught with
* non-obvious performance hazards, so we don't want Moz2D consumers to be
* doing their own format conversion. Do not try to do so, or at least read
* the comments in this functions implemtation. That said, the copy that
* this function carries out has a cost and, although this function tries
* to avoid perf hazards such as expensive uploads to/readbacks from the
* GPU, it can't guarantee that it always successfully does so. Perf
* critical code that can directly handle the common formats that it
* encounters in a way that is cheaper than a copy-with-format-conversion
* should consider doing so, and only use this function as a fallback to
* handle other formats.
*
* XXXjwatt it would be nice if SourceSurface::GetDataSurface took a
* SurfaceFormat argument (with a default argument meaning "use the
* existing surface's format") and returned a DataSourceSurface in that
* format. (There would then be an issue of callers maybe failing to
* realize format conversion may involve expensive copying/uploading/
* readback.)
*/
static mozilla::TemporaryRef<DataSourceSurface>
CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
SurfaceFormat aFormat);
static const uint8_t sUnpremultiplyTable[256*256];
static const uint8_t sPremultiplyTable[256*256];
#ifdef MOZ_DUMP_PAINTING

Просмотреть файл

@ -67,7 +67,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
'gfxFT2Fonts.cpp',
'gfxFT2Utils.cpp',
'gfxPDFSurface.cpp',
'nsUnicodeRange.cpp',
]
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
EXPORTS += [
@ -83,7 +82,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'gfxFT2Fonts.cpp',
'gfxFT2Utils.cpp',
'gfxPDFSurface.cpp',
'nsUnicodeRange.cpp',
]
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
EXPORTS += [
@ -99,7 +97,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
'gfxQuartzImageSurface.cpp',
'gfxQuartzNativeDrawing.cpp',
'gfxQuartzSurface.cpp',
'nsUnicodeRange.cpp',
]
elif CONFIG['MOZ_WIDGET_GTK']:
EXPORTS += [
@ -120,7 +117,6 @@ elif CONFIG['MOZ_WIDGET_GTK']:
'gfxPDFSurface.cpp',
'gfxPlatformGtk.cpp',
'gfxPSSurface.cpp',
'nsUnicodeRange.cpp',
]
if CONFIG['MOZ_X11']:
@ -150,7 +146,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
'gfxPDFSurface.cpp',
'gfxQPainterSurface.cpp',
'gfxQtPlatform.cpp',
'nsUnicodeRange.cpp',
]
if CONFIG['MOZ_X11']:
@ -184,7 +179,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
'gfxWindowsNativeDrawing.cpp',
'gfxWindowsPlatform.cpp',
'gfxWindowsSurface.cpp',
'nsUnicodeRange.cpp',
]
if CONFIG['MOZ_ENABLE_DWRITE_FONT']:
# gfxDWriteFontList.cpp forces NSPR logging, so it cannot be built in unified mode.
@ -253,6 +247,7 @@ UNIFIED_SOURCES += [
'gfxTeeSurface.cpp',
'gfxUtils.cpp',
'nsSurfaceTexture.cpp',
'nsUnicodeRange.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':

Просмотреть файл

@ -5,6 +5,7 @@
#include "nsUTF16ToUnicode.h"
#include "nsCharTraits.h"
#include "mozilla/Endian.h"
enum {
STATE_NORMAL = 0,
@ -75,7 +76,7 @@ nsUTF16ToUnicodeBase::UTF16ConvertToUnicode(const char * aSrc,
// the 1st byte of a 16-bit code unit was stored in |mOddByte| in the
// previous run while the 2nd byte has to come from |*src|.
mState = STATE_NORMAL;
#ifdef IS_BIG_ENDIAN
#if MOZ_BIG_ENDIAN
u = (mOddByte << 8) | uint8_t(*src++); // safe, we know we have at least one byte.
#else
u = (*src++ << 8) | mOddByte; // safe, we know we have at least one byte.
@ -209,7 +210,7 @@ nsUTF16BEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
mState = STATE_SECOND_BYTE;
return NS_OK_UDEC_MOREINPUT;
}
#ifdef IS_LITTLE_ENDIAN
#if MOZ_LITTLE_ENDIAN
// on LE machines, BE BOM is 0xFFFE
if (0xFFFE != *((char16_t*)aSrc)) {
mState = STATE_NORMAL;
@ -233,14 +234,8 @@ nsUTF16BEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
break;
}
nsresult rv = UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
#ifdef IS_LITTLE_ENDIAN
true
#else
false
#endif
);
return rv;
return UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
bool(MOZ_LITTLE_ENDIAN));
}
NS_IMETHODIMP
@ -262,7 +257,7 @@ nsUTF16LEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
mState = STATE_SECOND_BYTE;
return NS_OK_UDEC_MOREINPUT;
}
#ifdef IS_BIG_ENDIAN
#if MOZ_BIG_ENDIAN
// on BE machines, LE BOM is 0xFFFE
if (0xFFFE != *((char16_t*)aSrc)) {
mState = STATE_NORMAL;
@ -286,14 +281,8 @@ nsUTF16LEToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
break;
}
nsresult rv = UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
#ifdef IS_BIG_ENDIAN
true
#else
false
#endif
);
return rv;
return UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
bool(MOZ_BIG_ENDIAN));
}
NS_IMETHODIMP
@ -348,12 +337,10 @@ nsUTF16ToUnicode::Convert(const char * aSrc, int32_t * aSrcLength,
}
nsresult rv = UTF16ConvertToUnicode(aSrc, aSrcLength, aDest, aDestLength,
#ifdef IS_BIG_ENDIAN
#if MOZ_BIG_ENDIAN
(mEndian == kLittleEndian)
#elif defined(IS_LITTLE_ENDIAN)
(mEndian == kBigEndian)
#else
#error "Unknown endianness"
(mEndian == kBigEndian)
#endif
);

Просмотреть файл

@ -6,8 +6,6 @@
#include "nsUnicodeToUTF16.h"
#include <string.h>
inline static void SwapBytes(char *aDest, const char16_t* aSrc, int32_t aLen);
NS_IMETHODIMP nsUnicodeToUTF16BE::Convert(const char16_t * aSrc, int32_t * aSrcLength,
char * aDest, int32_t * aDestLength)
{
@ -97,40 +95,12 @@ NS_IMETHODIMP nsUnicodeToUTF16BE::SetOutputErrorBehavior(int32_t aBehavior,
NS_IMETHODIMP nsUnicodeToUTF16BE::CopyData(char* aDest, const char16_t* aSrc, int32_t aLen )
{
#ifdef IS_BIG_ENDIAN
//UnicodeToUTF16SameEndian
::memcpy(aDest, (void*) aSrc, aLen * 2);
#elif defined(IS_LITTLE_ENDIAN)
//UnicodeToUTF16DiffEndian
SwapBytes(aDest, aSrc, aLen);
#else
#error "Unknown endianness"
#endif
mozilla::NativeEndian::copyAndSwapToBigEndian(aDest, aSrc, aLen);
return NS_OK;
}
NS_IMETHODIMP nsUnicodeToUTF16LE::CopyData(char* aDest, const char16_t* aSrc, int32_t aLen )
{
#ifdef IS_LITTLE_ENDIAN
//UnicodeToUTF16SameEndian
::memcpy(aDest, (void*) aSrc, aLen * 2);
#elif defined(IS_BIG_ENDIAN)
//UnicodeToUTF16DiffEndian
SwapBytes(aDest, aSrc, aLen);
#else
#error "Unknown endianness"
#endif
mozilla::NativeEndian::copyAndSwapToLittleEndian(aDest, aSrc, aLen);
return NS_OK;
}
inline void SwapBytes(char *aDest, const char16_t* aSrc, int32_t aLen)
{
char16_t *p = (char16_t*) aDest;
// copy the data by swaping
for(int32_t i = 0; i < aLen; i++)
{
char16_t aChar = *aSrc++;
*p++ = (0x00FF & (aChar >> 8)) | (0xFF00 & (aChar << 8));
}
}

Просмотреть файл

@ -7,6 +7,7 @@
#define nsUnicodeToUTF16_h_
#include "nsUCSupport.h"
#include "mozilla/Endian.h"
class nsUnicodeToUTF16BE: public nsBasicEncoder
{
@ -39,14 +40,10 @@ protected:
NS_IMETHOD CopyData(char* aDest, const char16_t* aSrc, int32_t aLen );
};
// XXX In theory, we have to check the endianness at run-time because some
// modern RISC processors can be run at both LE and BE.
#ifdef IS_LITTLE_ENDIAN
#if MOZ_LITTLE_ENDIAN
class nsUnicodeToUTF16: public nsUnicodeToUTF16LE
#elif defined(IS_BIG_ENDIAN)
class nsUnicodeToUTF16: public nsUnicodeToUTF16BE
#else
#error "Unknown endianness"
class nsUnicodeToUTF16: public nsUnicodeToUTF16BE
#endif
{
public:

Просмотреть файл

@ -35,9 +35,9 @@ class ProfileEntry
// if a sample were taken it would be examining bogus information.
//
// A ProfileEntry represents both a C++ profile entry and a JS one. Both use
// the string as a description, but JS uses the sp as nullptr to indicate
// that it is a JS entry. The script_ is then only ever examined for a JS
// entry, and the idx is used by both, but with different meanings.
// the string as a description, but JS uses the sp as nullptr or (void*)1 to
// indicate that it is a JS entry. The script_ is then only ever examined for
// a JS entry, and the idx is used by both, but with different meanings.
//
const char * volatile string; // Descriptive string of this entry
void * volatile sp; // Relevant stack pointer for the entry

Просмотреть файл

@ -245,6 +245,18 @@ class Heap : public js::HeapBase<T>
}
}
/*
* Set the pointer to a value which will cause a crash if it is
* dereferenced.
*/
void setToCrashOnTouch() {
ptr = reinterpret_cast<T>(crashOnTouchPointer);
}
bool isSetToCrashOnTouch() {
return ptr == crashOnTouchPointer;
}
private:
void init(T newPtr) {
MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
@ -266,6 +278,10 @@ class Heap : public js::HeapBase<T>
#endif
}
enum {
crashOnTouchPointer = 1
};
T ptr;
};
@ -363,23 +379,10 @@ class TenuredHeap : public js::HeapBase<T>
return *this;
}
/*
* Set the pointer to a value which will cause a crash if it is
* dereferenced.
*/
void setToCrashOnTouch() {
bits = (bits & flagsMask) | crashOnTouchPointer;
}
bool isSetToCrashOnTouch() {
return (bits & ~flagsMask) == crashOnTouchPointer;
}
private:
enum {
maskBits = 3,
flagsMask = (1 << maskBits) - 1,
crashOnTouchPointer = 1 << maskBits
};
uintptr_t bits;

Просмотреть файл

@ -10,6 +10,7 @@
#include "jit/BaselineJIT.h"
#include "jit/CompileInfo.h"
#include "jit/IonSpewer.h"
#include "jit/Recover.h"
#include "vm/ArgumentsObject.h"
#include "jsscriptinlines.h"
@ -476,7 +477,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
if (excInfo)
exprStackSlots = excInfo->numExprSlots;
else
exprStackSlots = iter.allocations() - (script->nfixed() + CountArgSlots(script, fun));
exprStackSlots = iter.numAllocations() - (script->nfixed() + CountArgSlots(script, fun));
builder.resetFramePushed();
@ -629,9 +630,9 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
*builder.valuePointerAtStackOffset(thisvOffset) = thisv;
JS_ASSERT(iter.allocations() >= CountArgSlots(script, fun));
JS_ASSERT(iter.numAllocations() >= CountArgSlots(script, fun));
IonSpew(IonSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u",
iter.allocations(), fun->nargs(), script->nfixed());
iter.numAllocations(), fun->nargs(), script->nfixed());
if (!callerPC) {
// This is the first frame. Store the formals in a Vector until we
@ -1348,6 +1349,8 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
jsbytecode *topCallerPC = nullptr;
while (true) {
MOZ_ASSERT(snapIter.instruction()->isResumePoint());
#if JS_TRACE_LOGGING
if (frameNo > 0) {
TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, scr);
@ -1383,7 +1386,6 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
callerPC = callPC;
fun = nextCallee;
scr = fun->existingScript();
snapIter.nextFrame();
// Save top caller info for adjusting SPS frames later.
if (!topCaller) {
@ -1393,6 +1395,8 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
}
frameNo++;
snapIter.nextInstruction();
}
IonSpew(IonSpew_BaselineBailouts, " Done restoring frames");

Просмотреть файл

@ -7938,15 +7938,15 @@ static const VMFunction SPSEnterInfo = FunctionInfo<SPSFn>(SPSEnter);
static const VMFunction SPSExitInfo = FunctionInfo<SPSFn>(SPSExit);
bool
CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
CodeGenerator::visitProfilerStackOp(LProfilerStackOp *lir)
{
Register temp = ToRegister(lir->temp()->output());
bool inlinedFunction = lir->inlineLevel() > 0;
switch (lir->type()) {
case MFunctionBoundary::Inline_Enter:
case MProfilerStackOp::InlineEnter:
// Multiple scripts can be inlined at one depth, but there is only
// one Inline_Exit node to signify this. To deal with this, if we
// one InlineExit node to signify this. To deal with this, if we
// reach the entry of another inline script on the same level, then
// just reset the sps metadata about the frame. We must balance
// calls to leave()/reenter(), so perform the balance without
@ -7965,7 +7965,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
return false;
// fallthrough
case MFunctionBoundary::Enter:
case MProfilerStackOp::Enter:
if (gen->options.spsSlowAssertionsEnabled()) {
if (!inlinedFunction || js_JitOptions.profileInlineFrames) {
saveLive(lir);
@ -7980,7 +7980,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
return sps_.push(lir->script(), masm, temp, /* inlinedFunction = */ inlinedFunction);
case MFunctionBoundary::Inline_Exit:
case MProfilerStackOp::InlineExit:
// all inline returns were covered with ::Exit, so we just need to
// maintain the state of inline frames currently active and then
// reenter the caller
@ -7988,7 +7988,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
sps_.reenter(masm, temp, /* inlinedFunction = */ true);
return true;
case MFunctionBoundary::Exit:
case MProfilerStackOp::Exit:
if (gen->options.spsSlowAssertionsEnabled()) {
if (!inlinedFunction || js_JitOptions.profileInlineFrames) {
saveLive(lir);
@ -8008,7 +8008,7 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir)
return true;
default:
MOZ_ASSUME_UNREACHABLE("invalid LFunctionBoundary type");
MOZ_ASSUME_UNREACHABLE("invalid LProfilerStackOp type");
}
}

Просмотреть файл

@ -274,7 +274,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitInstanceOfO(LInstanceOfO *ins);
bool visitInstanceOfV(LInstanceOfV *ins);
bool visitCallInstanceOf(LCallInstanceOf *ins);
bool visitFunctionBoundary(LFunctionBoundary *lir);
bool visitProfilerStackOp(LProfilerStackOp *lir);
bool visitGetDOMProperty(LGetDOMProperty *lir);
bool visitGetDOMMember(LGetDOMMember *lir);
bool visitSetDOMProperty(LSetDOMProperty *lir);

Просмотреть файл

@ -654,7 +654,7 @@ IonBuilder::build()
// Emit the start instruction, so we can begin real instructions.
current->makeStart(MStart::New(alloc(), MStart::StartType_Default));
if (instrumentedProfiling())
current->add(MFunctionBoundary::New(alloc(), script(), MFunctionBoundary::Enter));
current->add(MProfilerStackOp::New(alloc(), script(), MProfilerStackOp::Enter));
// Guard against over-recursion. Do this before we start unboxing, since
// this will create an OSI point that will read the incoming argument
@ -791,11 +791,11 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
// All further instructions generated in from this scope should be
// considered as part of the function that we're inlining. We also need to
// keep track of the inlining depth because all scripts inlined on the same
// level contiguously have only one Inline_Exit node.
// level contiguously have only one InlineExit node.
if (instrumentedProfiling()) {
predecessor->add(MFunctionBoundary::New(alloc(), script(),
MFunctionBoundary::Inline_Enter,
inliningDepth_));
predecessor->add(MProfilerStackOp::New(alloc(), script(),
MProfilerStackOp::InlineEnter,
inliningDepth_));
}
predecessor->end(MGoto::New(alloc(), current));
@ -3628,8 +3628,8 @@ IonBuilder::processReturn(JSOp op)
}
if (instrumentedProfiling()) {
current->add(MFunctionBoundary::New(alloc(), script(), MFunctionBoundary::Exit,
inliningDepth_));
current->add(MProfilerStackOp::New(alloc(), script(), MProfilerStackOp::Exit,
inliningDepth_));
}
MReturn *ret = MReturn::New(alloc(), def);
current->end(ret);
@ -3961,9 +3961,9 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
return false;
returnBlock->setCallerResumePoint(callerResumePoint_);
// When profiling add Inline_Exit instruction to indicate end of inlined function.
// When profiling add InlineExit instruction to indicate end of inlined function.
if (instrumentedProfiling())
returnBlock->add(MFunctionBoundary::New(alloc(), nullptr, MFunctionBoundary::Inline_Exit));
returnBlock->add(MProfilerStackOp::New(alloc(), nullptr, MProfilerStackOp::InlineExit));
// Inherit the slots from current and pop |fun|.
returnBlock->inheritSlots(current);

Просмотреть файл

@ -23,6 +23,7 @@ InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(
JSContext *cx, const IonBailoutIterator *iter)
: frame_(iter),
framesRead_(0),
frameCount_(UINT32_MAX),
callee_(cx),
script_(cx)
{

Просмотреть файл

@ -244,6 +244,8 @@ class IonFrameIterator
class IonJSFrameLayout;
class IonBailoutIterator;
class RResumePoint;
// Reads frame information in snapshot-encoding order (that is, outermost frame
// to innermost frame).
class SnapshotIterator
@ -287,22 +289,23 @@ class SnapshotIterator
return snapshot_.readAllocation();
}
Value skip() {
readAllocation();
snapshot_.skipAllocation();
return UndefinedValue();
}
inline uint32_t allocations() const {
return recover_.allocations();
const RResumePoint *resumePoint() const;
const RInstruction *instruction() const {
return recover_.instruction();
}
uint32_t numAllocations() const;
inline bool moreAllocations() const {
return recover_.moreAllocations(snapshot_);
return snapshot_.numAllocationsRead() < numAllocations();
}
public:
// Exhibits frame properties contained in the snapshot.
inline uint32_t pcOffset() const {
return recover_.pcOffset();
}
uint32_t pcOffset() const;
inline bool resumeAfter() const {
// Inline frames are inlined on calls, which are considered as being
// resumed on the Call as baseline will push the pc once we return from
@ -315,17 +318,31 @@ class SnapshotIterator
return snapshot_.bailoutKind();
}
public:
// Read the next instruction available and get ready to either skip it or
// evaluate it.
inline void nextInstruction() {
MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations());
recover_.nextInstruction();
snapshot_.resetNumAllocationsRead();
}
// Skip an Instruction by walking to the next instruction and by skipping
// all the allocations corresponding to this instruction.
void skipInstruction();
inline bool moreInstructions() const {
return recover_.moreInstructions();
}
public:
// Handle iterating over frames of the snapshots.
inline void nextFrame() {
// Reuse the Snapshot buffer.
recover_.nextFrame(snapshot_);
}
void nextFrame();
inline bool moreFrames() const {
return recover_.moreFrames();
}
inline uint32_t frameCount() const {
return recover_.frameCount();
// The last instruction is recovering the innermost frame, so as long as
// there is more instruction there is necesseray more frames.
return moreInstructions();
}
public:
@ -409,7 +426,14 @@ class InlineFrameIteratorMaybeGC
const IonFrameIterator *frame_;
SnapshotIterator start_;
SnapshotIterator si_;
unsigned framesRead_;
uint32_t framesRead_;
// When the inline-frame-iterator is created, this variable is defined to
// UINT32_MAX. Then the first iteration of findNextFrame, which settle on
// the innermost frame, is used to update this counter to the number of
// frames contained in the recover buffer.
uint32_t frameCount_;
typename MaybeRooted<JSFunction*, allowGC>::RootType callee_;
typename MaybeRooted<JSScript*, allowGC>::RootType script_;
jsbytecode *pc_;
@ -442,6 +466,7 @@ class InlineFrameIteratorMaybeGC
InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter)
: frame_(iter ? iter->frame_ : nullptr),
framesRead_(0),
frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
callee_(cx),
script_(cx)
{
@ -455,7 +480,7 @@ class InlineFrameIteratorMaybeGC
}
bool more() const {
return frame_ && framesRead_ < start_.frameCount();
return frame_ && framesRead_ < frameCount_;
}
JSFunction *callee() const {
JS_ASSERT(callee_);
@ -510,8 +535,8 @@ class InlineFrameIteratorMaybeGC
// Skip over all slots until we get to the last slots
// (= arguments slots of callee) the +3 is for [this], [returnvalue],
// [scopechain], and maybe +1 for [argsObj]
JS_ASSERT(parent_s.allocations() >= nactual + 3 + argsObjAdj);
unsigned skip = parent_s.allocations() - nactual - 3 - argsObjAdj;
JS_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj);
unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj;
for (unsigned j = 0; j < skip; j++)
parent_s.skip();
@ -597,7 +622,8 @@ class InlineFrameIteratorMaybeGC
// Inline frame number, 0 for the outermost (non-inlined) frame.
size_t frameNo() const {
return start_.frameCount() - framesRead_;
MOZ_ASSERT(frameCount_ != UINT32_MAX);
return frameCount_ - framesRead_;
}
private:

Просмотреть файл

@ -20,6 +20,7 @@
#include "jit/JitCompartment.h"
#include "jit/ParallelFunctions.h"
#include "jit/PcScriptCache.h"
#include "jit/Recover.h"
#include "jit/Safepoints.h"
#include "jit/Snapshots.h"
#include "jit/VMFunctions.h"
@ -1498,6 +1499,42 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
}
}
const RResumePoint *
SnapshotIterator::resumePoint() const
{
return instruction()->toResumePoint();
}
uint32_t
SnapshotIterator::numAllocations() const
{
return resumePoint()->numOperands();
}
uint32_t
SnapshotIterator::pcOffset() const
{
return resumePoint()->pcOffset();
}
void
SnapshotIterator::skipInstruction()
{
MOZ_ASSERT(snapshot_.numAllocationsRead() == 0);
size_t numOperands = instruction()->numOperands();
for (size_t i = 0; i < numOperands; i++)
skip();
nextInstruction();
}
void
SnapshotIterator::nextFrame()
{
nextInstruction();
while (!instruction()->isResumePoint())
skipInstruction();
}
IonScript *
IonFrameIterator::ionScript() const
{
@ -1536,6 +1573,7 @@ InlineFrameIteratorMaybeGC<allowGC>::resetOn(const IonFrameIterator *iter)
{
frame_ = iter;
framesRead_ = 0;
frameCount_ = UINT32_MAX;
if (iter) {
start_ = SnapshotIterator(*iter);
@ -1553,9 +1591,15 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
si_ = start_;
// Read the initial frame.
// Read the initial frame out of the C stack.
callee_ = frame_->maybeCallee();
script_ = frame_->script();
// Settle on the outermost frame without evaluating any instructions before
// looking for a pc.
if (!si_.instruction()->isResumePoint())
si_.nextFrame();
pc_ = script_->offsetToPC(si_.pcOffset());
#ifdef DEBUG
numActualArgs_ = 0xbadbad;
@ -1563,8 +1607,15 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
// This unfortunately is O(n*m), because we must skip over outer frames
// before reading inner ones.
unsigned remaining = start_.frameCount() - framesRead_ - 1;
for (unsigned i = 0; i < remaining; i++) {
// The first time (frameCount_ == UINT32_MAX) we do not know the number of
// frames that we are going to inspect. So we are iterating until there is
// no more frames, to settle on the inner most frame and to count the number
// of frames.
size_t remaining = (frameCount_ != UINT32_MAX) ? frameNo() - 1 : SIZE_MAX;
size_t i = 1;
for (; i <= remaining && si_.moreFrames(); i++) {
JS_ASSERT(IsIonInlinablePC(pc_));
// Recover the number of actual arguments from the script.
@ -1582,10 +1633,11 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
JS_ASSERT(numActualArgs_ != 0xbadbad);
// Skip over non-argument slots, as well as |this|.
unsigned skipCount = (si_.allocations() - 1) - numActualArgs_ - 1;
unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1;
for (unsigned j = 0; j < skipCount; j++)
si_.skip();
// The JSFunction is a constant, otherwise we would not have inlined it.
Value funval = si_.read();
// Skip extra value allocations.
@ -1604,6 +1656,14 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
pc_ = script_->offsetToPC(si_.pcOffset());
}
// The first time we do not know the number of frames, we only settle on the
// last frame, and update the number of frames based on the number of
// iteration that we have done.
if (frameCount_ == UINT32_MAX) {
MOZ_ASSERT(!si_.moreFrames());
frameCount_ = i;
}
framesRead_++;
}
template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
@ -1804,8 +1864,8 @@ InlineFrameIteratorMaybeGC<allowGC>::dump() const
}
SnapshotIterator si = snapshotIterator();
fprintf(stderr, " slots: %u\n", si.allocations() - 1);
for (unsigned i = 0; i < si.allocations() - 1; i++) {
fprintf(stderr, " slots: %u\n", si.numAllocations() - 1);
for (unsigned i = 0; i < si.numAllocations() - 1; i++) {
if (isFunction) {
if (i == 0)
fprintf(stderr, " scope chain: ");

Просмотреть файл

@ -5695,12 +5695,12 @@ class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
static const size_t RHS = BOX_PIECES;
};
class LFunctionBoundary : public LInstructionHelper<0, 0, 1>
class LProfilerStackOp : public LInstructionHelper<0, 0, 1>
{
public:
LIR_HEADER(FunctionBoundary)
LIR_HEADER(ProfilerStackOp)
LFunctionBoundary(const LDefinition &temp) {
LProfilerStackOp(const LDefinition &temp) {
setTemp(0, temp);
}
@ -5709,15 +5709,15 @@ class LFunctionBoundary : public LInstructionHelper<0, 0, 1>
}
JSScript *script() {
return mir_->toFunctionBoundary()->script();
return mir_->toProfilerStackOp()->script();
}
MFunctionBoundary::Type type() {
return mir_->toFunctionBoundary()->type();
MProfilerStackOp::Type type() {
return mir_->toProfilerStackOp()->type();
}
unsigned inlineLevel() {
return mir_->toFunctionBoundary()->inlineLevel();
return mir_->toProfilerStackOp()->inlineLevel();
}
};

Просмотреть файл

@ -119,28 +119,48 @@ TotalOperandCount(MResumePoint *mir)
return accum;
}
LRecoverInfo::LRecoverInfo(MResumePoint *mir)
: mir_(mir),
LRecoverInfo::LRecoverInfo(TempAllocator &alloc)
: instructions_(alloc),
recoverOffset_(INVALID_RECOVER_OFFSET)
{ }
LRecoverInfo *
LRecoverInfo::New(MIRGenerator *gen, MResumePoint *mir)
{
LRecoverInfo *recover = new(gen->alloc()) LRecoverInfo(mir);
if (!recover)
LRecoverInfo *recoverInfo = new(gen->alloc()) LRecoverInfo(gen->alloc());
if (!recoverInfo || !recoverInfo->init(mir))
return nullptr;
IonSpew(IonSpew_Snapshots, "Generating LIR recover %p from MIR (%p)",
(void *)recover, (void *)mir);
IonSpew(IonSpew_Snapshots, "Generating LIR recover info %p from MIR (%p)",
(void *)recoverInfo, (void *)mir);
return recover;
return recoverInfo;
}
LSnapshot::LSnapshot(LRecoverInfo *recover, BailoutKind kind)
: numSlots_(TotalOperandCount(recover->mir()) * BOX_PIECES),
bool
LRecoverInfo::init(MResumePoint *rp)
{
MResumePoint *it = rp;
// Sort operations in the order in which we need to restore the stack. This
// implies that outer frames, as well as operations needed to recover the
// current frame, are located before the current frame. The inner-most
// resume point should be the last element in the list.
do {
if (!instructions_.append(it))
return false;
it = it->caller();
} while (it);
Reverse(instructions_.begin(), instructions_.end());
MOZ_ASSERT(mir() == rp);
return true;
}
LSnapshot::LSnapshot(LRecoverInfo *recoverInfo, BailoutKind kind)
: numSlots_(TotalOperandCount(recoverInfo->mir()) * BOX_PIECES),
slots_(nullptr),
recoverInfo_(recover),
recoverInfo_(recoverInfo),
snapshotOffset_(INVALID_SNAPSHOT_OFFSET),
bailoutId_(INVALID_BAILOUT_ID),
bailoutKind_(kind)

Просмотреть файл

@ -878,18 +878,26 @@ class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
class LRecoverInfo : public TempObject
{
MResumePoint *mir_;
public:
typedef Vector<MResumePoint *, 2, IonAllocPolicy> Instructions;
private:
// List of instructions needed to recover the stack frames.
// Outer frames are stored before inner frames.
Instructions instructions_;
// Cached offset where this resume point is encoded.
RecoverOffset recoverOffset_;
LRecoverInfo(MResumePoint *mir);
LRecoverInfo(TempAllocator &alloc);
bool init(MResumePoint *mir);
public:
static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir);
// Resume point of the inner most function.
MResumePoint *mir() const {
return mir_;
return instructions_.back();
}
RecoverOffset recoverOffset() const {
return recoverOffset_;
@ -898,6 +906,13 @@ class LRecoverInfo : public TempObject
JS_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
recoverOffset_ = offset;
}
MResumePoint **begin() {
return instructions_.begin();
}
MResumePoint **end() {
return instructions_.end();
}
};
// An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,

Просмотреть файл

@ -272,7 +272,7 @@
_(CallInstanceOf) \
_(InterruptCheck) \
_(InterruptCheckImplicit) \
_(FunctionBoundary) \
_(ProfilerStackOp) \
_(GetDOMProperty) \
_(GetDOMMember) \
_(SetDOMProperty) \

Просмотреть файл

@ -3358,9 +3358,9 @@ LIRGenerator::visitCallInstanceOf(MCallInstanceOf *ins)
}
bool
LIRGenerator::visitFunctionBoundary(MFunctionBoundary *ins)
LIRGenerator::visitProfilerStackOp(MProfilerStackOp *ins)
{
LFunctionBoundary *lir = new(alloc()) LFunctionBoundary(temp());
LProfilerStackOp *lir = new(alloc()) LProfilerStackOp(temp());
if (!add(lir, ins))
return false;
// If slow assertions are enabled, then this node will result in a callVM
@ -3532,8 +3532,11 @@ bool
LIRGenerator::visitGetDOMMember(MGetDOMMember *ins)
{
MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
MOZ_ASSERT(ins->domAliasSet() == JSJitInfo::AliasNone,
"Members had better not alias anything");
// We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
// but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
// value can in fact change as a result of DOM setters and method calls.
MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
"Member gets had better not alias the world");
LGetDOMMember *lir =
new(alloc()) LGetDOMMember(useRegister(ins->object()));
return defineBox(lir, ins);

Просмотреть файл

@ -238,7 +238,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitInArray(MInArray *ins);
bool visitInstanceOf(MInstanceOf *ins);
bool visitCallInstanceOf(MCallInstanceOf *ins);
bool visitFunctionBoundary(MFunctionBoundary *ins);
bool visitProfilerStackOp(MProfilerStackOp *ins);
bool visitIsCallable(MIsCallable *ins);
bool visitHaveSameClass(MHaveSameClass *ins);
bool visitHasClass(MHasClass *ins);

Просмотреть файл

@ -9217,15 +9217,15 @@ class MNewStringObject :
// Node that represents that a script has begun executing. This comes at the
// start of the function and is called once per function (including inline
// ones)
class MFunctionBoundary : public MNullaryInstruction
class MProfilerStackOp : public MNullaryInstruction
{
public:
enum Type {
Enter, // a function has begun executing and it is not inline
Exit, // any function has exited (inlined or normal)
Inline_Enter, // an inline function has begun executing
InlineEnter, // an inline function has begun executing
Inline_Exit // all instructions of an inline function are done, a
InlineExit // all instructions of an inline function are done, a
// return from the inline function could have occurred
// before this boundary
};
@ -9235,20 +9235,20 @@ class MFunctionBoundary : public MNullaryInstruction
Type type_;
unsigned inlineLevel_;
MFunctionBoundary(JSScript *script, Type type, unsigned inlineLevel)
MProfilerStackOp(JSScript *script, Type type, unsigned inlineLevel)
: script_(script), type_(type), inlineLevel_(inlineLevel)
{
JS_ASSERT_IF(type != Inline_Exit, script != nullptr);
JS_ASSERT_IF(type == Inline_Enter, inlineLevel != 0);
JS_ASSERT_IF(type != InlineExit, script != nullptr);
JS_ASSERT_IF(type == InlineEnter, inlineLevel != 0);
setGuard();
}
public:
INSTRUCTION_HEADER(FunctionBoundary)
INSTRUCTION_HEADER(ProfilerStackOp)
static MFunctionBoundary *New(TempAllocator &alloc, JSScript *script, Type type,
static MProfilerStackOp *New(TempAllocator &alloc, JSScript *script, Type type,
unsigned inlineLevel = 0) {
return new(alloc) MFunctionBoundary(script, type, inlineLevel);
return new(alloc) MProfilerStackOp(script, type, inlineLevel);
}
JSScript *script() {
@ -9425,44 +9425,8 @@ class MResumePoint MOZ_FINAL : public MNode, public InlineForwardListNode<MResum
operands_[i].producer()->removeUse(&operands_[i]);
}
}
};
/*
* Facade for a chain of MResumePoints that cross frame boundaries (due to
* function inlining). Operands are ordered from oldest frame to newest.
*/
class FlattenedMResumePointIter
{
Vector<MResumePoint *, 8, SystemAllocPolicy> resumePoints;
MResumePoint *newest;
size_t numOperands_;
public:
explicit FlattenedMResumePointIter(MResumePoint *newest)
: newest(newest), numOperands_(0)
{}
bool init() {
MResumePoint *it = newest;
do {
if (!resumePoints.append(it))
return false;
it = it->caller();
} while (it);
Reverse(resumePoints.begin(), resumePoints.end());
return true;
}
MResumePoint **begin() {
return resumePoints.begin();
}
MResumePoint **end() {
return resumePoints.end();
}
size_t numOperands() const {
return numOperands_;
}
bool writeRecoverData(CompactBufferWriter &writer) const;
};
class MIsCallable

Просмотреть файл

@ -187,7 +187,7 @@ namespace jit {
_(InstanceOf) \
_(CallInstanceOf) \
_(InterruptCheck) \
_(FunctionBoundary) \
_(ProfilerStackOp) \
_(GetDOMProperty) \
_(GetDOMMember) \
_(SetDOMProperty) \

Просмотреть файл

@ -291,7 +291,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
UNSAFE_OP(RegExpReplace)
UNSAFE_OP(StringReplace)
UNSAFE_OP(CallInstanceOf)
UNSAFE_OP(FunctionBoundary)
UNSAFE_OP(ProfilerStackOp)
UNSAFE_OP(GuardString)
UNSAFE_OP(NewDeclEnvObject)
UNSAFE_OP(In)

110
js/src/jit/Recover.cpp Normal file
Просмотреть файл

@ -0,0 +1,110 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 "jit/Recover.h"
#include "jit/IonSpewer.h"
#include "jit/MIR.h"
#include "jit/MIRGraph.h"
using namespace js;
using namespace js::jit;
void
RInstruction::readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw)
{
uint32_t op = reader.readUnsigned();
switch (Opcode(op)) {
case Recover_ResumePoint:
new (raw->addr()) RResumePoint(reader);
break;
default:
MOZ_ASSUME_UNREACHABLE("Bad decoding of the previous instruction?");
break;
}
}
bool
MResumePoint::writeRecoverData(CompactBufferWriter &writer) const
{
writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));
MBasicBlock *bb = block();
JSFunction *fun = bb->info().funMaybeLazy();
JSScript *script = bb->info().script();
uint32_t exprStack = stackDepth() - bb->info().ninvoke();
#ifdef DEBUG
// Ensure that all snapshot which are encoded can safely be used for
// bailouts.
if (GetIonContext()->cx) {
uint32_t stackDepth;
bool reachablePC;
jsbytecode *bailPC = pc();
if (mode() == MResumePoint::ResumeAfter)
bailPC = GetNextPc(pc());
if (!ReconstructStackDepth(GetIonContext()->cx, script,
bailPC, &stackDepth, &reachablePC))
{
return false;
}
if (reachablePC) {
if (JSOp(*bailPC) == JSOP_FUNCALL) {
// For fun.call(this, ...); the reconstructStackDepth will
// include the this. When inlining that is not included. So the
// exprStackSlots will be one less.
MOZ_ASSERT(stackDepth - exprStack <= 1);
} else if (JSOp(*bailPC) != JSOP_FUNAPPLY &&
!IsGetPropPC(bailPC) && !IsSetPropPC(bailPC))
{
// For fun.apply({}, arguments) the reconstructStackDepth will
// have stackdepth 4, but it could be that we inlined the
// funapply. In that case exprStackSlots, will have the real
// arguments in the slots and not be 4.
// With accessors, we have different stack depths depending on
// whether or not we inlined the accessor, as the inlined stack
// contains a callee function that should never have been there
// and we might just be capturing an uneventful property site,
// in which case there won't have been any violence.
MOZ_ASSERT(exprStack == stackDepth);
}
}
}
#endif
// Test if we honor the maximum of arguments at all times. This is a sanity
// check and not an algorithm limit. So check might be a bit too loose. +4
// to account for scope chain, return value, this value and maybe
// arguments_object.
MOZ_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4);
uint32_t implicit = StartArgSlot(script);
uint32_t formalArgs = CountArgSlots(script, fun);
uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
implicit, formalArgs - implicit, script->nfixed(), exprStack);
uint32_t pcoff = script->pcToOffset(pc());
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs);
writer.writeUnsigned(pcoff);
writer.writeUnsigned(nallocs);
return true;
}
RResumePoint::RResumePoint(CompactBufferReader &reader)
{
static_assert(sizeof(*this) <= sizeof(RInstructionStorage),
"Storage space is too small to decode this recover instruction.");
pcOffset_ = reader.readUnsigned();
numOperands_ = reader.readUnsigned();
IonSpew(IonSpew_Snapshots, "Read RResumePoint (pc offset %u, nslots %u)",
pcOffset_, numOperands_);
}

71
js/src/jit/Recover.h Normal file
Просмотреть файл

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 jit_Recover_h
#define jit_Recover_h
#include "mozilla/Attributes.h"
#include "jit/Snapshots.h"
namespace js {
namespace jit {
class RResumePoint;
class RInstruction
{
public:
enum Opcode
{
Recover_ResumePoint = 0
};
virtual Opcode opcode() const = 0;
bool isResumePoint() const {
return opcode() == Recover_ResumePoint;
}
inline const RResumePoint *toResumePoint() const;
virtual uint32_t numOperands() const = 0;
static void readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw);
};
class RResumePoint MOZ_FINAL : public RInstruction
{
private:
uint32_t pcOffset_; // Offset from script->code.
uint32_t numOperands_; // Number of slots.
friend class RInstruction;
RResumePoint(CompactBufferReader &reader);
public:
virtual Opcode opcode() const {
return Recover_ResumePoint;
}
uint32_t pcOffset() const {
return pcOffset_;
}
virtual uint32_t numOperands() const {
return numOperands_;
}
};
const RResumePoint *
RInstruction::toResumePoint() const
{
MOZ_ASSERT(isResumePoint());
return static_cast<const RResumePoint *>(this);
}
}
}
#endif /* jit_Recover_h */

Просмотреть файл

@ -12,8 +12,9 @@
#include "jit/IonSpewer.h"
#ifdef TRACK_SNAPSHOTS
# include "jit/LIR.h"
# include "jit/MIR.h"
#endif
#include "jit/MIR.h"
#include "jit/Recover.h"
using namespace js;
using namespace js::jit;
@ -481,9 +482,9 @@ static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
static const uint32_t RECOVER_RESUMEAFTER_BITS = 1;
static const uint32_t RECOVER_RESUMEAFTER_MASK = COMPUTE_MASK_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_FRAMECOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_FRAMECOUNT_BITS = 32 - RECOVER_FRAMECOUNT_SHIFT;
static const uint32_t RECOVER_FRAMECOUNT_MASK = COMPUTE_MASK_(RECOVER_FRAMECOUNT);
static const uint32_t RECOVER_RINSCOUNT_SHIFT = COMPUTE_SHIFT_AFTER_(RECOVER_RESUMEAFTER);
static const uint32_t RECOVER_RINSCOUNT_BITS = 32 - RECOVER_RINSCOUNT_SHIFT;
static const uint32_t RECOVER_RINSCOUNT_MASK = COMPUTE_MASK_(RECOVER_RINSCOUNT);
#undef COMPUTE_MASK_
#undef COMPUTE_SHIFT_AFTER_
@ -530,13 +531,18 @@ SnapshotReader::spewBailingFrom() const
}
#endif
uint32_t
SnapshotReader::readAllocationIndex()
{
allocRead_++;
return reader_.readUnsigned();
}
RValueAllocation
SnapshotReader::readAllocation()
{
IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_);
allocRead_++;
uint32_t offset = reader_.readUnsigned() * ALLOCATION_TABLE_ALIGNMENT;
uint32_t offset = readAllocationIndex() * ALLOCATION_TABLE_ALIGNMENT;
allocReader_.seek(allocTable_, offset);
return RValueAllocation::read(allocReader_);
}
@ -552,15 +558,14 @@ SnapshotWriter::init()
RecoverReader::RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size)
: reader_(nullptr, nullptr),
frameCount_(0),
framesRead_(0),
allocCount_(0)
numInstructions_(0),
numInstructionsRead_(0)
{
if (!recovers)
return;
reader_ = CompactBufferReader(recovers + snapshot.recoverOffset(), recovers + size);
readRecoverHeader();
readFrame(snapshot);
readInstruction();
}
void
@ -568,26 +573,20 @@ RecoverReader::readRecoverHeader()
{
uint32_t bits = reader_.readUnsigned();
frameCount_ = (bits & RECOVER_FRAMECOUNT_MASK) >> RECOVER_FRAMECOUNT_SHIFT;
numInstructions_ = (bits & RECOVER_RINSCOUNT_MASK) >> RECOVER_RINSCOUNT_SHIFT;
resumeAfter_ = (bits & RECOVER_RESUMEAFTER_MASK) >> RECOVER_RESUMEAFTER_SHIFT;
JS_ASSERT(frameCount_);
MOZ_ASSERT(numInstructions_);
IonSpew(IonSpew_Snapshots, "Read recover header with frameCount %u (ra: %d)",
frameCount_, resumeAfter_);
IonSpew(IonSpew_Snapshots, "Read recover header with instructionCount %u (ra: %d)",
numInstructions_, resumeAfter_);
}
void
RecoverReader::readFrame(SnapshotReader &snapshot)
RecoverReader::readInstruction()
{
JS_ASSERT(moreFrames());
JS_ASSERT(snapshot.allocRead_ == allocCount_);
pcOffset_ = reader_.readUnsigned();
allocCount_ = reader_.readUnsigned();
IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_);
framesRead_++;
snapshot.allocRead_ = 0;
MOZ_ASSERT(moreInstructions());
RInstruction::readRecoverData(reader_, &rawData_);
numInstructionsRead_++;
}
SnapshotOffset
@ -673,37 +672,23 @@ RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter)
frameCount);
MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_FRAMECOUNT_BITS));
MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_RINSCOUNT_BITS));
uint32_t bits =
(uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
(frameCount << RECOVER_FRAMECOUNT_SHIFT);
(frameCount << RECOVER_RINSCOUNT_SHIFT);
RecoverOffset recoverOffset = writer_.length();
writer_.writeUnsigned(bits);
return recoverOffset;
}
void
RecoverWriter::writeFrame(JSFunction *fun, JSScript *script,
jsbytecode *pc, uint32_t exprStack)
bool
RecoverWriter::writeFrame(const MResumePoint *rp)
{
// Test if we honor the maximum of arguments at all times.
// This is a sanity check and not an algorithm limit. So check might be a bit too loose.
// +4 to account for scope chain, return value, this value and maybe arguments_object.
JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4);
uint32_t implicit = StartArgSlot(script);
uint32_t formalArgs = CountArgSlots(script, fun);
uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
implicit, formalArgs - implicit, script->nfixed(), exprStack);
uint32_t pcoff = script->pcToOffset(pc);
IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs);
writer_.writeUnsigned(pcoff);
writer_.writeUnsigned(nallocs);
if (!rp->writeRecoverData(writer_))
return false;
framesWritten_++;
return true;
}
void

Просмотреть файл

@ -7,6 +7,8 @@
#ifndef jit_Snapshot_h
#define jit_Snapshot_h
#include "mozilla/Alignment.h"
#include "jsalloc.h"
#include "jsbytecode.h"
@ -308,7 +310,6 @@ class RecoverWriter;
// memory after code generation.
class SnapshotWriter
{
friend class RecoverWriter;
CompactBufferWriter writer_;
CompactBufferWriter allocWriter_;
@ -359,6 +360,8 @@ class SnapshotWriter
}
};
class MResumePoint;
class RecoverWriter
{
CompactBufferWriter writer_;
@ -369,7 +372,7 @@ class RecoverWriter
public:
SnapshotOffset startRecover(uint32_t frameCount, bool resumeAfter);
void writeFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack);
bool writeFrame(const MResumePoint *rp);
void endRecover();
@ -393,8 +396,6 @@ class RecoverReader;
// recover the corresponding Value from an Ion frame.
class SnapshotReader
{
friend class RecoverReader;
CompactBufferReader reader_;
CompactBufferReader allocReader_;
const uint8_t* allocTable_;
@ -418,13 +419,16 @@ class SnapshotReader
private:
void readSnapshotHeader();
void readFrameHeader();
uint32_t readAllocationIndex();
public:
SnapshotReader(const uint8_t *snapshots, uint32_t offset,
uint32_t RVATableSize, uint32_t listSize);
RValueAllocation readAllocation();
void skipAllocation() {
readAllocationIndex();
}
BailoutKind bailoutKind() const {
return bailoutKind_;
@ -432,48 +436,57 @@ class SnapshotReader
RecoverOffset recoverOffset() const {
return recoverOffset_;
}
uint32_t numAllocationsRead() const {
return allocRead_;
}
void resetNumAllocationsRead() {
allocRead_ = 0;
}
};
typedef mozilla::AlignedStorage<4 * sizeof(uint32_t)> RInstructionStorage;
class RInstruction;
class RecoverReader
{
CompactBufferReader reader_;
uint32_t frameCount_;
uint32_t framesRead_; // Number of frame headers that have been read.
uint32_t pcOffset_; // Offset from script->code.
uint32_t allocCount_; // Number of slots.
// Number of encoded instructions.
uint32_t numInstructions_;
// Number of instruction read.
uint32_t numInstructionsRead_;
// True if we need to resume after the Resume Point instruction of the
// innermost frame.
bool resumeAfter_;
// Space is reserved as part of the RecoverReader to avoid allocations of
// data which is needed to decode the current instruction.
RInstructionStorage rawData_;
private:
void readRecoverHeader();
void readFrame(SnapshotReader &snapshot);
void readInstruction();
public:
RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
bool moreFrames() const {
return framesRead_ < frameCount_;
bool moreInstructions() const {
return numInstructionsRead_ < numInstructions_;
}
void nextFrame(SnapshotReader &snapshot) {
readFrame(snapshot);
}
uint32_t frameCount() const {
return frameCount_;
void nextInstruction() {
readInstruction();
}
uint32_t pcOffset() const {
return pcOffset_;
const RInstruction *instruction() const {
return reinterpret_cast<const RInstruction *>(rawData_.addr());
}
bool resumeAfter() const {
return resumeAfter_;
}
uint32_t allocations() const {
return allocCount_;
}
bool moreAllocations(const SnapshotReader &snapshot) const {
return snapshot.allocRead_ < allocCount_;
}
};
}

Просмотреть файл

@ -37,6 +37,25 @@
#include "jit/AsmJS.h"
#include "vm/Runtime.h"
extern "C" {
int64_t
__aeabi_idivmod(int x, int y)
{
uint32_t lo = uint32_t(x / y);
uint32_t hi = uint32_t(x % y);
return (int64_t(hi) << 32) | lo;
}
int64_t
__aeabi_uidivmod(int x, int y)
{
uint32_t lo = uint32_t(x) / uint32_t(y);
uint32_t hi = uint32_t(x) % uint32_t(y);
return (int64_t(hi) << 32) | lo;
}
}
namespace js {
namespace jit {
@ -4271,22 +4290,3 @@ JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
MOZ_ASSERT(!simulatorRuntime_);
simulatorRuntime_ = srt;
}
extern "C" {
int64_t
__aeabi_idivmod(int x, int y)
{
uint32_t lo = uint32_t(x / y);
uint32_t hi = uint32_t(x % y);
return (int64_t(hi) << 32) | lo;
}
int64_t
__aeabi_uidivmod(int x, int y)
{
uint32_t lo = uint32_t(x) / uint32_t(y);
uint32_t hi = uint32_t(x) % uint32_t(y);
return (int64_t(hi) << 32) | lo;
}
}

Просмотреть файл

@ -250,63 +250,12 @@ CodeGeneratorShared::encode(LRecoverInfo *recover)
RecoverOffset offset = recovers_.startRecover(frameCount, resumeAfter);
FlattenedMResumePointIter mirOperandIter(recover->mir());
if (!mirOperandIter.init())
return false;
for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
for (MResumePoint **it = recover->begin(), **end = recover->end();
it != end;
++it)
{
MResumePoint *mir = *it;
MBasicBlock *block = mir->block();
JSFunction *fun = block->info().funMaybeLazy();
JSScript *script = block->info().script();
jsbytecode *pc = mir->pc();
uint32_t exprStack = mir->stackDepth() - block->info().ninvoke();
recovers_.writeFrame(fun, script, pc, exprStack);
#ifdef DEBUG
// Ensure that all snapshot which are encoded can safely be used for
// bailouts.
if (GetIonContext()->cx) {
uint32_t stackDepth;
bool reachablePC;
jsbytecode *bailPC = pc;
if (mir->mode() == MResumePoint::ResumeAfter)
bailPC = GetNextPc(pc);
if (!ReconstructStackDepth(GetIonContext()->cx, script,
bailPC, &stackDepth, &reachablePC))
{
return false;
}
if (reachablePC) {
if (JSOp(*bailPC) == JSOP_FUNCALL) {
// For fun.call(this, ...); the reconstructStackDepth will
// include the this. When inlining that is not included.
// So the exprStackSlots will be one less.
JS_ASSERT(stackDepth - exprStack <= 1);
} else if (JSOp(*bailPC) != JSOP_FUNAPPLY &&
!IsGetPropPC(bailPC) && !IsSetPropPC(bailPC))
{
// For fun.apply({}, arguments) the reconstructStackDepth will
// have stackdepth 4, but it could be that we inlined the
// funapply. In that case exprStackSlots, will have the real
// arguments in the slots and not be 4.
// With accessors, we have different stack depths depending on
// whether or not we inlined the accessor, as the inlined stack
// contains a callee function that should never have been there
// and we might just be capturing an uneventful property site, in
// which case there won't have been any violence.
JS_ASSERT(exprStack == stackDepth);
}
}
}
#endif
if (!recovers_.writeFrame(*it))
return false;
}
recovers_.endRecover();
@ -320,14 +269,15 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
if (snapshot->snapshotOffset() != INVALID_SNAPSHOT_OFFSET)
return true;
if (!encode(snapshot->recoverInfo()))
LRecoverInfo *recoverInfo = snapshot->recoverInfo();
if (!encode(recoverInfo))
return false;
RecoverOffset recoverOffset = snapshot->recoverInfo()->recoverOffset();
RecoverOffset recoverOffset = recoverInfo->recoverOffset();
MOZ_ASSERT(recoverOffset != INVALID_RECOVER_OFFSET);
IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (LRecoverInfo %p)",
(void *)snapshot, (void*) snapshot->recoverInfo());
IonSpew(IonSpew_Snapshots, "Encoding LSnapshot %p (LRecover %p)",
(void *)snapshot, (void*) recoverInfo);
SnapshotOffset offset = snapshots_.startSnapshot(recoverOffset, snapshot->bailoutKind());
@ -351,12 +301,8 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
#endif
FlattenedMResumePointIter mirOperandIter(snapshot->recoverInfo()->mir());
if (!mirOperandIter.init())
return false;
uint32_t startIndex = 0;
for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
for (MResumePoint **it = recoverInfo->begin(), **end = recoverInfo->end();
it != end;
++it)
{

Просмотреть файл

@ -63,6 +63,9 @@ LIRGeneratorShared::getRecoverInfo(MResumePoint *rp)
return cachedRecoverInfo_;
LRecoverInfo *recoverInfo = LRecoverInfo::New(gen, rp);
if (!recoverInfo)
return nullptr;
cachedRecoverInfo_ = recoverInfo;
return recoverInfo;
}
@ -79,12 +82,8 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
if (!snapshot)
return nullptr;
FlattenedMResumePointIter iter(rp);
if (!iter.init())
return nullptr;
size_t i = 0;
for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) {
for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) {
MResumePoint *mir = *it;
for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) {
MDefinition *ins = mir->getOperand(j);
@ -137,12 +136,8 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
if (!snapshot)
return nullptr;
FlattenedMResumePointIter iter(rp);
if (!iter.init())
return nullptr;
size_t i = 0;
for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) {
for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) {
MResumePoint *mir = *it;
for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) {
MDefinition *def = mir->getOperand(j);

Просмотреть файл

@ -281,6 +281,7 @@ if CONFIG['ENABLE_ION']:
'jit/ParallelSafetyAnalysis.cpp',
'jit/PerfSpewer.cpp',
'jit/RangeAnalysis.cpp',
'jit/Recover.cpp',
'jit/RegisterAllocator.cpp',
'jit/Safepoints.cpp',
'jit/shared/BaselineCompiler-shared.cpp',

Просмотреть файл

@ -1376,7 +1376,7 @@ FrameIter::numFrameSlots() const
case JIT: {
#ifdef JS_ION
if (data_.ionFrames_.isIonJS()) {
return ionInlineFrames_.snapshotIterator().allocations() -
return ionInlineFrames_.snapshotIterator().numAllocations() -
ionInlineFrames_.script()->nfixed();
}
jit::BaselineFrame *frame = data_.ionFrames_.baselineFrame();

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше