mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to birch
This commit is contained in:
commit
fda0263af1
7
CLOBBER
7
CLOBBER
@ -17,6 +17,9 @@
|
||||
#
|
||||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||
#
|
||||
Bug 854517: Integrate valgrind into B2G builds
|
||||
|
||||
clobber needed due to changes in configure.in for js engine and gecko
|
||||
Bug 854517: Integrate valgrind into B2G builds
|
||||
Bug 874640 touched webidl, so Windows needs to clobber
|
||||
|
||||
Alternative to clobber is to run ./config.status from the objdir and to
|
||||
touch the CLOBBER file in the objdir.
|
||||
|
@ -116,6 +116,7 @@ this.AccessFu = {
|
||||
Services.obs.addObserver(this, 'Accessibility:NextObject', false);
|
||||
Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
|
||||
Services.obs.addObserver(this, 'Accessibility:Focus', false);
|
||||
Services.obs.addObserver(this, 'Accessibility:ActivateObject', false);
|
||||
Utils.win.addEventListener('TabOpen', this);
|
||||
Utils.win.addEventListener('TabClose', this);
|
||||
Utils.win.addEventListener('TabSelect', this);
|
||||
@ -157,6 +158,7 @@ this.AccessFu = {
|
||||
Services.obs.removeObserver(this, 'Accessibility:NextObject');
|
||||
Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
|
||||
Services.obs.removeObserver(this, 'Accessibility:Focus');
|
||||
Services.obs.removeObserver(this, 'Accessibility:ActivateObject');
|
||||
|
||||
if (this.doneCallback) {
|
||||
this.doneCallback();
|
||||
@ -259,6 +261,9 @@ this.AccessFu = {
|
||||
case 'Accessibility:PreviousObject':
|
||||
this.Input.moveCursor('movePrevious', 'Simple', 'gesture');
|
||||
break;
|
||||
case 'Accessibility:ActivateObject':
|
||||
this.Input.activateCurrent();
|
||||
break;
|
||||
case 'Accessibility:Focus':
|
||||
this._focused = JSON.parse(aData);
|
||||
if (this._focused) {
|
||||
|
@ -217,10 +217,19 @@ AndroidPresenter.prototype = {
|
||||
androidEvents.push({eventType: this.ANDROID_VIEW_HOVER_EXIT, text: []});
|
||||
}
|
||||
|
||||
let state = Utils.getStates(aContext.accessible)[0];
|
||||
|
||||
androidEvents.push({eventType: (isExploreByTouch) ?
|
||||
this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
|
||||
text: UtteranceGenerator.genForContext(aContext),
|
||||
bounds: aContext.bounds});
|
||||
bounds: aContext.bounds,
|
||||
clickable: aContext.accessible.actionCount > 0,
|
||||
checkable: !!(state &
|
||||
Ci.nsIAccessibleStates.STATE_CHECKABLE),
|
||||
checked: !!(state &
|
||||
Ci.nsIAccessibleStates.STATE_CHECKED)});
|
||||
|
||||
|
||||
return {
|
||||
type: this.type,
|
||||
details: androidEvents
|
||||
@ -228,11 +237,13 @@ AndroidPresenter.prototype = {
|
||||
},
|
||||
|
||||
actionInvoked: function AndroidPresenter_actionInvoked(aObject, aActionName) {
|
||||
let state = Utils.getStates(aObject)[0];
|
||||
return {
|
||||
type: this.type,
|
||||
details: [{
|
||||
eventType: this.ANDROID_VIEW_CLICKED,
|
||||
text: UtteranceGenerator.genForAction(aObject, aActionName)
|
||||
text: UtteranceGenerator.genForAction(aObject, aActionName),
|
||||
checked: !!(state & Ci.nsIAccessibleStates.STATE_CHECKED)
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
@ -347,7 +347,11 @@ this.UtteranceGenerator = {
|
||||
stateUtterances.push(gStringBundle.GetStringFromName('stateUnavailable'));
|
||||
}
|
||||
|
||||
if (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
|
||||
// Don't utter this in Jelly Bean, we let TalkBack do it for us there.
|
||||
// This is because we expose the checked information on the node itself.
|
||||
// XXX: this means the checked state is always appended to the end, regardless
|
||||
// of the utterance ordering preference.
|
||||
if (Utils.AndroidSdkVersion < 16 && aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
|
||||
let stateStr = (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKED) ?
|
||||
'stateChecked' : 'stateNotChecked';
|
||||
stateUtterances.push(gStringBundle.GetStringFromName(stateStr));
|
||||
|
@ -237,15 +237,13 @@ pref("ui.dragThresholdY", 25);
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
pref("dom.ipc.tabs.disabled", true);
|
||||
pref("layers.offmainthreadcomposition.enabled", false);
|
||||
pref("layers.offmainthreadcomposition.animate-opacity", false);
|
||||
pref("layers.offmainthreadcomposition.animate-transform", false);
|
||||
pref("layers.offmainthreadcomposition.async-animations", false);
|
||||
pref("layers.async-video.enabled", false);
|
||||
#else
|
||||
pref("dom.ipc.tabs.disabled", false);
|
||||
pref("layers.offmainthreadcomposition.enabled", true);
|
||||
pref("layers.acceleration.disabled", false);
|
||||
pref("layers.offmainthreadcomposition.animate-opacity", true);
|
||||
pref("layers.offmainthreadcomposition.animate-transform", true);
|
||||
pref("layers.offmainthreadcomposition.async-animations", true);
|
||||
pref("layers.async-video.enabled", true);
|
||||
pref("layers.async-pan-zoom.enabled", true);
|
||||
#endif
|
||||
|
@ -4,16 +4,11 @@
|
||||
|
||||
var kMaxChunkDuration = 30; // ms
|
||||
|
||||
var escape = document.createElement('textarea');
|
||||
|
||||
function escapeHTML(html) {
|
||||
escape.innerHTML = html;
|
||||
return escape.innerHTML;
|
||||
}
|
||||
|
||||
function unescapeHTML(html) {
|
||||
escape.innerHTML = html;
|
||||
return escape.value;
|
||||
var pre = document.createElementNS("http://www.w3.org/1999/xhtml", "pre");
|
||||
var text = document.createTextNode(html);
|
||||
pre.appendChild(text);
|
||||
return pre.innerHTML;
|
||||
}
|
||||
|
||||
RegExp.escape = function(text) {
|
||||
|
@ -36,6 +36,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "devtools",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "require",
|
||||
"resource://gre/modules/devtools/Require.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
||||
"resource:///modules/devtools/shared/event-emitter.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
|
||||
let prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService);
|
||||
@ -215,6 +218,8 @@ this.DeveloperToolbar = function DeveloperToolbar(aChromeWindow, aToolbarElement
|
||||
this._errorCounterButton._defaultTooltipText =
|
||||
this._errorCounterButton.getAttribute("tooltiptext");
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
try {
|
||||
CmdCommands.refreshAutoCommands(aChromeWindow);
|
||||
}
|
||||
@ -675,6 +680,8 @@ function DT__updateErrorsCount(aChangedTabId)
|
||||
btn.removeAttribute("error-count");
|
||||
btn.setAttribute("tooltiptext", btn._defaultTooltipText);
|
||||
}
|
||||
|
||||
this.emit("errors-counter-updated");
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -10,8 +10,7 @@ this.EXPORTED_SYMBOLS = ["SplitView"];
|
||||
/* this must be kept in sync with CSS (ie. splitview.css) */
|
||||
const LANDSCAPE_MEDIA_QUERY = "(min-width: 551px)";
|
||||
|
||||
const BINDING_USERDATA = "splitview-binding";
|
||||
|
||||
let bindings = new WeakMap();
|
||||
|
||||
/**
|
||||
* SplitView constructor
|
||||
@ -115,7 +114,7 @@ SplitView.prototype = {
|
||||
}
|
||||
|
||||
if (this._activeSummary) {
|
||||
let binding = this._activeSummary.getUserData(BINDING_USERDATA);
|
||||
let binding = bindings.get(this._activeSummary);
|
||||
|
||||
if (binding.onHide) {
|
||||
binding.onHide(this._activeSummary, binding._details, binding.data);
|
||||
@ -129,7 +128,7 @@ SplitView.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let binding = aSummary.getUserData(BINDING_USERDATA);
|
||||
let binding = bindings.get(aSummary);
|
||||
aSummary.classList.add("splitview-active");
|
||||
binding._details.classList.add("splitview-active");
|
||||
|
||||
@ -147,7 +146,7 @@ SplitView.prototype = {
|
||||
get activeDetails()
|
||||
{
|
||||
let summary = this.activeSummary;
|
||||
return summary ? summary.getUserData(BINDING_USERDATA)._details : null;
|
||||
return summary ? bindings.get(summary)._details : null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -193,7 +192,7 @@ SplitView.prototype = {
|
||||
|
||||
binding._summary = aSummary;
|
||||
binding._details = aDetails;
|
||||
aSummary.setUserData(BINDING_USERDATA, binding, null);
|
||||
bindings.set(aSummary, binding);
|
||||
|
||||
this._nav.appendChild(aSummary);
|
||||
|
||||
@ -258,7 +257,7 @@ SplitView.prototype = {
|
||||
this.activeSummary = null;
|
||||
}
|
||||
|
||||
let binding = aSummary.getUserData(BINDING_USERDATA);
|
||||
let binding = bindings.get(aSummary);
|
||||
aSummary.parentNode.removeChild(aSummary);
|
||||
binding._details.parentNode.removeChild(binding._details);
|
||||
|
||||
@ -289,7 +288,7 @@ SplitView.prototype = {
|
||||
*/
|
||||
setItemClassName: function ASV_setItemClassName(aSummary, aClassName)
|
||||
{
|
||||
let binding = aSummary.getUserData(BINDING_USERDATA);
|
||||
let binding = bindings.get(aSummary);
|
||||
let viewSpecific;
|
||||
|
||||
viewSpecific = aSummary.className.match(/(splitview\-[\w-]+)/g);
|
||||
|
@ -7,18 +7,23 @@ function test() {
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/" +
|
||||
"browser_toolbar_webconsole_errors_count.html";
|
||||
|
||||
let imported = {};
|
||||
Components.utils.import("resource:///modules/HUDService.jsm", imported);
|
||||
let HUDService = imported.HUDService;
|
||||
|
||||
Components.utils.import("resource:///modules/devtools/gDevTools.jsm", imported);
|
||||
let gDevTools = imported.gDevTools;
|
||||
let HUDService = Cu.import("resource:///modules/HUDService.jsm",
|
||||
{}).HUDService;
|
||||
let gDevTools = Cu.import("resource:///modules/devtools/gDevTools.jsm",
|
||||
{}).gDevTools;
|
||||
|
||||
let webconsole = document.getElementById("developer-toolbar-toolbox-button");
|
||||
let tab1, tab2;
|
||||
|
||||
Services.prefs.setBoolPref("javascript.options.strict", true);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("javascript.options.strict");
|
||||
});
|
||||
|
||||
ignoreAllUncaughtExceptions();
|
||||
addTab(TEST_URI, openToolbar);
|
||||
|
||||
function openToolbar(browser, tab) {
|
||||
tab1 = tab;
|
||||
ignoreAllUncaughtExceptions(false);
|
||||
@ -33,47 +38,6 @@ function test() {
|
||||
}
|
||||
}
|
||||
|
||||
ignoreAllUncaughtExceptions();
|
||||
addTab(TEST_URI, openToolbar);
|
||||
|
||||
function getErrorsCount() {
|
||||
let count = webconsole.getAttribute("error-count");
|
||||
return count ? count : "0";
|
||||
}
|
||||
|
||||
function getTooltipValues() {
|
||||
let matches = webconsole.getAttribute("tooltiptext")
|
||||
.match(/(\d+) errors?, (\d+) warnings?/);
|
||||
return matches ? [matches[1], matches[2]] : [0, 0];
|
||||
}
|
||||
|
||||
function waitForButtonUpdate(aOptions)
|
||||
{
|
||||
aOptions.validator = function() {
|
||||
let errors = getErrorsCount();
|
||||
let tooltip = getTooltipValues();
|
||||
let result = errors == aOptions.errors &&
|
||||
tooltip[1] == aOptions.warnings;
|
||||
if (result) {
|
||||
is(errors, tooltip[0], "button error-count is the same as in the tooltip");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
let originalFailure = aOptions.failure;
|
||||
aOptions.failure = function() {
|
||||
let tooltip = getTooltipValues();
|
||||
|
||||
info("expected " + aOptions.errors + " errors, " +
|
||||
aOptions.warnings + " warnings");
|
||||
info("got " + tooltip[0] + " errors, " + tooltip[1] + " warnings");
|
||||
|
||||
originalFailure();
|
||||
};
|
||||
|
||||
waitForValue(aOptions);
|
||||
}
|
||||
|
||||
function onOpenToolbar() {
|
||||
ok(DeveloperToolbar.visible, "DeveloperToolbar is visible");
|
||||
|
||||
@ -81,8 +45,7 @@ function test() {
|
||||
name: "web console button shows page errors",
|
||||
errors: 3,
|
||||
warnings: 0,
|
||||
success: addErrors,
|
||||
failure: finish,
|
||||
callback: addErrors,
|
||||
});
|
||||
}
|
||||
|
||||
@ -100,11 +63,10 @@ function test() {
|
||||
name: "button shows one more error after click in page",
|
||||
errors: 4,
|
||||
warnings: 1,
|
||||
success: function() {
|
||||
callback: () => {
|
||||
ignoreAllUncaughtExceptions();
|
||||
addTab(TEST_URI, onOpenSecondTab);
|
||||
},
|
||||
failure: finish,
|
||||
});
|
||||
}
|
||||
|
||||
@ -118,8 +80,7 @@ function test() {
|
||||
name: "button shows correct number of errors after new tab is open",
|
||||
errors: 3,
|
||||
warnings: 0,
|
||||
success: switchToTab1,
|
||||
failure: finish,
|
||||
callback: switchToTab1,
|
||||
});
|
||||
}
|
||||
|
||||
@ -129,28 +90,10 @@ function test() {
|
||||
name: "button shows the page errors from tab 1",
|
||||
errors: 4,
|
||||
warnings: 1,
|
||||
success: function() {
|
||||
openWebConsole(tab1, onWebConsoleOpen);
|
||||
},
|
||||
failure: finish,
|
||||
callback: openWebConsole.bind(null, tab1, onWebConsoleOpen),
|
||||
});
|
||||
}
|
||||
|
||||
function openWebConsole(tab, callback)
|
||||
{
|
||||
function _onWebConsoleOpen(subject)
|
||||
{
|
||||
subject.QueryInterface(Ci.nsISupportsString);
|
||||
let hud = HUDService.getHudReferenceById(subject.data);
|
||||
executeSoon(callback.bind(null, hud));
|
||||
}
|
||||
|
||||
oneTimeObserve("web-console-created", _onWebConsoleOpen);
|
||||
|
||||
let target = TargetFactory.forTab(tab);
|
||||
gDevTools.showToolbox(target, "webconsole");
|
||||
}
|
||||
|
||||
function onWebConsoleOpen(hud) {
|
||||
waitForValue({
|
||||
name: "web console shows the page errors",
|
||||
@ -185,10 +128,7 @@ function test() {
|
||||
name: "button shows one more error after another click in page",
|
||||
errors: 5,
|
||||
warnings: 1, // warnings are not repeated by the js engine
|
||||
success: function() {
|
||||
waitForValue(waitForNewError);
|
||||
},
|
||||
failure: finish,
|
||||
callback: () => waitForValue(waitForNewError),
|
||||
});
|
||||
|
||||
let waitForNewError = {
|
||||
@ -216,24 +156,23 @@ function test() {
|
||||
}
|
||||
|
||||
function doPageReload(hud) {
|
||||
tab1.linkedBrowser.addEventListener("load", function _onReload() {
|
||||
tab1.linkedBrowser.removeEventListener("load", _onReload, true);
|
||||
ignoreAllUncaughtExceptions(false);
|
||||
expectUncaughtException();
|
||||
}, true);
|
||||
tab1.linkedBrowser.addEventListener("load", onReload, true);
|
||||
|
||||
ignoreAllUncaughtExceptions();
|
||||
content.location.reload();
|
||||
|
||||
waitForButtonUpdate({
|
||||
name: "the Web Console button count has been reset after page reload",
|
||||
errors: 3,
|
||||
warnings: 0,
|
||||
success: function() {
|
||||
waitForValue(waitForConsoleOutputAfterReload);
|
||||
},
|
||||
failure: finish,
|
||||
});
|
||||
function onReload() {
|
||||
tab1.linkedBrowser.removeEventListener("load", onReload, true);
|
||||
ignoreAllUncaughtExceptions(false);
|
||||
expectUncaughtException();
|
||||
|
||||
waitForButtonUpdate({
|
||||
name: "the Web Console button count has been reset after page reload",
|
||||
errors: 3,
|
||||
warnings: 0,
|
||||
callback: waitForValue.bind(null, waitForConsoleOutputAfterReload),
|
||||
});
|
||||
}
|
||||
|
||||
let waitForConsoleOutputAfterReload = {
|
||||
name: "the Web Console displays the correct number of errors after reload",
|
||||
@ -256,16 +195,51 @@ function test() {
|
||||
gDevTools.closeToolbox(target1);
|
||||
gBrowser.removeTab(tab1);
|
||||
gBrowser.removeTab(tab2);
|
||||
Services.prefs.clearUserPref("javascript.options.strict");
|
||||
finish();
|
||||
}
|
||||
|
||||
function oneTimeObserve(name, callback) {
|
||||
function _onObserve(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(_onObserve, name);
|
||||
callback(aSubject, aTopic, aData);
|
||||
};
|
||||
Services.obs.addObserver(_onObserve, name, false);
|
||||
// Utility functions
|
||||
|
||||
function getErrorsCount() {
|
||||
let count = webconsole.getAttribute("error-count");
|
||||
return count ? count : "0";
|
||||
}
|
||||
|
||||
function getTooltipValues() {
|
||||
let matches = webconsole.getAttribute("tooltiptext")
|
||||
.match(/(\d+) errors?, (\d+) warnings?/);
|
||||
return matches ? [matches[1], matches[2]] : [0, 0];
|
||||
}
|
||||
|
||||
function waitForButtonUpdate(options) {
|
||||
function check() {
|
||||
let errors = getErrorsCount();
|
||||
let tooltip = getTooltipValues();
|
||||
let result = errors == options.errors && tooltip[1] == options.warnings;
|
||||
if (result) {
|
||||
ok(true, options.name);
|
||||
is(errors, tooltip[0], "button error-count is the same as in the tooltip");
|
||||
|
||||
// Get out of the toolbar event execution loop.
|
||||
executeSoon(options.callback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!check()) {
|
||||
info("wait for: " + options.name);
|
||||
DeveloperToolbar.on("errors-counter-updated", function onUpdate(event) {
|
||||
if (check()) {
|
||||
DeveloperToolbar.off(event, onUpdate);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function openWebConsole(tab, callback)
|
||||
{
|
||||
let target = TargetFactory.forTab(tab);
|
||||
gDevTools.showToolbox(target, "webconsole").then((toolbox) =>
|
||||
callback(toolbox.getCurrentPanel().hud));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,11 +127,10 @@ this.log = function log()
|
||||
* Selector string or DOMElement for the element(s) to wire up.
|
||||
* @param object aDescriptor
|
||||
* An object describing how to wire matching selector, supported properties
|
||||
* are "events", "attributes" and "userData" taking objects themselves.
|
||||
* Each key of properties above represents the name of the event, attribute
|
||||
* or userData, with the value being a function used as an event handler,
|
||||
* string to use as attribute value, or object to use as named userData
|
||||
* respectively.
|
||||
* are "events" and "attributes" taking objects themselves.
|
||||
* Each key of properties above represents the name of the event or
|
||||
* attribute, with the value being a function used as an event handler or
|
||||
* string to use as attribute value.
|
||||
* If aDescriptor is a function, the argument is equivalent to :
|
||||
* {events: {'click': aDescriptor}}
|
||||
*/
|
||||
@ -157,7 +156,6 @@ this.wire = function wire(aRoot, aSelectorOrElement, aDescriptor)
|
||||
element.addEventListener(aName, aHandler, false);
|
||||
});
|
||||
forEach(aDescriptor.attributes, element.setAttribute);
|
||||
forEach(aDescriptor.userData, element.setUserData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,7 @@ let Sync = {
|
||||
Services.obs.addObserver(self._boundOnEngineSync, "weave:engine:sync:error", false);
|
||||
Services.obs.addObserver(self._boundOnServiceSync, "weave:service:sync:finish", false);
|
||||
Services.obs.addObserver(self._boundOnServiceSync, "weave:service:sync:error", false);
|
||||
Services.obs.addObserver(self._boundOnServiceSync, "weave:service:login:error", false);
|
||||
self.setupData = aCredentials;
|
||||
self.connect();
|
||||
},
|
||||
@ -278,6 +279,7 @@ let Sync = {
|
||||
Services.obs.removeObserver(this._boundOnEngineSync, "weave:engine:sync:error");
|
||||
Services.obs.removeObserver(this._boundOnServiceSync, "weave:service:sync:finish");
|
||||
Services.obs.removeObserver(this._boundOnServiceSync, "weave:service:sync:error");
|
||||
Services.obs.removeObserver(this._boundOnServiceSync, "weave:service:login:error");
|
||||
}
|
||||
catch(e) {
|
||||
// Observers weren't registered because we never got as far as onComplete.
|
||||
@ -567,7 +569,7 @@ let Sync = {
|
||||
let accountinfo = this._elements.accountinfo;
|
||||
|
||||
// Show what went wrong with login if necessary
|
||||
if (aTopic == "weave:ui:login:error") {
|
||||
if (aTopic == "weave:ui:login:error" || aTopic == "weave:service:login:error") {
|
||||
this._loginError = true;
|
||||
errormsg.textContent = Weave.Utils.getErrorString(Weave.Status.login);
|
||||
errormsg.collapsed = false;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -287,15 +287,15 @@ documenttab[selected] .documenttab-selection {
|
||||
#identity-icon {
|
||||
margin: 0;
|
||||
padding: 0 @metro_spacing_snormal@;
|
||||
list-style-image: url(chrome://browser/skin/images/identity-icons-generic.png);
|
||||
list-style-image: url("chrome://browser/skin/images/identity-icons-generic.png");
|
||||
}
|
||||
|
||||
#identity-box-inner.verifiedDomain > #identity-icon {
|
||||
list-style-image: url(chrome://browser/skin/images/locked-hdpi.png);
|
||||
list-style-image: url("chrome://browser/skin/images/identity-icons-https.png");
|
||||
}
|
||||
|
||||
#identity-box-inner.verifiedIdentity > #identity-icon {
|
||||
list-style-image: url(chrome://browser/skin/images/locked-hdpi.png);
|
||||
list-style-image: url("chrome://browser/skin/images/identity-icons-https-ev.png");
|
||||
}
|
||||
|
||||
/* Main URL textbox */
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 233 B |
Binary file not shown.
Before Width: | Height: | Size: 500 B After Width: | Height: | Size: 248 B |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
@ -67,8 +67,6 @@ chrome.jar:
|
||||
skin/images/identity-default-hdpi.png (images/identity-default-hdpi.png)
|
||||
skin/images/identity-ssl-hdpi.png (images/identity-ssl-hdpi.png)
|
||||
skin/images/identity-ev-hdpi.png (images/identity-ev-hdpi.png)
|
||||
skin/images/unlocked-hdpi.png (images/unlocked-hdpi.png)
|
||||
skin/images/locked-hdpi.png (images/locked-hdpi.png)
|
||||
skin/images/search-glass-30.png (images/search-glass-30.png)
|
||||
skin/images/play-hdpi.png (images/play-hdpi.png)
|
||||
skin/images/pause-hdpi.png (images/pause-hdpi.png)
|
||||
|
@ -6,6 +6,7 @@ parsing command lines into argv and making sure that no shell magic is being use
|
||||
#TODO: ship pyprocessing?
|
||||
import multiprocessing
|
||||
import subprocess, shlex, re, logging, sys, traceback, os, imp, glob
|
||||
from collections import deque
|
||||
# XXXkhuey Work around http://bugs.python.org/issue1731717
|
||||
subprocess._cleanup = lambda: None
|
||||
import command, util
|
||||
@ -439,7 +440,7 @@ class ParallelContext(object):
|
||||
self.exit = False
|
||||
|
||||
self.processpool = multiprocessing.Pool(processes=jcount)
|
||||
self.pending = [] # list of (cb, args, kwargs)
|
||||
self.pending = deque() # deque of (cb, args, kwargs)
|
||||
self.running = [] # list of (subprocess, cb)
|
||||
|
||||
self._allcontexts.add(self)
|
||||
@ -452,7 +453,7 @@ class ParallelContext(object):
|
||||
|
||||
def run(self):
|
||||
while len(self.pending) and len(self.running) < self.jcount:
|
||||
cb, args, kwargs = self.pending.pop(0)
|
||||
cb, args, kwargs = self.pending.popleft()
|
||||
cb(*args, **kwargs)
|
||||
|
||||
def defer(self, cb, *args, **kwargs):
|
||||
|
@ -14,8 +14,7 @@ PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS))
|
||||
###############
|
||||
export_tier_%:
|
||||
@$(ECHO) "$@"
|
||||
@$(MAKE_TIER_SUBMAKEFILES)
|
||||
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,export,$(dir)))
|
||||
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,export,$(dir)))
|
||||
|
||||
#################
|
||||
## Common targets
|
||||
|
@ -14,8 +14,7 @@ PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS))
|
||||
###############
|
||||
libs_tier_%:
|
||||
@$(ECHO) "$@"
|
||||
@$(MAKE_TIER_SUBMAKEFILES)
|
||||
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,libs,$(dir)))
|
||||
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,libs,$(dir)))
|
||||
|
||||
#################
|
||||
## Common targets
|
||||
|
@ -14,8 +14,7 @@ PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS))
|
||||
###############
|
||||
tools_tier_%:
|
||||
@$(ECHO) "$@"
|
||||
@$(MAKE_TIER_SUBMAKEFILES)
|
||||
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,tools,$(dir)))
|
||||
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,tools,$(dir)))
|
||||
|
||||
#################
|
||||
## Common targets
|
||||
|
@ -425,6 +425,14 @@ define SUBMAKE # $(call SUBMAKE,target,directory)
|
||||
|
||||
endef # The extra line is important here! don't delete it
|
||||
|
||||
define TIER_DIR_SUBMAKE
|
||||
@echo "BUILDSTATUS TIERDIR_START $(2)"
|
||||
$(call SUBMAKE,$(1),$(2))
|
||||
@echo "BUILDSTATUS TIERDIR_FINISH $(2)"
|
||||
|
||||
endef # Ths empty line is important.
|
||||
|
||||
|
||||
ifneq (,$(strip $(DIRS)))
|
||||
LOOP_OVER_DIRS = \
|
||||
$(foreach dir,$(DIRS),$(call SUBMAKE,$@,$(dir)))
|
||||
@ -627,6 +635,16 @@ endif
|
||||
# other rules for the default target or else it may not run in time.
|
||||
ifndef MOZBUILD_BACKEND_CHECKED
|
||||
|
||||
# Since Makefile is listed as a global dependency, this has the
|
||||
# unfortunate side-effect of invalidating all targets if it is executed.
|
||||
# So e.g. if you are in /dom/bindings and /foo/moz.build changes,
|
||||
# /dom/bindings will get invalidated. The upside is if the current
|
||||
# Makefile/backend.mk is updated as a result of backend regeneration, we
|
||||
# actually pick up the changes. This should reduce the amount of
|
||||
# required clobbers and is thus the lesser evil.
|
||||
Makefile: $(DEPTH)/backend.RecursiveMakeBackend.built
|
||||
@$(TOUCH) $@
|
||||
|
||||
$(DEPTH)/backend.RecursiveMakeBackend.built:
|
||||
@echo "Build configuration changed. Regenerating backend."
|
||||
@cd $(DEPTH) && $(PYTHON) ./config.status
|
||||
@ -650,6 +668,7 @@ SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS))
|
||||
ifndef SUPPRESS_DEFAULT_RULES
|
||||
ifdef TIERS
|
||||
default all alldep::
|
||||
@echo "BUILDSTATUS TIERS $(TIERS)"
|
||||
$(foreach tier,$(TIERS),$(call SUBMAKE,tier_$(tier)))
|
||||
else
|
||||
|
||||
@ -679,14 +698,44 @@ ECHO := true
|
||||
QUIET := -q
|
||||
endif
|
||||
|
||||
MAKE_TIER_SUBMAKEFILES = +$(if $(tier_$*_dirs),$(MAKE) $(addsuffix /Makefile,$(tier_$*_dirs)))
|
||||
# This function is called and evaluated to produce the rule to build the
|
||||
# specified tier. Each tier begins by building the "static" directories.
|
||||
# The BUILDSTATUS echo commands are used to faciliate easier parsing
|
||||
# of build output. Build drivers are encouraged to filter these lines
|
||||
# from the user.
|
||||
define CREATE_TIER_RULE
|
||||
tier_$(1)::
|
||||
@echo "BUILDSTATUS TIER_START $(1)"
|
||||
@printf "BUILDSTATUS SUBTIERS"
|
||||
ifneq (,$(tier_$(1)_staticdirs))
|
||||
@printf " static"
|
||||
endif
|
||||
ifneq (,$(tier_$(1)_dirs))
|
||||
@printf " export libs tools"
|
||||
endif
|
||||
@printf "\n"
|
||||
@echo "BUILDSTATUS STATICDIRS $$($$@_staticdirs)"
|
||||
@echo "BUILDSTATUS DIRS $$($$@_dirs)"
|
||||
ifneq (,$(tier_$(1)_staticdirs))
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) static"
|
||||
$$(foreach dir,$$($$@_staticdirs),$$(call TIER_DIR_SUBMAKE,,$$(dir)))
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) static"
|
||||
endif
|
||||
ifneq (,$(tier_$(1)_dirs))
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) export"
|
||||
$$(MAKE) export_$$@
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) export"
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) libs"
|
||||
$$(MAKE) libs_$$@
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) libs"
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) tools"
|
||||
$$(MAKE) tools_$$@
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) tools"
|
||||
@echo "BUILDSTATUS TIER_FINISH $(1)"
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach tier,$(TIERS),tier_$(tier))::
|
||||
@$(ECHO) "$@: $($@_staticdirs) $($@_dirs)"
|
||||
$(foreach dir,$($@_staticdirs),$(call SUBMAKE,,$(dir)))
|
||||
$(MAKE) export_$@
|
||||
$(MAKE) libs_$@
|
||||
$(MAKE) tools_$@
|
||||
$(foreach tier,$(TIERS),$(eval $(call CREATE_TIER_RULE,$(tier))))
|
||||
|
||||
# Do everything from scratch
|
||||
everything::
|
||||
|
@ -1135,68 +1135,18 @@ WebSocket::UpdateURI()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocket::RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture)
|
||||
void
|
||||
WebSocket::EventListenerAdded(nsIAtom* aType)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsresult rv = nsDOMEventTargetHelper::RemoveEventListener(aType,
|
||||
aListener,
|
||||
aUseCapture);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
return rv;
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
ErrorResult& aRv)
|
||||
WebSocket::EventListenerRemoved(nsIAtom* aType)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsDOMEventTargetHelper::RemoveEventListener(aType, aListener,
|
||||
aUseCapture, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocket::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted,
|
||||
uint8_t optional_argc)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsresult rv = nsDOMEventTargetHelper::AddEventListener(aType,
|
||||
aListener,
|
||||
aUseCapture,
|
||||
aWantsUntrusted,
|
||||
optional_argc);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture,
|
||||
aWantsUntrusted, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// WebSocket - methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -71,24 +71,9 @@ public:
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
// nsIDOMEventTarget
|
||||
NS_IMETHOD AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted,
|
||||
uint8_t optional_argc);
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
NS_IMETHOD RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture);
|
||||
virtual void RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
// EventTarget
|
||||
virtual void EventListenerAdded(nsIAtom* aType) MOZ_OVERRIDE;
|
||||
virtual void EventListenerRemoved(nsIAtom* aType) MOZ_OVERRIDE;
|
||||
|
||||
virtual void DisconnectFromOwner();
|
||||
|
||||
|
@ -1402,10 +1402,12 @@ nsFrameMessageManager*
|
||||
nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::ContentParent* aProcess)
|
||||
{
|
||||
if (!nsFrameMessageManager::sParentProcessManager) {
|
||||
nsCOMPtr<nsIMessageBroadcaster> dummy;
|
||||
NS_NewParentProcessMessageManager(getter_AddRefs(dummy));
|
||||
nsCOMPtr<nsIMessageBroadcaster> dummy =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
}
|
||||
|
||||
MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager,
|
||||
"parent process manager not created");
|
||||
nsFrameMessageManager* mm;
|
||||
if (aProcess) {
|
||||
mm = new nsFrameMessageManager(aProcess,
|
||||
|
@ -2145,7 +2145,7 @@ nsObjectLoadingContent::DestroyContent()
|
||||
mFrameLoader = nullptr;
|
||||
}
|
||||
|
||||
StopPluginInstance();
|
||||
QueueCheckPluginStopEvent();
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -60,6 +60,10 @@ public:
|
||||
return SetEventHandler(type, aHandler, rv);
|
||||
}
|
||||
|
||||
// Note, for an event 'foo' aType will be 'onfoo'.
|
||||
virtual void EventListenerAdded(nsIAtom* aType) {}
|
||||
virtual void EventListenerRemoved(nsIAtom* aType) {}
|
||||
|
||||
protected:
|
||||
EventHandlerNonNull* GetEventHandler(nsIAtom* aType);
|
||||
void SetEventHandler(nsIAtom* aType, EventHandlerNonNull* aHandler,
|
||||
|
@ -101,7 +101,7 @@ MutationBitForEventType(uint32_t aEventType)
|
||||
|
||||
uint32_t nsEventListenerManager::sCreatedCount = 0;
|
||||
|
||||
nsEventListenerManager::nsEventListenerManager(nsISupports* aTarget) :
|
||||
nsEventListenerManager::nsEventListenerManager(EventTarget* aTarget) :
|
||||
mMayHavePaintEventListener(false),
|
||||
mMayHaveMutationListeners(false),
|
||||
mMayHaveCapturingListeners(false),
|
||||
@ -352,6 +352,9 @@ nsEventListenerManager::AddEventListenerInternal(
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (aTypeAtom && mTarget) {
|
||||
mTarget->EventListenerAdded(aTypeAtom);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -464,6 +467,9 @@ nsEventListenerManager::RemoveEventListenerInternal(
|
||||
--count;
|
||||
mNoListenerForEvent = NS_EVENT_TYPE_NULL;
|
||||
mNoListenerForEventAtom = nullptr;
|
||||
if (mTarget && aUserType) {
|
||||
mTarget->EventListenerRemoved(aUserType);
|
||||
}
|
||||
|
||||
if (!deviceType
|
||||
#ifdef MOZ_B2G
|
||||
@ -748,6 +754,9 @@ nsEventListenerManager::RemoveEventHandler(nsIAtom* aName)
|
||||
mListeners.RemoveElementAt(uint32_t(ls - &mListeners.ElementAt(0)));
|
||||
mNoListenerForEvent = NS_EVENT_TYPE_NULL;
|
||||
mNoListenerForEventAtom = nullptr;
|
||||
if (mTarget) {
|
||||
mTarget->EventListenerRemoved(aName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,7 @@ class nsEventListenerManager
|
||||
{
|
||||
|
||||
public:
|
||||
nsEventListenerManager(nsISupports* aTarget);
|
||||
nsEventListenerManager(mozilla::dom::EventTarget* aTarget);
|
||||
virtual ~nsEventListenerManager();
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsEventListenerManager)
|
||||
@ -404,7 +404,7 @@ public:
|
||||
|
||||
void MarkForCC();
|
||||
|
||||
nsISupports* GetTarget() { return mTarget; }
|
||||
mozilla::dom::EventTarget* GetTarget() { return mTarget; }
|
||||
protected:
|
||||
void HandleEventInternal(nsPresContext* aPresContext,
|
||||
nsEvent* aEvent,
|
||||
@ -533,7 +533,7 @@ protected:
|
||||
uint32_t mNoListenerForEvent : 24;
|
||||
|
||||
nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
|
||||
nsISupports* mTarget; //WEAK
|
||||
mozilla::dom::EventTarget* mTarget; //WEAK
|
||||
nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
|
||||
|
||||
static uint32_t mInstanceCount;
|
||||
|
@ -48,6 +48,7 @@ enum ButtonElementTypes {
|
||||
enum InputElementTypes {
|
||||
NS_FORM_INPUT_BUTTON = NS_FORM_INPUT_ELEMENT + 1,
|
||||
NS_FORM_INPUT_CHECKBOX,
|
||||
NS_FORM_INPUT_COLOR,
|
||||
NS_FORM_INPUT_DATE,
|
||||
NS_FORM_INPUT_EMAIL,
|
||||
NS_FORM_INPUT_FILE,
|
||||
|
@ -133,6 +133,7 @@ UploadLastDir* HTMLInputElement::gUploadLastDir;
|
||||
static const nsAttrValue::EnumTable kInputTypeTable[] = {
|
||||
{ "button", NS_FORM_INPUT_BUTTON },
|
||||
{ "checkbox", NS_FORM_INPUT_CHECKBOX },
|
||||
{ "color", NS_FORM_INPUT_COLOR },
|
||||
{ "date", NS_FORM_INPUT_DATE },
|
||||
{ "email", NS_FORM_INPUT_EMAIL },
|
||||
{ "file", NS_FORM_INPUT_FILE },
|
||||
@ -153,7 +154,7 @@ static const nsAttrValue::EnumTable kInputTypeTable[] = {
|
||||
};
|
||||
|
||||
// Default type is 'text'.
|
||||
static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[15];
|
||||
static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[16];
|
||||
|
||||
static const uint8_t NS_INPUT_AUTOCOMPLETE_OFF = 0;
|
||||
static const uint8_t NS_INPUT_AUTOCOMPLETE_ON = 1;
|
||||
@ -383,6 +384,24 @@ HTMLInputElement::AsyncClickHandler::AsyncClickHandler(HTMLInputElement* aInput)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::AsyncClickHandler::Run()
|
||||
{
|
||||
if (mInput->GetType() == NS_FORM_INPUT_FILE) {
|
||||
return InitFilePicker();
|
||||
} else if (mInput->GetType() == NS_FORM_INPUT_COLOR) {
|
||||
return InitColorPicker();
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLInputElement::AsyncClickHandler::InitColorPicker()
|
||||
{
|
||||
// TODO
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLInputElement::AsyncClickHandler::InitFilePicker()
|
||||
{
|
||||
// Get parent nsPIDOMWindow object.
|
||||
nsCOMPtr<nsIDocument> doc = mInput->OwnerDoc();
|
||||
@ -3149,13 +3168,15 @@ HTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
||||
PostHandleEventForRangeThumb(aVisitor);
|
||||
}
|
||||
|
||||
// Open a file picker when we receive a click on a <input type='file'>.
|
||||
// Open a file picker when we receive a click on a <input type='file'>, or
|
||||
// open a color picker when we receive a click on a <input type='color'>.
|
||||
// A click is handled in the following cases:
|
||||
// - preventDefault() has not been called (or something similar);
|
||||
// - it's the left mouse button.
|
||||
// We do not prevent non-trusted click because authors can already use
|
||||
// .click(). However, the file picker will follow the rules of popup-blocking.
|
||||
if (mType == NS_FORM_INPUT_FILE && NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) &&
|
||||
if ((mType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_COLOR) &&
|
||||
NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) &&
|
||||
!aVisitor.mEvent->mFlags.mDefaultPrevented) {
|
||||
return FireAsyncClickHandler();
|
||||
}
|
||||
@ -3539,9 +3560,35 @@ HTMLInputElement::SanitizeValue(nsAString& aValue)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_FORM_INPUT_COLOR:
|
||||
{
|
||||
if (IsValidSimpleColor(aValue)) {
|
||||
ToLowerCase(aValue);
|
||||
} else {
|
||||
// Set default (black) color, if aValue wasn't parsed correctly.
|
||||
aValue.AssignLiteral("#000000");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool HTMLInputElement::IsValidSimpleColor(const nsAString& aValue) const
|
||||
{
|
||||
if (aValue.Length() != 7 || aValue.First() != '#') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < 7; ++i) {
|
||||
if (!nsCRT::IsAsciiDigit(aValue[i]) &&
|
||||
!(aValue[i] >= 'a' && aValue[i] <= 'f') &&
|
||||
!(aValue[i] >= 'A' && aValue[i] <= 'F')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLInputElement::IsValidDate(const nsAString& aValue) const
|
||||
{
|
||||
@ -3747,7 +3794,9 @@ HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
|
||||
if ((IsExperimentalMobileType(newType) &&
|
||||
!Preferences::GetBool("dom.experimental_forms", false)) ||
|
||||
(newType == NS_FORM_INPUT_RANGE &&
|
||||
!Preferences::GetBool("dom.experimental_forms_range", false))) {
|
||||
!Preferences::GetBool("dom.experimental_forms_range", false)) ||
|
||||
(newType == NS_FORM_INPUT_COLOR &&
|
||||
!Preferences::GetBool("dom.forms.color", false))) {
|
||||
newType = kInputDefaultType->value;
|
||||
aResult.SetTo(newType, &aValue);
|
||||
}
|
||||
@ -4851,6 +4900,7 @@ HTMLInputElement::GetValueMode() const
|
||||
case NS_FORM_INPUT_RANGE:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
case NS_FORM_INPUT_TIME:
|
||||
case NS_FORM_INPUT_COLOR:
|
||||
return VALUE_MODE_VALUE;
|
||||
default:
|
||||
NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
|
||||
@ -4884,8 +4934,7 @@ HTMLInputElement::DoesReadOnlyApply() const
|
||||
case NS_FORM_INPUT_FILE:
|
||||
case NS_FORM_INPUT_CHECKBOX:
|
||||
case NS_FORM_INPUT_RANGE:
|
||||
// TODO:
|
||||
// case NS_FORM_INPUT_COLOR:
|
||||
case NS_FORM_INPUT_COLOR:
|
||||
return false;
|
||||
#ifdef DEBUG
|
||||
case NS_FORM_INPUT_TEXT:
|
||||
@ -4919,8 +4968,7 @@ HTMLInputElement::DoesRequiredApply() const
|
||||
case NS_FORM_INPUT_RESET:
|
||||
case NS_FORM_INPUT_SUBMIT:
|
||||
case NS_FORM_INPUT_RANGE:
|
||||
// TODO:
|
||||
// case NS_FORM_INPUT_COLOR:
|
||||
case NS_FORM_INPUT_COLOR:
|
||||
return false;
|
||||
#ifdef DEBUG
|
||||
case NS_FORM_INPUT_RADIO:
|
||||
@ -4995,6 +5043,7 @@ HTMLInputElement::DoesMinMaxApply() const
|
||||
case NS_FORM_INPUT_TEL:
|
||||
case NS_FORM_INPUT_EMAIL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
case NS_FORM_INPUT_COLOR:
|
||||
return false;
|
||||
default:
|
||||
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
|
||||
|
@ -971,6 +971,14 @@ protected:
|
||||
*/
|
||||
bool ConvertNumberToString(Decimal aValue, nsAString& aResultString) const;
|
||||
|
||||
/**
|
||||
* Parse a color string of the form #XXXXXX where X should be hexa characters
|
||||
* @param the string to be parsed.
|
||||
* @return whether the string is a valid simple color.
|
||||
* Note : this function does not consider the empty string as valid.
|
||||
*/
|
||||
bool IsValidSimpleColor(const nsAString& aValue) const;
|
||||
|
||||
/**
|
||||
* Parse a date string of the form yyyy-mm-dd
|
||||
* @param the string to be parsed.
|
||||
@ -1229,6 +1237,9 @@ private:
|
||||
NS_IMETHOD Run();
|
||||
|
||||
protected:
|
||||
nsresult InitFilePicker();
|
||||
nsresult InitColorPicker();
|
||||
|
||||
nsRefPtr<HTMLInputElement> mInput;
|
||||
PopupControlState mPopupControlState;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(ValidityState)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(ValidityState, mConstraintValidation)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ValidityState)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ValidityState)
|
||||
|
||||
|
@ -74,16 +74,6 @@ public:
|
||||
protected:
|
||||
ValidityState(nsIConstraintValidation* aConstraintValidation);
|
||||
|
||||
/**
|
||||
* This function should be called by nsIConstraintValidation
|
||||
* to set mConstraintValidation to null to be sure
|
||||
* it will not be used when the object is destroyed.
|
||||
*/
|
||||
inline void Disconnect()
|
||||
{
|
||||
mConstraintValidation = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get a validity state from constraint validation instance.
|
||||
*/
|
||||
@ -93,8 +83,7 @@ protected:
|
||||
mConstraintValidation->GetValidityState(aState);
|
||||
}
|
||||
|
||||
// Weak reference to owner which will call Disconnect() when being destroyed.
|
||||
nsIConstraintValidation* mConstraintValidation;
|
||||
nsCOMPtr<nsIConstraintValidation> mConstraintValidation;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -171,6 +171,7 @@ ShouldBeInElements(nsIFormControl* aFormControl)
|
||||
case NS_FORM_BUTTON_SUBMIT :
|
||||
case NS_FORM_INPUT_BUTTON :
|
||||
case NS_FORM_INPUT_CHECKBOX :
|
||||
case NS_FORM_INPUT_COLOR :
|
||||
case NS_FORM_INPUT_EMAIL :
|
||||
case NS_FORM_INPUT_FILE :
|
||||
case NS_FORM_INPUT_HIDDEN :
|
||||
|
@ -23,9 +23,6 @@ nsIConstraintValidation::nsIConstraintValidation()
|
||||
|
||||
nsIConstraintValidation::~nsIConstraintValidation()
|
||||
{
|
||||
if (mValidity) {
|
||||
mValidity->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::dom::ValidityState*
|
||||
|
@ -61,6 +61,7 @@ MOCHITEST_FILES = \
|
||||
test_input_file_picker.html \
|
||||
test_input_event.html \
|
||||
test_input_number_rounding.html \
|
||||
test_valueAsDate_pref.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -206,11 +206,10 @@ reflectLimitedEnumerated({
|
||||
attribute: "type",
|
||||
validValues: [ "hidden", "text", "search", "tel", "url", "email", "password",
|
||||
"checkbox", "radio", "file", "submit", "image", "reset",
|
||||
"button", "date", "time", "number", "range" ],
|
||||
"button", "date", "time", "number", "range", "color" ],
|
||||
invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ],
|
||||
defaultValue: "text",
|
||||
unsupportedValues: [ "datetime", "month", "week", "datetime-local",
|
||||
"color" ]
|
||||
unsupportedValues: [ "datetime", "month", "week", "datetime-local" ]
|
||||
});
|
||||
|
||||
// .defaultValue
|
||||
|
@ -42,12 +42,11 @@ var inputTypes =
|
||||
[
|
||||
"text", "password", "search", "tel", "hidden", "checkbox", "radio",
|
||||
"submit", "image", "reset", "button", "email", "url", "number", "date",
|
||||
"time", "range"
|
||||
"time", "range", "color"
|
||||
];
|
||||
|
||||
var todoTypes =
|
||||
[
|
||||
"color",
|
||||
"month", "week", "datetime", "datetime-local",
|
||||
];
|
||||
|
||||
@ -152,9 +151,7 @@ function sanitizeValue(aType, aValue)
|
||||
ok(false);
|
||||
return "";
|
||||
case "color":
|
||||
ok(false);
|
||||
// TODO: write the sanitize algorithm.
|
||||
return "";
|
||||
return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000";
|
||||
default:
|
||||
return aValue;
|
||||
}
|
||||
@ -290,6 +287,17 @@ function checkSanitizing(element)
|
||||
"13:37:42.",
|
||||
"foo12:12",
|
||||
"13:37:42.100000000000",
|
||||
// For color
|
||||
"#00ff00",
|
||||
"#000000",
|
||||
"red",
|
||||
"#0f0",
|
||||
"#FFFFAA",
|
||||
"FFAABB",
|
||||
"fFAaBb",
|
||||
"FFAAZZ",
|
||||
"ABCDEF",
|
||||
"#7654321",
|
||||
];
|
||||
|
||||
for (value of testData) {
|
||||
|
@ -170,7 +170,6 @@ function runTest()
|
||||
{ type: 'month', todo: true },
|
||||
{ type: 'datetime', todo: true },
|
||||
{ type: 'datetime-local', todo: true },
|
||||
{ type: 'color', todo: true },
|
||||
];
|
||||
|
||||
for (test of data) {
|
||||
|
@ -35,7 +35,7 @@ var data = [
|
||||
{ type: 'datetime-local', apply: true, todo: true },
|
||||
{ type: 'number', apply: true },
|
||||
{ type: 'range', apply: true },
|
||||
{ type: 'color', apply: false, todo: true },
|
||||
{ type: 'color', apply: false },
|
||||
{ type: 'checkbox', apply: false },
|
||||
{ type: 'radio', apply: false },
|
||||
{ type: 'file', apply: false },
|
||||
@ -125,6 +125,7 @@ for (var test of data) {
|
||||
case 'reset':
|
||||
case 'button':
|
||||
case 'image':
|
||||
case 'color':
|
||||
input.max = '-1';
|
||||
break;
|
||||
case 'date':
|
||||
|
@ -35,7 +35,7 @@ var data = [
|
||||
{ type: 'datetime-local', apply: true, todo: true },
|
||||
{ type: 'number', apply: true },
|
||||
{ type: 'range', apply: true },
|
||||
{ type: 'color', apply: false, todo: true },
|
||||
{ type: 'color', apply: false },
|
||||
{ type: 'checkbox', apply: false },
|
||||
{ type: 'radio', apply: false },
|
||||
{ type: 'file', apply: false },
|
||||
@ -124,6 +124,7 @@ for (var test of data) {
|
||||
case 'reset':
|
||||
case 'button':
|
||||
case 'image':
|
||||
case 'color':
|
||||
input.min = '999';
|
||||
break;
|
||||
case 'date':
|
||||
@ -156,6 +157,7 @@ for (var test of data) {
|
||||
case 'button':
|
||||
case 'submit':
|
||||
case 'image':
|
||||
case 'color':
|
||||
input.value = '0';
|
||||
checkValidity(input, true, apply, apply);
|
||||
break;
|
||||
|
@ -51,6 +51,7 @@ var gInputTestData = [
|
||||
['range', false],
|
||||
['date', false],
|
||||
['time', false],
|
||||
['color', false],
|
||||
];
|
||||
|
||||
/**
|
||||
@ -59,7 +60,6 @@ var gInputTestData = [
|
||||
*/
|
||||
var gInputTodoData = [
|
||||
/* type expected result */
|
||||
['color', false],
|
||||
['datetime', false],
|
||||
['month', false],
|
||||
['week', false],
|
||||
|
@ -261,8 +261,8 @@ var input = document.getElementById('i');
|
||||
// and |invalidTypes| are the ones which do not accept it.
|
||||
var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url');
|
||||
var barredTypes = Array('hidden', 'reset', 'button', 'submit', 'image');
|
||||
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', 'time');
|
||||
// TODO: 'datetime', 'month', 'week', 'datetime-local' and 'color'
|
||||
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', 'time', 'color');
|
||||
// TODO: 'datetime', 'month', 'week', and 'datetime-local'
|
||||
// do not accept the @pattern too but are not implemented yet.
|
||||
|
||||
for (type of validTypes) {
|
||||
|
@ -367,8 +367,7 @@ for (type of typeBarredFromConstraintValidation) {
|
||||
}
|
||||
|
||||
// Then, checks for the types which do not use the required attribute.
|
||||
// TODO: check 'color' when they will be implemented.
|
||||
var typeRequireNotApply = ['range'];
|
||||
var typeRequireNotApply = ['range', 'color'];
|
||||
for (type of typeRequireNotApply) {
|
||||
checkInputRequiredNotApply(type, false);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ var data = [
|
||||
{ type: 'datetime-local', apply: true, todo: true },
|
||||
{ type: 'number', apply: true },
|
||||
{ type: 'range', apply: true },
|
||||
{ type: 'color', apply: false, todo: true },
|
||||
{ type: 'color', apply: false },
|
||||
{ type: 'checkbox', apply: false },
|
||||
{ type: 'radio', apply: false },
|
||||
{ type: 'file', apply: false },
|
||||
@ -111,6 +111,7 @@ for (var test of data) {
|
||||
case 'button':
|
||||
case 'submit':
|
||||
case 'image':
|
||||
case 'color':
|
||||
input.value = '0';
|
||||
checkValidity(input, true, apply);
|
||||
break;
|
||||
|
@ -50,8 +50,6 @@ function checkAvailability()
|
||||
["range", true],
|
||||
["date", true],
|
||||
["time", true],
|
||||
// The next types have not been implemented but will fallback to "text"
|
||||
// which has the same value.
|
||||
["color", false],
|
||||
];
|
||||
|
||||
|
46
content/html/content/test/forms/test_valueAsDate_pref.html
Normal file
46
content/html/content/test/forms/test_valueAsDate_pref.html
Normal file
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=874640
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 874640</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 874640 **/
|
||||
var states = [ 'true', 'false', 'end' ];
|
||||
var pref = SpecialPowers.getBoolPref("dom.experimental_forms");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest(iframe) {
|
||||
var state = states.shift();
|
||||
|
||||
if (state == 'end') {
|
||||
SpecialPowers.setBoolPref("dom.experimental_forms", pref);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
SpecialPowers.setBoolPref("dom.experimental_forms", state === 'true');
|
||||
iframe.src = 'data:text/html,<script>' +
|
||||
'parent.is("valueAsDate" in document.createElement("input"), ' +
|
||||
state + ', "valueAsDate presence state should be ' + state + '");' +
|
||||
'<\/script>'
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=874640">Mozilla Bug 874640</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe onload='runTest(this);'></iframe>
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -44,8 +44,6 @@ var validTypes =
|
||||
["range", false],
|
||||
["date", true],
|
||||
["time", true],
|
||||
// The next types have not been implemented but will fallback to "text"
|
||||
// which has the same value.
|
||||
["color", false],
|
||||
];
|
||||
|
||||
|
@ -43,8 +43,6 @@ function checkAvailability()
|
||||
["range", true],
|
||||
["date", true],
|
||||
["time", true],
|
||||
// The next types have not been implemented but will fallback to "text"
|
||||
// which has the same value.
|
||||
["color", false],
|
||||
];
|
||||
|
||||
|
@ -38,14 +38,15 @@ var testData = [
|
||||
[ "date", true ],
|
||||
[ "time", true ],
|
||||
[ "range", true ],
|
||||
[ "color", true ],
|
||||
// 'file' is treated separatly.
|
||||
];
|
||||
|
||||
var todoTypes = [
|
||||
"datetime", "month", "week", "datetime-local", "color"
|
||||
"datetime", "month", "week", "datetime-local"
|
||||
];
|
||||
|
||||
var nonTrivialSanitizing = [ 'number', 'date', 'time' ];
|
||||
var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color' ];
|
||||
|
||||
var length = testData.length;
|
||||
for (var i=0; i<length; ++i) {
|
||||
@ -60,9 +61,18 @@ for (var i=0; i<length; ++i) {
|
||||
if (testData[j][0] == 'range' || testData[i][0] == 'range') {
|
||||
if (testData[j][0] == 'date' || testData[j][0] == 'time') {
|
||||
expectedValue = '';
|
||||
} else if (testData[j][0] == 'color') {
|
||||
expectedValue = '#000000';
|
||||
} else {
|
||||
expectedValue = '50';
|
||||
}
|
||||
} else if (testData[i][0] == 'color' || testData[j][0] == 'color') {
|
||||
if (testData[j][0] == 'number' || testData[j][0] == 'date' ||
|
||||
testData[j][0] == 'time') {
|
||||
expectedValue = ''
|
||||
} else {
|
||||
expectedValue = '#000000';
|
||||
}
|
||||
} else if (nonTrivialSanitizing.indexOf(testData[i][0]) != -1 &&
|
||||
nonTrivialSanitizing.indexOf(testData[j][0]) != -1) {
|
||||
expectedValue = '';
|
||||
@ -95,6 +105,9 @@ for (var data of testData) {
|
||||
if (data[0] == 'range') {
|
||||
is(e.value, '50', ".value should still return the same value after " +
|
||||
"changing type from " + data[0] + " to 'file' then reverting to " + data[0]);
|
||||
} else if (data[0] == 'color') {
|
||||
is(e.value, '#000000', ".value should have been reset to the default color after " +
|
||||
"changing type from " + data[0] + " to 'file' then reverting to " + data[0]);
|
||||
} else if (data[1]) {
|
||||
is(e.value, '', ".value should have been reset to the empty string after " +
|
||||
"changing type from " + data[0] + " to 'file' then reverting to " + data[0]);
|
||||
|
@ -50,9 +50,9 @@ var types = [
|
||||
[ "text", "email", "password", "url", "search", "tel" ],
|
||||
// These types can't be too long.
|
||||
[ "radio", "checkbox", "submit", "button", "reset", "image", "hidden",
|
||||
'number', 'range', 'date', 'time' ],
|
||||
'number', 'range', 'date', 'time', 'color' ],
|
||||
// These types can't be too long but are not implemented yet.
|
||||
[ "color", "datetime", "month", "week", 'datetime-local' ]
|
||||
[ "datetime", "month", "week", 'datetime-local' ]
|
||||
];
|
||||
|
||||
var input = document.createElement("input");
|
||||
|
@ -315,6 +315,8 @@ AudioNodeStream::ObtainInputBlock(AudioChunk& aTmpChunk, uint32_t aPortIndex)
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(outputChannelCount > 0, "How did this happen?");
|
||||
|
||||
AllocateAudioBlock(outputChannelCount, &aTmpChunk);
|
||||
float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {0.f};
|
||||
// The static storage here should be 1KB, so it's fine
|
||||
|
15
content/media/test/crashtests/874869.html
Normal file
15
content/media/test/crashtests/874869.html
Normal file
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
var Context0= new AudioContext()
|
||||
var Panner0=Context0.createPanner();
|
||||
var BufferSource3=Context0.createBufferSource();
|
||||
Panner0.channelCount=0;
|
||||
BufferSource3.connect(Panner0);
|
||||
BufferSource3.buffer=function(){
|
||||
var length=1;
|
||||
var Buffer=Context0.createBuffer(1,length,'44200');
|
||||
var bufferData= Buffer.getChannelData(0);
|
||||
for (var i = 0; i < length; ++i) { bufferData[i] = 255;};
|
||||
return Buffer;
|
||||
}();
|
||||
|
||||
</script>
|
24
content/media/test/crashtests/874915.html
Normal file
24
content/media/test/crashtests/874915.html
Normal file
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
var Context0= new AudioContext()
|
||||
var BufferSource6=Context0.createBufferSource();
|
||||
|
||||
setInterval(function(){
|
||||
BufferSource6.buffer=function(){
|
||||
var length=11283;
|
||||
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
|
||||
var bufferData= Buffer.getChannelData(0);
|
||||
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(624))};
|
||||
return Buffer;
|
||||
}();
|
||||
},0)
|
||||
|
||||
BufferSource6.start(0.15831333969254047,0.23571860056836158,0.529235512483865);
|
||||
|
||||
BufferSource6.buffer=function(){
|
||||
var length=48517;
|
||||
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
|
||||
var bufferData= Buffer.getChannelData(0);
|
||||
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(365))};
|
||||
return Buffer;
|
||||
}();
|
||||
</script>
|
23
content/media/test/crashtests/874934.html
Normal file
23
content/media/test/crashtests/874934.html
Normal file
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
var Context0= new AudioContext()
|
||||
var BufferSource0=Context0.createBufferSource();
|
||||
BufferSource0.start(0.01932738965842873,0.33345631847623736,0.3893404237460345);
|
||||
BufferSource0.buffer=function(){
|
||||
var length=35887;
|
||||
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
|
||||
var bufferData= Buffer.getChannelData(0);
|
||||
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(0.39765272522345185))};
|
||||
return Buffer;
|
||||
}();
|
||||
|
||||
BufferSource0.buffer=function(){
|
||||
var length=15952;
|
||||
var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
|
||||
var bufferData= Buffer.getChannelData(0);
|
||||
for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(85))};
|
||||
return Buffer;
|
||||
}();
|
||||
|
||||
BufferSource0.playbackRate.value=20.401213286832185;
|
||||
|
||||
</script>
|
@ -15,3 +15,6 @@ skip-if(Android||B2G) load 789075-1.html # load failed, bug 833371 for B2G
|
||||
load 844563.html
|
||||
load 846612.html
|
||||
load 852838.html
|
||||
load 874869.html
|
||||
load 874915.html
|
||||
load 874934.html
|
||||
|
@ -541,6 +541,11 @@ AudioBufferSourceNode::SendOffsetAndDurationParametersToStream(AudioNodeStream*
|
||||
length : std::min(aOffset + aDuration, length);
|
||||
|
||||
if (offset >= endOffset) {
|
||||
// The offset falls past the end of the buffer. In this case, we need to
|
||||
// stop the playback immediately if it's in progress. No need to check
|
||||
// mStartCalled here, since Stop() does that for us.
|
||||
ErrorResult rv;
|
||||
Stop(0.0, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize,
|
||||
uint32_t aNumberOfOutputChannels,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (aNumberOfInputChannels == 0 || aNumberOfOutputChannels == 0 ||
|
||||
if ((aNumberOfInputChannels == 0 && aNumberOfOutputChannels == 0) ||
|
||||
aNumberOfInputChannels > MAX_SCRIPT_PROCESSOR_CHANNELS ||
|
||||
aNumberOfOutputChannels > MAX_SCRIPT_PROCESSOR_CHANNELS ||
|
||||
!IsValidBufferSize(aBufferSize)) {
|
||||
|
@ -159,8 +159,12 @@ public:
|
||||
virtual uint16_t NumberOfOutputs() const { return 1; }
|
||||
|
||||
uint32_t ChannelCount() const { return mChannelCount; }
|
||||
void SetChannelCount(uint32_t aChannelCount)
|
||||
void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
|
||||
{
|
||||
if (aChannelCount == 0) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
mChannelCount = aChannelCount;
|
||||
SendChannelMixingParametersToStream();
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ MOCHITEST_FILES := \
|
||||
test_pannerNode.html \
|
||||
test_scriptProcessorNode.html \
|
||||
test_scriptProcessorNodeChannelCount.html \
|
||||
test_scriptProcessorNodeZeroInputOutput.html \
|
||||
test_singleSourceDest.html \
|
||||
test_waveShaper.html \
|
||||
test_waveShaperNoCurve.html \
|
||||
|
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test AudioBufferSourceNode</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="webaudio.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
|
||||
|
||||
var context = new AudioContext();
|
||||
|
||||
var sp = context.createScriptProcessor(2048, 0, 2);
|
||||
sp.onaudioprocess = function(e) {
|
||||
is(e.inputBuffer.numberOfChannels, 0, "Should have 0 input channels");
|
||||
is(e.outputBuffer.numberOfChannels, 2, "Should have 2 output channels");
|
||||
sp.onaudioprocess = null;
|
||||
|
||||
sp = context.createScriptProcessor(2048, 2, 0);
|
||||
sp.onaudioprocess = function(e) {
|
||||
is(e.inputBuffer.numberOfChannels, 2, "Should have 2 input channels");
|
||||
is(e.outputBuffer.numberOfChannels, 0, "Should have 0 output channels");
|
||||
sp.onaudioprocess = null;
|
||||
|
||||
SpecialPowers.clearUserPref("media.webaudio.enabled");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -91,6 +91,10 @@ function createNode(context, buffer, destination) {
|
||||
is(source.channelCountMode, "max", "Correct channelCountMode for the source node");
|
||||
is(source.channelInterpretation, "speakers", "Correct channelCountInterpretation for the source node");
|
||||
|
||||
expectException(function() {
|
||||
source.channelCount = 0;
|
||||
}, DOMException.NOT_SUPPORTED_ERR);
|
||||
|
||||
source.buffer = buffer;
|
||||
ok(source.buffer, "Source node should have a buffer now");
|
||||
|
||||
|
@ -134,6 +134,16 @@ SVGTransformableElement::SetAnimateMotionTransform(const gfxMatrix* aMatrix)
|
||||
}
|
||||
mAnimateMotionTransform = aMatrix ? new gfxMatrix(*aMatrix) : nullptr;
|
||||
DidAnimateTransformList();
|
||||
nsIFrame* frame = GetPrimaryFrame();
|
||||
if (frame) {
|
||||
// If the result of this transform and any other transforms on this frame
|
||||
// is the identity matrix, then DoApplyRenderingChangeToTree won't handle
|
||||
// our nsChangeHint_UpdateTransformLayer hint since aFrame->IsTransformed()
|
||||
// will return false. That's fine, but we still need to schedule a repaint,
|
||||
// and that won't otherwise happen. Since it's cheap to call SchedulePaint,
|
||||
// we don't bother to check IsTransformed().
|
||||
frame->SchedulePaint();
|
||||
}
|
||||
}
|
||||
|
||||
nsSVGAnimatedTransformList*
|
||||
|
@ -36,6 +36,7 @@ interface AudioNode : EventTarget {
|
||||
readonly attribute unsigned long numberOfOutputs;
|
||||
|
||||
// Channel up-mixing and down-mixing rules for all inputs.
|
||||
[SetterThrows]
|
||||
attribute unsigned long channelCount;
|
||||
attribute ChannelCountMode channelCountMode;
|
||||
attribute ChannelInterpretation channelInterpretation;
|
||||
|
@ -81,7 +81,7 @@ interface HTMLInputElement : HTMLElement {
|
||||
attribute DOMString defaultValue;
|
||||
[Pure, TreatNullAs=EmptyString, SetterThrows]
|
||||
attribute DOMString value;
|
||||
[Throws]
|
||||
[Throws, Pref="dom.experimental_forms"]
|
||||
attribute Date? valueAsDate;
|
||||
[Pure, SetterThrows]
|
||||
attribute unrestricted double valueAsNumber;
|
||||
|
@ -1687,7 +1687,7 @@ void nsWebBrowser::WindowLowered(nsIWidget* aWidget)
|
||||
Deactivate();
|
||||
}
|
||||
|
||||
bool nsWebBrowser::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion, uint32_t aFlags)
|
||||
bool nsWebBrowser::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion)
|
||||
{
|
||||
LayerManager* layerManager = aWidget->GetLayerManager();
|
||||
NS_ASSERTION(layerManager, "Must be in paint event");
|
||||
|
@ -124,7 +124,7 @@ protected:
|
||||
// nsIWidgetListener
|
||||
virtual void WindowRaised(nsIWidget* aWidget);
|
||||
virtual void WindowLowered(nsIWidget* aWidget);
|
||||
virtual bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion, uint32_t aFlags) MOZ_OVERRIDE;
|
||||
virtual bool PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
nsDocShellTreeOwner* mDocShellTreeOwner;
|
||||
|
@ -3252,6 +3252,7 @@ nsWebBrowserPersist::CloneNodeWithFixedUpAttributes(
|
||||
case NS_FORM_INPUT_RANGE:
|
||||
case NS_FORM_INPUT_DATE:
|
||||
case NS_FORM_INPUT_TIME:
|
||||
case NS_FORM_INPUT_COLOR:
|
||||
nodeAsInput->GetValue(valueStr);
|
||||
// Avoid superfluous value="" serialization
|
||||
if (valueStr.IsEmpty())
|
||||
|
@ -46,7 +46,7 @@ enum TextureClientType
|
||||
{
|
||||
TEXTURE_CONTENT, // dynamically drawn content
|
||||
TEXTURE_SHMEM, // shared memory
|
||||
TEXTURE_YCBCR, // ShmemYCbCrImage
|
||||
TEXTURE_YCBCR, // YCbCr in a shmem
|
||||
TEXTURE_SHARED_GL, // GLContext::SharedTextureHandle
|
||||
TEXTURE_SHARED_GL_EXTERNAL, // GLContext::SharedTextureHandle, the ownership of
|
||||
// the SurfaceDescriptor passed to the texture
|
||||
|
@ -134,7 +134,6 @@ CPPSRCS += \
|
||||
LayerTransactionChild.cpp \
|
||||
LayerTransactionParent.cpp \
|
||||
SharedPlanarYCbCrImage.cpp \
|
||||
ShmemYCbCrImage.cpp \
|
||||
SharedRGBImage.cpp \
|
||||
TaskThrottler.cpp \
|
||||
ImageClient.cpp \
|
||||
@ -146,6 +145,7 @@ CPPSRCS += \
|
||||
TextureHostOGL.cpp \
|
||||
TiledContentClient.cpp \
|
||||
TiledContentHost.cpp \
|
||||
YCbCrImageDataSerializer.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_X11 #{
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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 "ShmemYCbCrImage.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
|
||||
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
|
||||
|
||||
@ -14,11 +14,7 @@ namespace layers {
|
||||
|
||||
// The Data is layed out as follows:
|
||||
//
|
||||
// +-----------------+ -+ <-- Beginning of the Shmem
|
||||
// | | |
|
||||
// | ... | | offset
|
||||
// | | |
|
||||
// +-----------------+ -++ --+ --+
|
||||
// +-----------------+ -++ --+ --+ <-- Beginning of the buffer
|
||||
// | YCbCrBufferInfo | | | |
|
||||
// +-----------------+ --+ | |
|
||||
// | data | | | YCbCrBufferInfo->[mY/mCb/mCr]Offset
|
||||
@ -44,69 +40,68 @@ struct YCbCrBufferInfo
|
||||
uint32_t mCbCrHeight;
|
||||
};
|
||||
|
||||
static YCbCrBufferInfo* GetYCbCrBufferInfo(Shmem& aShmem, size_t aOffset)
|
||||
static YCbCrBufferInfo* GetYCbCrBufferInfo(uint8_t* aData)
|
||||
{
|
||||
return reinterpret_cast<YCbCrBufferInfo*>(aShmem.get<uint8_t>() + aOffset);
|
||||
return reinterpret_cast<YCbCrBufferInfo*>(aData);
|
||||
}
|
||||
|
||||
|
||||
uint8_t* ShmemYCbCrImage::GetYData()
|
||||
bool YCbCrImageDataDeserializerBase::IsValid()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
if (mData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
size_t bufferInfoSize = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetYData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return reinterpret_cast<uint8_t*>(info) + info->mYOffset;
|
||||
}
|
||||
|
||||
uint8_t* ShmemYCbCrImage::GetCbData()
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetCbData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return reinterpret_cast<uint8_t*>(info) + info->mCbOffset;
|
||||
}
|
||||
|
||||
uint8_t* ShmemYCbCrImage::GetCrData()
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetCrData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return reinterpret_cast<uint8_t*>(info) + info->mCrOffset;
|
||||
}
|
||||
|
||||
uint8_t* ShmemYCbCrImage::GetData()
|
||||
uint8_t* YCbCrImageDataDeserializerBase::GetData()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return (reinterpret_cast<uint8_t*>(info)) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
}
|
||||
|
||||
uint32_t ShmemYCbCrImage::GetYStride()
|
||||
uint32_t YCbCrImageDataDeserializerBase::GetYStride()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return info->mYWidth;
|
||||
}
|
||||
|
||||
uint32_t ShmemYCbCrImage::GetCbCrStride()
|
||||
uint32_t YCbCrImageDataDeserializerBase::GetCbCrStride()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return info->mCbCrWidth;
|
||||
}
|
||||
|
||||
gfxIntSize ShmemYCbCrImage::GetYSize()
|
||||
gfxIntSize YCbCrImageDataDeserializerBase::GetYSize()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return gfxIntSize(info->mYWidth, info->mYHeight);
|
||||
}
|
||||
|
||||
gfxIntSize ShmemYCbCrImage::GetCbCrSize()
|
||||
gfxIntSize YCbCrImageDataDeserializerBase::GetCbCrSize()
|
||||
{
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mShmem, mOffset);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
return gfxIntSize(info->mCbCrWidth, info->mCbCrHeight);
|
||||
}
|
||||
|
||||
|
||||
bool ShmemYCbCrImage::Open(Shmem& aShmem, size_t aOffset)
|
||||
{
|
||||
mShmem = aShmem;
|
||||
mOffset = aOffset;
|
||||
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
// Offset in bytes
|
||||
static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
|
||||
{
|
||||
@ -114,8 +109,9 @@ static size_t ComputeOffset(uint32_t aHeight, uint32_t aStride)
|
||||
}
|
||||
|
||||
// Minimum required shmem size in bytes
|
||||
size_t ShmemYCbCrImage::ComputeMinBufferSize(const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize)
|
||||
size_t
|
||||
YCbCrImageDataSerializer::ComputeMinBufferSize(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize)
|
||||
{
|
||||
uint32_t yStride = aYSize.width;
|
||||
uint32_t CbCrStride = aCbCrSize.width;
|
||||
@ -125,6 +121,13 @@ size_t ShmemYCbCrImage::ComputeMinBufferSize(const gfxIntSize& aYSize,
|
||||
+ MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
}
|
||||
|
||||
size_t
|
||||
YCbCrImageDataSerializer::ComputeMinBufferSize(const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize)
|
||||
{
|
||||
return ComputeMinBufferSize(gfx::IntSize(aYSize.width, aYSize.height),
|
||||
gfx::IntSize(aCbCrSize.width, aCbCrSize.height));
|
||||
}
|
||||
// Offset in bytes
|
||||
static size_t ComputeOffset(uint32_t aSize)
|
||||
{
|
||||
@ -132,17 +135,17 @@ static size_t ComputeOffset(uint32_t aSize)
|
||||
}
|
||||
|
||||
// Minimum required shmem size in bytes
|
||||
size_t ShmemYCbCrImage::ComputeMinBufferSize(uint32_t aSize)
|
||||
size_t
|
||||
YCbCrImageDataSerializer::ComputeMinBufferSize(uint32_t aSize)
|
||||
{
|
||||
|
||||
return ComputeOffset(aSize) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
}
|
||||
|
||||
void ShmemYCbCrImage::InitializeBufferInfo(uint8_t* aBuffer,
|
||||
const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize)
|
||||
void
|
||||
YCbCrImageDataSerializer::InitializeBufferInfo(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize)
|
||||
{
|
||||
YCbCrBufferInfo* info = reinterpret_cast<YCbCrBufferInfo*>(aBuffer);
|
||||
YCbCrBufferInfo* info = GetYCbCrBufferInfo(mData);
|
||||
info->mYOffset = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
info->mCbOffset = info->mYOffset
|
||||
+ MOZ_ALIGN_WORD(aYSize.width * aYSize.height);
|
||||
@ -155,18 +158,12 @@ void ShmemYCbCrImage::InitializeBufferInfo(uint8_t* aBuffer,
|
||||
info->mCbCrHeight = aCbCrSize.height;
|
||||
}
|
||||
|
||||
bool ShmemYCbCrImage::IsValid()
|
||||
void
|
||||
YCbCrImageDataSerializer::InitializeBufferInfo(const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize)
|
||||
{
|
||||
if (mShmem == Shmem()) {
|
||||
return false;
|
||||
}
|
||||
size_t bufferInfoSize = MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo));
|
||||
if (mShmem.Size<uint8_t>() < bufferInfoSize ||
|
||||
GetYCbCrBufferInfo(mShmem, mOffset)->mYOffset != bufferInfoSize ||
|
||||
mShmem.Size<uint8_t>() < mOffset + ComputeMinBufferSize(GetYSize(),GetCbCrSize())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
InitializeBufferInfo(gfx::IntSize(aYSize.width, aYSize.height),
|
||||
gfx::IntSize(aCbCrSize.width, aCbCrSize.height));
|
||||
}
|
||||
|
||||
static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) {
|
||||
@ -177,11 +174,12 @@ static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uin
|
||||
}
|
||||
}
|
||||
|
||||
bool ShmemYCbCrImage::CopyData(const uint8_t* aYData,
|
||||
const uint8_t* aCbData, const uint8_t* aCrData,
|
||||
gfxIntSize aYSize, uint32_t aYStride,
|
||||
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
|
||||
uint32_t aYSkip, uint32_t aCbCrSkip)
|
||||
bool
|
||||
YCbCrImageDataSerializer::CopyData(const uint8_t* aYData,
|
||||
const uint8_t* aCbData, const uint8_t* aCrData,
|
||||
gfxIntSize aYSize, uint32_t aYStride,
|
||||
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
|
||||
uint32_t aYSkip, uint32_t aCbCrSkip)
|
||||
{
|
||||
if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) {
|
||||
return false;
|
@ -3,8 +3,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_LAYERS_SHMEMYCBCRIMAGE_H
|
||||
#define MOZILLA_LAYERS_SHMEMYCBCRIMAGE_H
|
||||
#ifndef MOZILLA_LAYERS_BLOBYCBCRSURFACE_H
|
||||
#define MOZILLA_LAYERS_BLOBYCBCRSURFACE_H
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
@ -21,49 +21,13 @@ namespace layers {
|
||||
class Image;
|
||||
|
||||
/**
|
||||
* This class is a view on a YCbCrImage stored in a Shmem at a certain offset.
|
||||
* It is only meant as a convenience to access the image data, and does not own
|
||||
* the data. The instance can live on the stack and used as follows:
|
||||
*
|
||||
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
|
||||
* ShmemYCbCrImage shmImg(yuv.data(), yuv.offset());
|
||||
* if (!shmImg.IsValid()) {
|
||||
* // handle error
|
||||
* }
|
||||
* mYSize = shmImg.GetYSize(); // work with the data, etc...
|
||||
* Convenience class to share code between YCbCrImageDataSerializer
|
||||
* and YCbCrImageDataDeserializer.
|
||||
* Do not use it.
|
||||
*/
|
||||
class ShmemYCbCrImage
|
||||
class YCbCrImageDataDeserializerBase
|
||||
{
|
||||
public:
|
||||
typedef mozilla::ipc::Shmem Shmem;
|
||||
|
||||
ShmemYCbCrImage() : mOffset(0) {}
|
||||
|
||||
ShmemYCbCrImage(Shmem& shm, size_t offset = 0) {
|
||||
DebugOnly<bool> status = Open(shm,offset);
|
||||
NS_ASSERTION(status, "Invalid data in the shmem");
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is meant as a helper to know how much shared memory we need
|
||||
* to allocate in a shmem in order to place a shared YCbCr image blob of
|
||||
* given dimensions.
|
||||
*/
|
||||
static size_t ComputeMinBufferSize(const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize);
|
||||
static size_t ComputeMinBufferSize(uint32_t aSize);
|
||||
/**
|
||||
* Write the image informations in a buffer for given dimensions.
|
||||
* The provided pointer should point to the beginning of the (chunk of)
|
||||
* buffer on which we want to store th image.
|
||||
*/
|
||||
static void InitializeBufferInfo(uint8_t* aBuffer,
|
||||
const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize);
|
||||
|
||||
/**
|
||||
* Returns true if the shmem's data blob contains a valid YCbCr image.
|
||||
*/
|
||||
bool IsValid();
|
||||
|
||||
/**
|
||||
@ -102,21 +66,74 @@ public:
|
||||
* Return a pointer to the begining of the data buffer.
|
||||
*/
|
||||
uint8_t* GetData();
|
||||
protected:
|
||||
YCbCrImageDataDeserializerBase(uint8_t* aData)
|
||||
: mData (aData) {}
|
||||
|
||||
uint8_t* mData;
|
||||
};
|
||||
|
||||
/**
|
||||
* A view on a YCbCr image stored with its metadata in a blob of memory.
|
||||
* It is only meant as a convenience to access the image data, and does not own
|
||||
* the data. The instance can live on the stack and used as follows:
|
||||
*
|
||||
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
|
||||
* YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
|
||||
* if (!deserializer.IsValid()) {
|
||||
* // handle error
|
||||
* }
|
||||
* size = deserializer.GetYSize(); // work with the data, etc...
|
||||
*/
|
||||
class MOZ_STACK_CLASS YCbCrImageDataSerializer : public YCbCrImageDataDeserializerBase
|
||||
{
|
||||
public:
|
||||
YCbCrImageDataSerializer(uint8_t* aData) : YCbCrImageDataDeserializerBase(aData) {}
|
||||
|
||||
/**
|
||||
* Copies the data passed in parameter into the shmem.
|
||||
* This function is meant as a helper to know how much shared memory we need
|
||||
* to allocate in a shmem in order to place a shared YCbCr image blob of
|
||||
* given dimensions.
|
||||
*/
|
||||
static size_t ComputeMinBufferSize(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize);
|
||||
static size_t ComputeMinBufferSize(const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize);
|
||||
static size_t ComputeMinBufferSize(uint32_t aSize);
|
||||
|
||||
/**
|
||||
* Write the image informations in the buffer for given dimensions.
|
||||
* The provided pointer should point to the beginning of the (chunk of)
|
||||
* buffer on which we want to store the image.
|
||||
*/
|
||||
void InitializeBufferInfo(const gfx::IntSize& aYSize,
|
||||
const gfx::IntSize& aCbCrSize);
|
||||
void InitializeBufferInfo(const gfxIntSize& aYSize,
|
||||
const gfxIntSize& aCbCrSize);
|
||||
|
||||
bool CopyData(const uint8_t* aYData,
|
||||
const uint8_t* aCbData, const uint8_t* aCrData,
|
||||
gfxIntSize aYSize, uint32_t aYStride,
|
||||
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
|
||||
uint32_t aYSkip, uint32_t aCbCrSkip);
|
||||
};
|
||||
|
||||
private:
|
||||
bool Open(Shmem& aShmem, size_t aOffset = 0);
|
||||
|
||||
ipc::Shmem mShmem;
|
||||
size_t mOffset;
|
||||
/**
|
||||
* A view on a YCbCr image stored with its metadata in a blob of memory.
|
||||
* It is only meant as a convenience to access the image data, and does not own
|
||||
* the data. The instance can live on the stack and used as follows:
|
||||
*
|
||||
* const YCbCrImage& yuv = sharedImage.get_YCbCrImage();
|
||||
* YCbCrImageDataDeserializer deserializer(yuv.data().get<uint8_t>());
|
||||
* if (!deserializer.IsValid()) {
|
||||
* // handle error
|
||||
* }
|
||||
* size = deserializer.GetYSize(); // work with the data, etc...
|
||||
*/
|
||||
class MOZ_STACK_CLASS YCbCrImageDataDeserializer : public YCbCrImageDataDeserializerBase
|
||||
{
|
||||
public:
|
||||
YCbCrImageDataDeserializer(uint8_t* aData) : YCbCrImageDataDeserializerBase(aData) {}
|
||||
};
|
||||
|
||||
} // namespace
|
@ -13,9 +13,10 @@
|
||||
#include "mozilla/layers/SharedPlanarYCbCrImage.h"
|
||||
#include "GLContext.h"
|
||||
#include "BasicLayers.h" // for PaintContext
|
||||
#include "ShmemYCbCrImage.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "gfxReusableSurfaceWrapper.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "mozilla/StandardInteger.h"
|
||||
|
||||
using namespace mozilla::gl;
|
||||
|
||||
@ -277,8 +278,8 @@ AutoLockYCbCrClient::Update(PlanarYCbCrImage* aImage)
|
||||
|
||||
ipc::Shmem& shmem = mDescriptor->get_YCbCrImage().data();
|
||||
|
||||
ShmemYCbCrImage shmemImage(shmem);
|
||||
if (!shmemImage.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel,
|
||||
YCbCrImageDataSerializer serializer(shmem.get<uint8_t>());
|
||||
if (!serializer.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel,
|
||||
data->mYSize, data->mYStride,
|
||||
data->mCbCrSize, data->mCbCrStride,
|
||||
data->mYSkip, data->mCbSkip)) {
|
||||
@ -306,9 +307,9 @@ bool AutoLockYCbCrClient::EnsureTextureClient(PlanarYCbCrImage* aImage)
|
||||
needsAllocation = true;
|
||||
} else {
|
||||
ipc::Shmem& shmem = mDescriptor->get_YCbCrImage().data();
|
||||
ShmemYCbCrImage shmemImage(shmem);
|
||||
if (shmemImage.GetYSize() != data->mYSize ||
|
||||
shmemImage.GetCbCrSize() != data->mCbCrSize) {
|
||||
YCbCrImageDataSerializer serializer(shmem.get<uint8_t>());
|
||||
if (serializer.GetYSize() != data->mYSize ||
|
||||
serializer.GetCbCrSize() != data->mCbCrSize) {
|
||||
needsAllocation = true;
|
||||
}
|
||||
}
|
||||
@ -320,19 +321,18 @@ bool AutoLockYCbCrClient::EnsureTextureClient(PlanarYCbCrImage* aImage)
|
||||
mTextureClient->ReleaseResources();
|
||||
|
||||
ipc::SharedMemory::SharedMemoryType shmType = OptimalShmemType();
|
||||
size_t size = ShmemYCbCrImage::ComputeMinBufferSize(data->mYSize,
|
||||
data->mCbCrSize);
|
||||
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(data->mYSize,
|
||||
data->mCbCrSize);
|
||||
ipc::Shmem shmem;
|
||||
if (!mTextureClient->GetForwarder()->AllocUnsafeShmem(size, shmType, &shmem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShmemYCbCrImage::InitializeBufferInfo(shmem.get<uint8_t>(),
|
||||
data->mYSize,
|
||||
data->mCbCrSize);
|
||||
YCbCrImageDataSerializer serializer(shmem.get<uint8_t>());
|
||||
serializer.InitializeBufferInfo(data->mYSize,
|
||||
data->mCbCrSize);
|
||||
|
||||
|
||||
*mDescriptor = YCbCrImage(shmem, 0, 0);
|
||||
*mDescriptor = YCbCrImage(shmem, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "gfxImageSurface.h"
|
||||
#include "Effects.h"
|
||||
#include "ipc/AutoOpenSurface.h"
|
||||
#include "ShmemYCbCrImage.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "gfxD2DSurface.h"
|
||||
|
||||
@ -460,30 +460,29 @@ TextureHostYCbCrD3D11::UpdateImpl(const SurfaceDescriptor& aImage,
|
||||
{
|
||||
MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TYCbCrImage);
|
||||
|
||||
ShmemYCbCrImage shmemImage(aImage.get_YCbCrImage().data(),
|
||||
aImage.get_YCbCrImage().offset());
|
||||
YCbCrImageDataDeserializer yuvDeserializer(aImage.get_YCbCrImage().data().get<uint8_t>());
|
||||
|
||||
gfxIntSize gfxCbCrSize = shmemImage.GetCbCrSize();
|
||||
gfxIntSize gfxCbCrSize = yuvDeserializer.GetCbCrSize();
|
||||
|
||||
gfxIntSize size = shmemImage.GetYSize();
|
||||
gfxIntSize size = yuvDeserializer.GetYSize();
|
||||
|
||||
D3D11_SUBRESOURCE_DATA initData;
|
||||
initData.pSysMem = shmemImage.GetYData();
|
||||
initData.SysMemPitch = shmemImage.GetYStride();
|
||||
initData.pSysMem = yuvDeserializer.GetYData();
|
||||
initData.SysMemPitch = yuvDeserializer.GetYStride();
|
||||
|
||||
CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8_UNORM, size.width, size.height,
|
||||
1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_IMMUTABLE);
|
||||
|
||||
mDevice->CreateTexture2D(&desc, &initData, byRef(mTextures[0]));
|
||||
|
||||
initData.pSysMem = shmemImage.GetCbData();
|
||||
initData.SysMemPitch = shmemImage.GetCbCrStride();
|
||||
desc.Width = shmemImage.GetCbCrSize().width;
|
||||
desc.Height = shmemImage.GetCbCrSize().height;
|
||||
initData.pSysMem = yuvDeserializer.GetCbData();
|
||||
initData.SysMemPitch = yuvDeserializer.GetCbCrStride();
|
||||
desc.Width = yuvDeserializer.GetCbCrSize().width;
|
||||
desc.Height = yuvDeserializer.GetCbCrSize().height;
|
||||
|
||||
mDevice->CreateTexture2D(&desc, &initData, byRef(mTextures[1]));
|
||||
|
||||
initData.pSysMem = shmemImage.GetCrData();
|
||||
initData.pSysMem = yuvDeserializer.GetCrData();
|
||||
mDevice->CreateTexture2D(&desc, &initData, byRef(mTextures[2]));
|
||||
|
||||
mSize = IntSize(size.width, size.height);
|
||||
|
@ -71,7 +71,6 @@ struct SurfaceStreamDescriptor {
|
||||
|
||||
struct YCbCrImage {
|
||||
Shmem data;
|
||||
size_t offset;
|
||||
uint64_t owner;
|
||||
};
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SharedPlanarYCbCrImage.h"
|
||||
#include "ShmemYCbCrImage.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
|
||||
@ -40,21 +40,21 @@ SharedPlanarYCbCrImage::SetData(const PlanarYCbCrImage::Data& aData)
|
||||
// do not set mBuffer like in PlanarYCbCrImage because the later
|
||||
// will try to manage this memory without knowing it belongs to a
|
||||
// shmem.
|
||||
mBufferSize = ShmemYCbCrImage::ComputeMinBufferSize(mData.mYSize,
|
||||
mData.mCbCrSize);
|
||||
mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
|
||||
mData.mCbCrSize);
|
||||
mSize = mData.mPicSize;
|
||||
|
||||
ShmemYCbCrImage shmImg(mShmem);
|
||||
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
|
||||
MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
|
||||
if (!shmImg.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
|
||||
aData.mYSize, aData.mYStride,
|
||||
aData.mCbCrSize, aData.mCbCrStride,
|
||||
aData.mYSkip, aData.mCbSkip)) {
|
||||
if (!serializer.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
|
||||
aData.mYSize, aData.mYStride,
|
||||
aData.mCbCrSize, aData.mCbCrStride,
|
||||
aData.mYSkip, aData.mCbSkip)) {
|
||||
NS_WARNING("Failed to copy image data!");
|
||||
}
|
||||
mData.mYChannel = shmImg.GetYData();
|
||||
mData.mCbChannel = shmImg.GetCbData();
|
||||
mData.mCrChannel = shmImg.GetCrData();
|
||||
mData.mYChannel = serializer.GetYData();
|
||||
mData.mCbChannel = serializer.GetCbData();
|
||||
mData.mCrChannel = serializer.GetCrData();
|
||||
}
|
||||
|
||||
// needs to be overriden because the parent class sets mBuffer which we
|
||||
@ -63,15 +63,15 @@ uint8_t*
|
||||
SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mAllocated, "This image already has allocated data");
|
||||
size_t size = ShmemYCbCrImage::ComputeMinBufferSize(aSize);
|
||||
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aSize);
|
||||
// update buffer size
|
||||
mBufferSize = size;
|
||||
|
||||
// get new buffer _without_ setting mBuffer.
|
||||
AllocateBuffer(mBufferSize);
|
||||
ShmemYCbCrImage shmImg(mShmem);
|
||||
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
|
||||
|
||||
return shmImg.GetData();
|
||||
return serializer.GetData();
|
||||
}
|
||||
|
||||
|
||||
@ -80,9 +80,9 @@ SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
|
||||
{
|
||||
mData = aData;
|
||||
mSize = aData.mPicSize;
|
||||
ShmemYCbCrImage::InitializeBufferInfo(mShmem.get<uint8_t>(),
|
||||
aData.mYSize,
|
||||
aData.mCbCrSize);
|
||||
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
|
||||
serializer.InitializeBufferInfo(aData.mYSize,
|
||||
aData.mCbCrSize);
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
@ -103,25 +103,24 @@ SharedPlanarYCbCrImage::Allocate(PlanarYCbCrImage::Data& aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mAllocated, "This image already has allocated data");
|
||||
|
||||
size_t size = ShmemYCbCrImage::ComputeMinBufferSize(aData.mYSize,
|
||||
aData.mCbCrSize);
|
||||
size_t size = YCbCrImageDataSerializer::ComputeMinBufferSize(aData.mYSize,
|
||||
aData.mCbCrSize);
|
||||
|
||||
if (AllocateBuffer(static_cast<uint32_t>(size)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShmemYCbCrImage::InitializeBufferInfo(mShmem.get<uint8_t>(),
|
||||
aData.mYSize,
|
||||
aData.mCbCrSize);
|
||||
ShmemYCbCrImage shmImg(mShmem);
|
||||
if (!shmImg.IsValid() || mShmem.Size<uint8_t>() < size) {
|
||||
YCbCrImageDataSerializer serializer(mShmem.get<uint8_t>());
|
||||
serializer.InitializeBufferInfo(aData.mYSize,
|
||||
aData.mCbCrSize);
|
||||
if (!serializer.IsValid() || mShmem.Size<uint8_t>() < size) {
|
||||
mSurfaceAllocator->DeallocShmem(mShmem);
|
||||
return false;
|
||||
}
|
||||
|
||||
aData.mYChannel = shmImg.GetYData();
|
||||
aData.mCbChannel = shmImg.GetCbData();
|
||||
aData.mCrChannel = shmImg.GetCrData();
|
||||
aData.mYChannel = serializer.GetYData();
|
||||
aData.mCbChannel = serializer.GetCbData();
|
||||
aData.mCrChannel = serializer.GetCrData();
|
||||
|
||||
// copy some of aData's values in mData (most of them)
|
||||
mData.mYChannel = aData.mYChannel;
|
||||
@ -150,7 +149,7 @@ SharedPlanarYCbCrImage::ToSurfaceDescriptor(SurfaceDescriptor& aDesc) {
|
||||
if (!mAllocated) {
|
||||
return false;
|
||||
}
|
||||
aDesc = YCbCrImage(mShmem, 0, reinterpret_cast<uint64_t>(this));
|
||||
aDesc = YCbCrImage(mShmem, reinterpret_cast<uint64_t>(this));
|
||||
this->AddRef();
|
||||
return true;
|
||||
}
|
||||
@ -160,7 +159,7 @@ SharedPlanarYCbCrImage::DropToSurfaceDescriptor(SurfaceDescriptor& aDesc) {
|
||||
if (!mAllocated) {
|
||||
return false;
|
||||
}
|
||||
aDesc = YCbCrImage(mShmem, 0, 0);
|
||||
aDesc = YCbCrImage(mShmem, 0);
|
||||
mShmem = Shmem();
|
||||
mAllocated = false;
|
||||
return true;
|
||||
|
@ -40,7 +40,6 @@ EXPORTS += [
|
||||
'ReadbackLayer.h',
|
||||
'ShadowLayersManager.h',
|
||||
'SharedTextureImage.h',
|
||||
'ShmemYCbCrImage.h',
|
||||
'TexturePoolOGL.h',
|
||||
]
|
||||
|
||||
@ -105,7 +104,6 @@ EXPORTS.mozilla.layers += [
|
||||
'ShadowLayersManager.h',
|
||||
'SharedPlanarYCbCrImage.h',
|
||||
'SharedRGBImage.h',
|
||||
'ShmemYCbCrImage.h',
|
||||
'TaskThrottler.h',
|
||||
'TextureClient.h',
|
||||
'TextureClientOGL.h',
|
||||
@ -113,6 +111,7 @@ EXPORTS.mozilla.layers += [
|
||||
'TextureHostOGL.h',
|
||||
'ThebesLayerComposite.h',
|
||||
'TiledContentClient.h',
|
||||
'YCbCrImageDataSerializer.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_X11']:
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "gfxSharedImageSurface.h"
|
||||
|
||||
#include "ImageContainer.h" // for PlanarYCBCRImage
|
||||
#include "mozilla/layers/ShmemYCbCrImage.h"
|
||||
#include "ipc/AutoOpenSurface.h"
|
||||
#include "ImageLayerOGL.h"
|
||||
#include "gfxImageSurface.h"
|
||||
|
@ -19,7 +19,7 @@ namespace layers {
|
||||
|
||||
class CairoImage;
|
||||
class PlanarYCbCrImage;
|
||||
class ShmemYCbCrImage;
|
||||
class BlobYCbCrSurface;
|
||||
|
||||
/**
|
||||
* This class wraps a GL texture. It includes a GLContext reference
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "TextureHostOGL.h"
|
||||
#include "ipc/AutoOpenSurface.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "ShmemYCbCrImage.h"
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "GLContext.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "SurfaceStream.h"
|
||||
@ -491,11 +491,10 @@ YCbCrTextureHostOGL::UpdateImpl(const SurfaceDescriptor& aImage,
|
||||
}
|
||||
NS_ASSERTION(aImage.type() == SurfaceDescriptor::TYCbCrImage, "SurfaceDescriptor mismatch");
|
||||
|
||||
ShmemYCbCrImage shmemImage(aImage.get_YCbCrImage().data(),
|
||||
aImage.get_YCbCrImage().offset());
|
||||
YCbCrImageDataDeserializer deserializer(aImage.get_YCbCrImage().data().get<uint8_t>());
|
||||
|
||||
gfxIntSize gfxSize = shmemImage.GetYSize();
|
||||
gfxIntSize gfxCbCrSize = shmemImage.GetCbCrSize();
|
||||
gfxIntSize gfxSize = deserializer.GetYSize();
|
||||
gfxIntSize gfxCbCrSize = deserializer.GetCbCrSize();
|
||||
|
||||
if (!mYTexture->mTexImage || mYTexture->mTexImage->GetSize() != gfxSize) {
|
||||
mYTexture->mTexImage = CreateBasicTextureImage(mGL,
|
||||
@ -519,14 +518,14 @@ YCbCrTextureHostOGL::UpdateImpl(const SurfaceDescriptor& aImage,
|
||||
FlagsToGLFlags(mFlags));
|
||||
}
|
||||
|
||||
RefPtr<gfxImageSurface> tempY = new gfxImageSurface(shmemImage.GetYData(),
|
||||
gfxSize, shmemImage.GetYStride(),
|
||||
gfxASurface::ImageFormatA8);
|
||||
RefPtr<gfxImageSurface> tempCb = new gfxImageSurface(shmemImage.GetCbData(),
|
||||
gfxCbCrSize, shmemImage.GetCbCrStride(),
|
||||
RefPtr<gfxImageSurface> tempY = new gfxImageSurface(deserializer.GetYData(),
|
||||
gfxSize, deserializer.GetYStride(),
|
||||
gfxASurface::ImageFormatA8);
|
||||
RefPtr<gfxImageSurface> tempCr = new gfxImageSurface(shmemImage.GetCrData(),
|
||||
gfxCbCrSize, shmemImage.GetCbCrStride(),
|
||||
RefPtr<gfxImageSurface> tempCb = new gfxImageSurface(deserializer.GetCbData(),
|
||||
gfxCbCrSize, deserializer.GetCbCrStride(),
|
||||
gfxASurface::ImageFormatA8);
|
||||
RefPtr<gfxImageSurface> tempCr = new gfxImageSurface(deserializer.GetCrData(),
|
||||
gfxCbCrSize, deserializer.GetCbCrStride(),
|
||||
gfxASurface::ImageFormatA8);
|
||||
|
||||
nsIntRegion yRegion(nsIntRect(0, 0, gfxSize.width, gfxSize.height));
|
||||
|
@ -215,6 +215,7 @@ CPPSRCS += MIR.cpp \
|
||||
IonMacroAssembler.cpp \
|
||||
IonSpewer.cpp \
|
||||
JSONSpewer.cpp \
|
||||
PerfSpewer.cpp \
|
||||
LICM.cpp \
|
||||
LinearScan.cpp \
|
||||
LIR.cpp \
|
||||
|
@ -14,8 +14,7 @@ PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS))
|
||||
###############
|
||||
export_tier_%:
|
||||
@$(ECHO) "$@"
|
||||
@$(MAKE_TIER_SUBMAKEFILES)
|
||||
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,export,$(dir)))
|
||||
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,export,$(dir)))
|
||||
|
||||
#################
|
||||
## Common targets
|
||||
|
@ -14,8 +14,7 @@ PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS))
|
||||
###############
|
||||
libs_tier_%:
|
||||
@$(ECHO) "$@"
|
||||
@$(MAKE_TIER_SUBMAKEFILES)
|
||||
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,libs,$(dir)))
|
||||
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,libs,$(dir)))
|
||||
|
||||
#################
|
||||
## Common targets
|
||||
|
@ -14,8 +14,7 @@ PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS))
|
||||
###############
|
||||
tools_tier_%:
|
||||
@$(ECHO) "$@"
|
||||
@$(MAKE_TIER_SUBMAKEFILES)
|
||||
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,tools,$(dir)))
|
||||
$(foreach dir,$(tier_$*_dirs),$(call TIER_DIR_SUBMAKE,tools,$(dir)))
|
||||
|
||||
#################
|
||||
## Common targets
|
||||
|
@ -425,6 +425,14 @@ define SUBMAKE # $(call SUBMAKE,target,directory)
|
||||
|
||||
endef # The extra line is important here! don't delete it
|
||||
|
||||
define TIER_DIR_SUBMAKE
|
||||
@echo "BUILDSTATUS TIERDIR_START $(2)"
|
||||
$(call SUBMAKE,$(1),$(2))
|
||||
@echo "BUILDSTATUS TIERDIR_FINISH $(2)"
|
||||
|
||||
endef # Ths empty line is important.
|
||||
|
||||
|
||||
ifneq (,$(strip $(DIRS)))
|
||||
LOOP_OVER_DIRS = \
|
||||
$(foreach dir,$(DIRS),$(call SUBMAKE,$@,$(dir)))
|
||||
@ -627,6 +635,16 @@ endif
|
||||
# other rules for the default target or else it may not run in time.
|
||||
ifndef MOZBUILD_BACKEND_CHECKED
|
||||
|
||||
# Since Makefile is listed as a global dependency, this has the
|
||||
# unfortunate side-effect of invalidating all targets if it is executed.
|
||||
# So e.g. if you are in /dom/bindings and /foo/moz.build changes,
|
||||
# /dom/bindings will get invalidated. The upside is if the current
|
||||
# Makefile/backend.mk is updated as a result of backend regeneration, we
|
||||
# actually pick up the changes. This should reduce the amount of
|
||||
# required clobbers and is thus the lesser evil.
|
||||
Makefile: $(DEPTH)/backend.RecursiveMakeBackend.built
|
||||
@$(TOUCH) $@
|
||||
|
||||
$(DEPTH)/backend.RecursiveMakeBackend.built:
|
||||
@echo "Build configuration changed. Regenerating backend."
|
||||
@cd $(DEPTH) && $(PYTHON) ./config.status
|
||||
@ -650,6 +668,7 @@ SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS))
|
||||
ifndef SUPPRESS_DEFAULT_RULES
|
||||
ifdef TIERS
|
||||
default all alldep::
|
||||
@echo "BUILDSTATUS TIERS $(TIERS)"
|
||||
$(foreach tier,$(TIERS),$(call SUBMAKE,tier_$(tier)))
|
||||
else
|
||||
|
||||
@ -679,14 +698,44 @@ ECHO := true
|
||||
QUIET := -q
|
||||
endif
|
||||
|
||||
MAKE_TIER_SUBMAKEFILES = +$(if $(tier_$*_dirs),$(MAKE) $(addsuffix /Makefile,$(tier_$*_dirs)))
|
||||
# This function is called and evaluated to produce the rule to build the
|
||||
# specified tier. Each tier begins by building the "static" directories.
|
||||
# The BUILDSTATUS echo commands are used to faciliate easier parsing
|
||||
# of build output. Build drivers are encouraged to filter these lines
|
||||
# from the user.
|
||||
define CREATE_TIER_RULE
|
||||
tier_$(1)::
|
||||
@echo "BUILDSTATUS TIER_START $(1)"
|
||||
@printf "BUILDSTATUS SUBTIERS"
|
||||
ifneq (,$(tier_$(1)_staticdirs))
|
||||
@printf " static"
|
||||
endif
|
||||
ifneq (,$(tier_$(1)_dirs))
|
||||
@printf " export libs tools"
|
||||
endif
|
||||
@printf "\n"
|
||||
@echo "BUILDSTATUS STATICDIRS $$($$@_staticdirs)"
|
||||
@echo "BUILDSTATUS DIRS $$($$@_dirs)"
|
||||
ifneq (,$(tier_$(1)_staticdirs))
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) static"
|
||||
$$(foreach dir,$$($$@_staticdirs),$$(call TIER_DIR_SUBMAKE,,$$(dir)))
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) static"
|
||||
endif
|
||||
ifneq (,$(tier_$(1)_dirs))
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) export"
|
||||
$$(MAKE) export_$$@
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) export"
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) libs"
|
||||
$$(MAKE) libs_$$@
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) libs"
|
||||
@echo "BUILDSTATUS SUBTIER_START $(1) tools"
|
||||
$$(MAKE) tools_$$@
|
||||
@echo "BUILDSTATUS SUBTIER_FINISH $(1) tools"
|
||||
@echo "BUILDSTATUS TIER_FINISH $(1)"
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach tier,$(TIERS),tier_$(tier))::
|
||||
@$(ECHO) "$@: $($@_staticdirs) $($@_dirs)"
|
||||
$(foreach dir,$($@_staticdirs),$(call SUBMAKE,,$(dir)))
|
||||
$(MAKE) export_$@
|
||||
$(MAKE) libs_$@
|
||||
$(MAKE) tools_$@
|
||||
$(foreach tier,$(TIERS),$(eval $(call CREATE_TIER_RULE,$(tier))))
|
||||
|
||||
# Do everything from scratch
|
||||
everything::
|
||||
|
@ -3708,6 +3708,18 @@ if test -n "$JS_GC_ZEAL" -o -n "$MOZ_DEBUG"; then
|
||||
AC_DEFINE(JS_GC_ZEAL)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable perf logging for ion.
|
||||
dnl = Perf logging is OFF by default
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(perf,
|
||||
[ --enable-perf Enable Linux perf integration],
|
||||
JS_ION_PERF=1,
|
||||
JS_ION_PERF= )
|
||||
if test -n "$JS_ION_PERF"; then
|
||||
AC_DEFINE(JS_ION_PERF)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl JS opt-mode assertions and minidump instrumentation
|
||||
dnl ========================================================
|
||||
|
@ -2478,6 +2478,22 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
|
||||
bce->switchToMain();
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a prologue for run-once scripts which will deoptimize JIT code if
|
||||
* the script ends up running multiple times via foo.caller related
|
||||
* shenanigans.
|
||||
*/
|
||||
bool runOnce = bce->parent &&
|
||||
bce->parent->emittingRunOnceLambda &&
|
||||
!funbox->argumentsHasLocalBinding() &&
|
||||
!funbox->isGenerator();
|
||||
if (runOnce) {
|
||||
bce->switchToProlog();
|
||||
if (!Emit1(cx, bce, JSOP_RUNONCE) < 0)
|
||||
return false;
|
||||
bce->switchToMain();
|
||||
}
|
||||
|
||||
if (!EmitTree(cx, bce, body))
|
||||
return false;
|
||||
|
||||
@ -2495,8 +2511,10 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
|
||||
* If this function is only expected to run once, mark the script so that
|
||||
* initializers created within it may be given more precise types.
|
||||
*/
|
||||
if (bce->parent && bce->parent->emittingRunOnceLambda)
|
||||
if (runOnce) {
|
||||
bce->script->treatAsRunOnce = true;
|
||||
JS_ASSERT(!bce->script->hasRunOnce);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark as singletons any function which will only be executed once, or
|
||||
|
@ -17,6 +17,7 @@ using namespace js;
|
||||
using namespace js::frontend;
|
||||
using namespace mozilla;
|
||||
|
||||
#include "ion/PerfSpewer.h"
|
||||
#include "ion/CodeGenerator.h"
|
||||
#include "ion/MIR.h"
|
||||
#include "ion/MIRGraph.h"
|
||||
|
@ -295,6 +295,10 @@ ConvertFrames(JSContext *cx, IonActivation *activation, IonBailoutIterator &it)
|
||||
while (true) {
|
||||
IonSpew(IonSpew_Bailouts, " restoring frame");
|
||||
fp->initFromBailout(cx, iter);
|
||||
// If the IonScript wasn't compiled with SPS enabled, make sure that the StackFrame
|
||||
// frame isn't marked as having a pushed SPS frame.
|
||||
if (!it.ionScript()->hasSPSInstrumentation())
|
||||
fp->unsetPushedSPSFrame();
|
||||
|
||||
if (!iter.moreFrames())
|
||||
break;
|
||||
|
@ -443,8 +443,8 @@ struct BaselineStackBuilder
|
||||
//
|
||||
static bool
|
||||
InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||
HandleFunction fun, HandleScript script, SnapshotIterator &iter,
|
||||
bool invalidate, BaselineStackBuilder &builder,
|
||||
HandleFunction fun, HandleScript script, IonScript *ionScript,
|
||||
SnapshotIterator &iter, bool invalidate, BaselineStackBuilder &builder,
|
||||
MutableHandleFunction nextCallee, jsbytecode **callPC)
|
||||
{
|
||||
uint32_t exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(script, fun));
|
||||
@ -503,7 +503,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||
// If SPS Profiler is enabled, mark the frame as having pushed an SPS entry.
|
||||
// This may be wrong for the last frame of ArgumentCheck bailout, but
|
||||
// that will be fixed later.
|
||||
if (cx->runtime->spsProfiler.enabled()) {
|
||||
if (cx->runtime->spsProfiler.enabled() && ionScript->hasSPSInstrumentation()) {
|
||||
IonSpew(IonSpew_BaselineBailouts, " Setting SPS flag on frame!");
|
||||
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
|
||||
}
|
||||
@ -1080,8 +1080,8 @@ ion::BailoutIonToBaseline(JSContext *cx, IonActivation *activation, IonBailoutIt
|
||||
IonSpew(IonSpew_BaselineBailouts, " FrameNo %d", frameNo);
|
||||
jsbytecode *callPC = NULL;
|
||||
RootedFunction nextCallee(cx, NULL);
|
||||
if (!InitFromBailout(cx, caller, callerPC, fun, scr, snapIter, invalidate, builder,
|
||||
&nextCallee, &callPC))
|
||||
if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
|
||||
snapIter, invalidate, builder, &nextCallee, &callPC))
|
||||
{
|
||||
return BAILOUT_RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
@ -67,6 +67,9 @@ BaselineCompiler::compile()
|
||||
IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
|
||||
script->filename(), script->lineno, script.get());
|
||||
|
||||
if (cx->typeInferenceEnabled() && !script->ensureHasBytecodeTypeMap(cx))
|
||||
return Method_Error;
|
||||
|
||||
// Only need to analyze scripts which are marked |argumensHasVarBinding|, to
|
||||
// compute |needsArgsObj| flag.
|
||||
if (script->argumentsHasVarBinding()) {
|
||||
@ -1666,14 +1669,22 @@ BaselineCompiler::emit_JSOP_DELPROP()
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
BaselineCompiler::getScopeCoordinateAddress(Register reg)
|
||||
void
|
||||
BaselineCompiler::getScopeCoordinateObject(Register reg)
|
||||
{
|
||||
ScopeCoordinate sc(pc);
|
||||
|
||||
masm.loadPtr(frame.addressOfScopeChain(), reg);
|
||||
for (unsigned i = sc.hops; i; i--)
|
||||
masm.extractObject(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
|
||||
}
|
||||
|
||||
Address
|
||||
BaselineCompiler::getScopeCoordinateAddress(Register reg)
|
||||
{
|
||||
getScopeCoordinateObject(reg);
|
||||
|
||||
ScopeCoordinate sc(pc);
|
||||
|
||||
Shape *shape = ScopeCoordinateToStaticScopeShape(cx, script, pc);
|
||||
Address addr;
|
||||
@ -1710,6 +1721,29 @@ BaselineCompiler::emit_JSOP_CALLALIASEDVAR()
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SETALIASEDVAR()
|
||||
{
|
||||
JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script, pc);
|
||||
if (outerScript && outerScript->treatAsRunOnce) {
|
||||
// Type updates for this operation might need to be tracked, so treat
|
||||
// this as a SETPROP.
|
||||
|
||||
// Load rhs into R1.
|
||||
frame.syncStack(1);
|
||||
frame.popValue(R1);
|
||||
|
||||
// Load and box lhs into R0.
|
||||
getScopeCoordinateObject(R2.scratchReg());
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
|
||||
|
||||
// Call SETPROP IC.
|
||||
ICSetProp_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_)))
|
||||
return false;
|
||||
|
||||
// The IC will return the RHS value in R0, mark it as pushed value.
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sync everything except the top value, so that we can use R0 as scratch
|
||||
// (storeValue does not touch it if the top value is in R0).
|
||||
frame.syncStack(1);
|
||||
@ -2435,6 +2469,23 @@ BaselineCompiler::emit_JSOP_ARGUMENTS()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
|
||||
static const VMFunction RunOnceScriptPrologueInfo =
|
||||
FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_RUNONCE()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
masm.movePtr(ImmGCPtr(script), R0.scratchReg());
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
return callVM(RunOnceScriptPrologueInfo);
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_REST()
|
||||
{
|
||||
|
@ -152,6 +152,7 @@ namespace ion {
|
||||
_(JSOP_EXCEPTION) \
|
||||
_(JSOP_DEBUGGER) \
|
||||
_(JSOP_ARGUMENTS) \
|
||||
_(JSOP_RUNONCE) \
|
||||
_(JSOP_REST) \
|
||||
_(JSOP_TOID) \
|
||||
_(JSOP_TABLESWITCH) \
|
||||
@ -236,6 +237,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
||||
|
||||
bool addPCMappingEntry(bool addIndexEntry);
|
||||
|
||||
void getScopeCoordinateObject(Register reg);
|
||||
Address getScopeCoordinateAddress(Register reg);
|
||||
};
|
||||
|
||||
|
@ -6191,9 +6191,17 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
|
||||
JSOp op = JSOp(*pc);
|
||||
FallbackICSpew(cx, stub, "SetProp(%s)", js_CodeName[op]);
|
||||
|
||||
JS_ASSERT(op == JSOP_SETPROP || op == JSOP_SETNAME || op == JSOP_SETGNAME || op == JSOP_INITPROP);
|
||||
JS_ASSERT(op == JSOP_SETPROP ||
|
||||
op == JSOP_SETNAME ||
|
||||
op == JSOP_SETGNAME ||
|
||||
op == JSOP_INITPROP ||
|
||||
op == JSOP_SETALIASEDVAR);
|
||||
|
||||
RootedPropertyName name(cx, script->getName(pc));
|
||||
RootedPropertyName name(cx);
|
||||
if (op == JSOP_SETALIASEDVAR)
|
||||
name = ScopeCoordinateName(cx, script, pc);
|
||||
else
|
||||
name = script->getName(pc);
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
RootedObject obj(cx, ToObjectFromStack(cx, lhs));
|
||||
@ -6209,6 +6217,8 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
|
||||
} else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
|
||||
if (!SetNameOperation(cx, script, pc, obj, rhs))
|
||||
return false;
|
||||
} else if (op == JSOP_SETALIASEDVAR) {
|
||||
obj->asScope().setAliasedVar(cx, pc, name, rhs);
|
||||
} else if (script->strict) {
|
||||
if (!js::SetProperty<true>(cx, obj, id, rhs))
|
||||
return false;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "PerfSpewer.h"
|
||||
#include "CodeGenerator.h"
|
||||
#include "IonLinker.h"
|
||||
#include "IonSpewer.h"
|
||||
@ -2501,6 +2502,9 @@ CodeGenerator::generateBody()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PerfBlockEnabled())
|
||||
perfSpewer_.startBasicBlock(current->mir(), masm);
|
||||
|
||||
for (; iter != current->end(); iter++) {
|
||||
IonSpew(IonSpew_Codegen, "instruction %s", iter->opName());
|
||||
|
||||
@ -2520,6 +2524,9 @@ CodeGenerator::generateBody()
|
||||
}
|
||||
if (masm.oom())
|
||||
return false;
|
||||
|
||||
if (PerfBlockEnabled())
|
||||
perfSpewer_.endBasicBlock(masm);
|
||||
}
|
||||
|
||||
JS_ASSERT(pushedArgumentSlots_.empty());
|
||||
@ -2799,7 +2806,7 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape,
|
||||
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape,
|
||||
HandleTypeObject, HeapSlot *);
|
||||
static const VMFunction NewCallObjectInfo =
|
||||
FunctionInfo<NewCallObjectFn>(NewCallObject);
|
||||
@ -2815,25 +2822,33 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
|
||||
OutOfLineCode *ool;
|
||||
if (lir->slots()->isRegister()) {
|
||||
ool = oolCallVM(NewCallObjectInfo, lir,
|
||||
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->type()),
|
||||
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
|
||||
ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->hasLazyType() ? NULL : templateObj->type()),
|
||||
ToRegister(lir->slots())),
|
||||
StoreRegisterTo(obj));
|
||||
} else {
|
||||
ool = oolCallVM(NewCallObjectInfo, lir,
|
||||
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->type()),
|
||||
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
|
||||
ImmGCPtr(templateObj->lastProperty()),
|
||||
ImmGCPtr(templateObj->hasLazyType() ? NULL : templateObj->type()),
|
||||
ImmWord((void *)NULL)),
|
||||
StoreRegisterTo(obj));
|
||||
}
|
||||
if (!ool)
|
||||
return false;
|
||||
|
||||
masm.newGCThing(obj, templateObj, ool->entry());
|
||||
masm.initGCThing(obj, templateObj);
|
||||
if (lir->mir()->needsSingletonType()) {
|
||||
// Objects can only be given singleton types in VM calls.
|
||||
masm.jump(ool->entry());
|
||||
} else {
|
||||
masm.newGCThing(obj, templateObj, ool->entry());
|
||||
masm.initGCThing(obj, templateObj);
|
||||
|
||||
if (lir->slots()->isRegister())
|
||||
masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
|
||||
}
|
||||
|
||||
if (lir->slots()->isRegister())
|
||||
masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots()));
|
||||
masm.bind(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
@ -5000,6 +5015,17 @@ CodeGenerator::visitGetArgument(LGetArgument *lir)
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
|
||||
static const VMFunction RunOnceScriptPrologueInfo =
|
||||
FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitRunOncePrologue(LRunOncePrologue *lir)
|
||||
{
|
||||
pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
|
||||
return callVM(RunOnceScriptPrologueInfo, lir);
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
|
||||
Register temp0, Register temp1, unsigned numFormals,
|
||||
@ -5214,6 +5240,10 @@ CodeGenerator::link()
|
||||
ionScript->setMethod(code);
|
||||
ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
|
||||
|
||||
// If SPS is enabled, mark IonScript as having been instrumented with SPS
|
||||
if (sps_.enabled())
|
||||
ionScript->setHasSPSInstrumentation();
|
||||
|
||||
SetIonScript(script, executionMode, ionScript);
|
||||
|
||||
if (!ionScript)
|
||||
@ -5234,6 +5264,9 @@ CodeGenerator::link()
|
||||
|
||||
ionScript->setDeoptTable(deoptTable_);
|
||||
|
||||
if (PerfEnabled())
|
||||
perfSpewer_.writeProfile(script, code, masm);
|
||||
|
||||
// for generating inline caches during the execution.
|
||||
if (runtimeData_.length())
|
||||
ionScript->copyRuntimeData(&runtimeData_[0]);
|
||||
@ -5670,7 +5703,7 @@ CodeGenerator::visitBindNameIC(OutOfLineUpdateCache *ool, BindNameIC *ic)
|
||||
}
|
||||
|
||||
typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
|
||||
HandlePropertyName, const HandleValue, bool, bool);
|
||||
HandlePropertyName, const HandleValue, bool, int);
|
||||
static const VMFunction SetPropertyInfo =
|
||||
FunctionInfo<SetPropertyFn>(SetProperty);
|
||||
|
||||
@ -5680,10 +5713,9 @@ CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
|
||||
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
|
||||
|
||||
const Register objReg = ToRegister(ins->getOperand(0));
|
||||
jsbytecode *pc = ins->mir()->resumePoint()->pc();
|
||||
bool isSetName = JSOp(*pc) == JSOP_SETNAME || JSOp(*pc) == JSOP_SETGNAME;
|
||||
JSOp op = JSOp(*ins->mir()->resumePoint()->pc());
|
||||
|
||||
pushArg(Imm32(isSetName));
|
||||
pushArg(Imm32(op));
|
||||
pushArg(Imm32(ins->mir()->strict()));
|
||||
|
||||
pushArg(value);
|
||||
|
@ -215,6 +215,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitIteratorEnd(LIteratorEnd *lir);
|
||||
bool visitArgumentsLength(LArgumentsLength *lir);
|
||||
bool visitGetArgument(LGetArgument *lir);
|
||||
bool visitRunOncePrologue(LRunOncePrologue *lir);
|
||||
bool emitRest(LInstruction *lir, Register array, Register numActuals,
|
||||
Register temp0, Register temp1, unsigned numFormals,
|
||||
JSObject *templateObject, const VMFunction &f);
|
||||
@ -335,6 +336,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
|
||||
// Script counts created when compiling code with no associated JSScript.
|
||||
IonScriptCounts *unassociatedScriptCounts_;
|
||||
|
||||
PerfSpewer perfSpewer_;
|
||||
};
|
||||
|
||||
} // namespace ion
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "vm/ThreadPool.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "IonCompartment.h"
|
||||
#include "PerfSpewer.h"
|
||||
#include "CodeGenerator.h"
|
||||
#include "jsworkers.h"
|
||||
#include "BacktrackingAllocator.h"
|
||||
@ -158,6 +159,7 @@ ion::InitializeIon()
|
||||
}
|
||||
#endif
|
||||
CheckLogging();
|
||||
CheckPerf();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -494,6 +496,11 @@ IonCode::finalize(FreeOp *fop)
|
||||
// Buffer can be freed at any time hereafter. Catch use-after-free bugs.
|
||||
JS_POISON(code_, JS_FREE_PATTERN, bufferSize_);
|
||||
|
||||
// Horrible hack: if we are using perf integration, we don't
|
||||
// want to reuse code addresses, so we just leak the memory instead.
|
||||
if (PerfEnabled())
|
||||
return;
|
||||
|
||||
// Code buffers are stored inside JSC pools.
|
||||
// Pools are refcounted. Releasing the pool may free it.
|
||||
if (pool_)
|
||||
@ -560,6 +567,7 @@ IonScript::IonScript()
|
||||
invalidateEpilogueDataOffset_(0),
|
||||
numBailouts_(0),
|
||||
hasInvalidatedCallTarget_(false),
|
||||
hasSPSInstrumentation_(false),
|
||||
runtimeData_(0),
|
||||
runtimeSize_(0),
|
||||
cacheIndex_(0),
|
||||
@ -1476,8 +1484,13 @@ CheckFrame(AbstractFramePtr fp)
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckScript(JSScript *script, bool osr)
|
||||
CheckScript(JSContext *cx, JSScript *script, bool osr)
|
||||
{
|
||||
if (!script->analyzedArgsUsage() && !script->ensureRanAnalysis(cx)) {
|
||||
IonSpew(IonSpew_Abort, "OOM under ensureRanAnalysis");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (osr && script->needsArgsObj()) {
|
||||
// OSR-ing into functions with arguments objects is not supported.
|
||||
IonSpew(IonSpew_Abort, "OSR script has argsobj");
|
||||
@ -1538,7 +1551,7 @@ SequentialCompileContext::checkScriptSize(JSContext *cx, JSScript *script)
|
||||
bool
|
||||
CanIonCompileScript(JSContext *cx, HandleScript script, bool osr)
|
||||
{
|
||||
if (!script->canIonCompile() || !CheckScript(script, osr))
|
||||
if (!script->canIonCompile() || !CheckScript(cx, script, osr))
|
||||
return false;
|
||||
|
||||
SequentialCompileContext compileContext;
|
||||
@ -1568,7 +1581,7 @@ Compile(JSContext *cx, HandleScript script, AbstractFramePtr fp, jsbytecode *osr
|
||||
return Method_CantCompile;
|
||||
}
|
||||
|
||||
if (!CheckScript(script, bool(osrPc))) {
|
||||
if (!CheckScript(cx, script, bool(osrPc))) {
|
||||
IonSpew(IonSpew_Abort, "Aborted compilation of %s:%d", script->filename(), script->lineno);
|
||||
return Method_CantCompile;
|
||||
}
|
||||
|
@ -1191,6 +1191,9 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
case JSOP_ARGUMENTS:
|
||||
return jsop_arguments();
|
||||
|
||||
case JSOP_RUNONCE:
|
||||
return jsop_runonce();
|
||||
|
||||
case JSOP_REST:
|
||||
return jsop_rest();
|
||||
|
||||
@ -1302,7 +1305,8 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
case JSOP_CALLGNAME:
|
||||
{
|
||||
RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
|
||||
return jsop_getgname(name);
|
||||
RootedObject obj(cx, &script()->global());
|
||||
return getStaticName(obj, name);
|
||||
}
|
||||
|
||||
case JSOP_BINDGNAME:
|
||||
@ -1311,7 +1315,8 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
case JSOP_SETGNAME:
|
||||
{
|
||||
RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
|
||||
return jsop_setgname(name);
|
||||
RootedObject obj(cx, &script()->global());
|
||||
return setStaticName(obj, name);
|
||||
}
|
||||
|
||||
case JSOP_NAME:
|
||||
@ -4279,8 +4284,9 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
|
||||
|
||||
// Allocate the actual object. It is important that no intervening
|
||||
// instructions could potentially bailout, thus leaking the dynamic slots
|
||||
// pointer.
|
||||
MInstruction *callObj = MNewCallObject::New(templateObj, slots);
|
||||
// pointer. Run-once scripts need a singleton type, so always do a VM call
|
||||
// in such cases.
|
||||
MInstruction *callObj = MNewCallObject::New(templateObj, script()->treatAsRunOnce, slots);
|
||||
current->add(callObj);
|
||||
|
||||
// Initialize the object's reserved slots. No post barrier is needed here,
|
||||
@ -5900,44 +5906,45 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_getgname(HandlePropertyName name)
|
||||
IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
{
|
||||
// Optimize undefined, NaN, and Infinity.
|
||||
if (name == cx->names().undefined)
|
||||
return pushConstant(UndefinedValue());
|
||||
if (name == cx->names().NaN)
|
||||
return pushConstant(cx->runtime->NaNValue);
|
||||
if (name == cx->names().Infinity)
|
||||
return pushConstant(cx->runtime->positiveInfinityValue);
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
|
||||
|
||||
RootedObject globalObj(cx, &script()->global());
|
||||
JS_ASSERT(globalObj->isNative());
|
||||
if (staticObject->isGlobal()) {
|
||||
// Optimize undefined, NaN, and Infinity.
|
||||
if (name == cx->names().undefined)
|
||||
return pushConstant(UndefinedValue());
|
||||
if (name == cx->names().NaN)
|
||||
return pushConstant(cx->runtime->NaNValue);
|
||||
if (name == cx->names().Infinity)
|
||||
return pushConstant(cx->runtime->positiveInfinityValue);
|
||||
}
|
||||
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
// For the fastest path, the property must be found, and it must be found
|
||||
// as a normal data property on exactly the global object.
|
||||
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
|
||||
RootedShape shape(cx, staticObject->nativeLookup(cx, id));
|
||||
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
return jsop_getname(name);
|
||||
|
||||
types::TypeObject *globalType = globalObj->getType(cx);
|
||||
if (!globalType)
|
||||
types::TypeObject *staticType = staticObject->getType(cx);
|
||||
if (!staticType)
|
||||
return false;
|
||||
types::HeapTypeSet *propertyTypes = NULL;
|
||||
if (!globalType->unknownProperties()) {
|
||||
propertyTypes = globalType->getProperty(cx, id, false);
|
||||
if (!staticType->unknownProperties()) {
|
||||
propertyTypes = staticType->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return false;
|
||||
}
|
||||
if (propertyTypes && propertyTypes->isOwnProperty(cx, globalType, true)) {
|
||||
if (propertyTypes && propertyTypes->isOwnProperty(cx, staticType, true)) {
|
||||
// The property has been reconfigured as non-configurable, non-enumerable
|
||||
// or non-writable.
|
||||
return jsop_getname(name);
|
||||
}
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, globalType, name, types);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, staticType, name, types);
|
||||
|
||||
// If the property is permanent, a shape guard isn't necessary.
|
||||
|
||||
@ -5948,7 +5955,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
|
||||
if (singleton) {
|
||||
// Try to inline a known constant value.
|
||||
bool isKnownConstant;
|
||||
if (!TestSingletonProperty(cx, globalObj, singleton, id, &isKnownConstant))
|
||||
if (!TestSingletonProperty(cx, staticObject, singleton, id, &isKnownConstant))
|
||||
return false;
|
||||
if (isKnownConstant)
|
||||
return pushConstant(ObjectValue(*singleton));
|
||||
@ -5959,27 +5966,19 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
|
||||
return pushConstant(NullValue());
|
||||
}
|
||||
|
||||
MInstruction *global = MConstant::New(ObjectValue(*globalObj));
|
||||
current->add(global);
|
||||
MInstruction *obj = MConstant::New(ObjectValue(*staticObject));
|
||||
current->add(obj);
|
||||
|
||||
// If we have a property typeset, the isOwnProperty call will trigger recompilation if
|
||||
// the property is deleted or reconfigured.
|
||||
if (!propertyTypes && shape->configurable())
|
||||
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
|
||||
obj = addShapeGuard(obj, staticObject->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
|
||||
MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
|
||||
if (barrier)
|
||||
rvalType = MIRType_Value;
|
||||
|
||||
MSlots *slots = MSlots::New(global);
|
||||
current->add(slots);
|
||||
MLoadSlot *load = MLoadSlot::New(slots, shape->slot() - globalObj->numFixedSlots());
|
||||
current->add(load);
|
||||
|
||||
// Slot loads can be typed, if they have a single, known, definitive type.
|
||||
if (knownType != JSVAL_TYPE_UNKNOWN && !barrier)
|
||||
load->setResultType(MIRTypeFromValueType(knownType));
|
||||
|
||||
current->push(load);
|
||||
return pushTypeBarrier(load, types, barrier);
|
||||
return loadSlot(obj, shape, rvalType, barrier, types);
|
||||
}
|
||||
|
||||
// Whether 'types' includes all possible values represented by input/inputTypes.
|
||||
@ -6016,34 +6015,33 @@ ion::NeedsPostBarrier(CompileInfo &info, MDefinition *value)
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_setgname(HandlePropertyName name)
|
||||
IonBuilder::setStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
{
|
||||
RootedObject globalObj(cx, &script()->global());
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
JS_ASSERT(globalObj->isNative());
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
|
||||
|
||||
MDefinition *value = current->peek(-1);
|
||||
|
||||
if (globalObj->watched())
|
||||
if (staticObject->watched())
|
||||
return jsop_setprop(name);
|
||||
|
||||
// For the fastest path, the property must be found, and it must be found
|
||||
// as a normal data property on exactly the global object.
|
||||
RootedShape shape(cx, globalObj->nativeLookup(cx, id));
|
||||
RootedShape shape(cx, staticObject->nativeLookup(cx, id));
|
||||
if (!shape || !shape->hasDefaultSetter() || !shape->writable() || !shape->hasSlot())
|
||||
return jsop_setprop(name);
|
||||
|
||||
types::TypeObject *globalType = globalObj->getType(cx);
|
||||
if (!globalType)
|
||||
types::TypeObject *staticType = staticObject->getType(cx);
|
||||
if (!staticType)
|
||||
return false;
|
||||
types::HeapTypeSet *propertyTypes = NULL;
|
||||
if (!globalType->unknownProperties()) {
|
||||
propertyTypes = globalType->getProperty(cx, id, false);
|
||||
if (!staticType->unknownProperties()) {
|
||||
propertyTypes = staticType->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return false;
|
||||
}
|
||||
if (!propertyTypes || propertyTypes->isOwnProperty(cx, globalType, true)) {
|
||||
if (!propertyTypes || propertyTypes->isOwnProperty(cx, staticType, true)) {
|
||||
// The property has been reconfigured as non-configurable, non-enumerable
|
||||
// or non-writable.
|
||||
return jsop_setprop(name);
|
||||
@ -6051,48 +6049,36 @@ IonBuilder::jsop_setgname(HandlePropertyName name)
|
||||
if (!TypeSetIncludes(propertyTypes, value->type(), value->resultTypeSet()))
|
||||
return jsop_setprop(name);
|
||||
|
||||
MInstruction *global = MConstant::New(ObjectValue(*globalObj));
|
||||
current->add(global);
|
||||
current->pop();
|
||||
|
||||
// Pop the bound object on the stack.
|
||||
MDefinition *obj = current->pop();
|
||||
JS_ASSERT(&obj->toConstant()->value().toObject() == staticObject);
|
||||
|
||||
// If we have a property type set, the isOwnProperty call will trigger recompilation
|
||||
// if the property is deleted or reconfigured. Without TI, we always need a shape guard
|
||||
// to guard against the property being reconfigured as non-writable.
|
||||
if (!propertyTypes)
|
||||
global = addShapeGuard(global, globalObj->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
JS_ASSERT(shape->slot() >= globalObj->numFixedSlots());
|
||||
|
||||
MSlots *slots = MSlots::New(global);
|
||||
current->add(slots);
|
||||
obj = addShapeGuard(obj, staticObject->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
// Note: we do not use a post barrier when writing to the global object.
|
||||
// Slots in the global object will be treated as roots during a minor GC.
|
||||
current->pop();
|
||||
MStoreSlot *store = MStoreSlot::New(slots, shape->slot() - globalObj->numFixedSlots(), value);
|
||||
current->add(store);
|
||||
|
||||
// Determine whether write barrier is required.
|
||||
if (!propertyTypes || propertyTypes->needsBarrier(cx))
|
||||
store->setNeedsBarrier();
|
||||
|
||||
// Pop the global object pushed by bindgname.
|
||||
DebugOnly<MDefinition *> pushedGlobal = current->pop();
|
||||
JS_ASSERT(&pushedGlobal->toConstant()->value().toObject() == globalObj);
|
||||
if (!staticObject->isGlobal() && NeedsPostBarrier(info(), value))
|
||||
current->add(MPostWriteBarrier::New(obj, value));
|
||||
|
||||
// If the property has a known type, we may be able to optimize typed stores by not
|
||||
// storing the type tag. This only works if the property does not have its initial
|
||||
// |undefined| value; if |undefined| is assigned at a later point, it will be added
|
||||
// to the type set.
|
||||
if (propertyTypes && !globalObj->getSlot(shape->slot()).isUndefined()) {
|
||||
MIRType slotType = MIRType_None;
|
||||
if (propertyTypes && !staticObject->getSlot(shape->slot()).isUndefined()) {
|
||||
JSValueType knownType = propertyTypes->getKnownTypeTag(cx);
|
||||
if (knownType != JSVAL_TYPE_UNKNOWN)
|
||||
store->setSlotType(MIRTypeFromValueType(knownType));
|
||||
slotType = MIRTypeFromValueType(knownType);
|
||||
}
|
||||
|
||||
JS_ASSERT_IF(store->needsBarrier(), store->slotType() != MIRType_None);
|
||||
|
||||
current->push(value);
|
||||
return resumeAfter(store);
|
||||
bool needsBarrier = !propertyTypes || propertyTypes->needsBarrier(cx);
|
||||
return storeSlot(obj, shape, value, needsBarrier, slotType);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -7018,6 +7004,14 @@ GetDefiniteSlot(JSContext *cx, types::StackTypeSet *types, JSAtom *atom)
|
||||
return propertyTypes;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_runonce()
|
||||
{
|
||||
MRunOncePrologue *ins = MRunOncePrologue::New();
|
||||
current->add(ins);
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_not()
|
||||
{
|
||||
@ -7364,7 +7358,8 @@ IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier)
|
||||
IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
|
||||
MIRType slotType /* = MIRType_None */)
|
||||
{
|
||||
JS_ASSERT(shape->hasDefaultSetter());
|
||||
JS_ASSERT(shape->writable());
|
||||
@ -7387,6 +7382,8 @@ IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool n
|
||||
current->push(value);
|
||||
if (needsBarrier)
|
||||
store->setNeedsBarrier();
|
||||
if (slotType != MIRType_None)
|
||||
store->setSlotType(slotType);
|
||||
return resumeAfter(store);
|
||||
}
|
||||
|
||||
@ -8095,9 +8092,70 @@ IonBuilder::walkScopeChain(unsigned hops)
|
||||
return scope;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall)
|
||||
{
|
||||
JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script(), pc);
|
||||
if (!outerScript || !outerScript->treatAsRunOnce)
|
||||
return false;
|
||||
|
||||
types::TypeObject *funType = outerScript->function()->getType(cx);
|
||||
if (!funType)
|
||||
return false;
|
||||
if (types::HeapTypeSet::HasObjectFlags(cx, funType, types::OBJECT_FLAG_RUNONCE_INVALIDATED))
|
||||
return false;
|
||||
|
||||
// The script this aliased var operation is accessing will run only once,
|
||||
// so there will be only one call object and the aliased var access can be
|
||||
// compiled in the same manner as a global access. We still need to find
|
||||
// the call object though.
|
||||
|
||||
// Look for the call object on the current script's function's scope chain.
|
||||
// If the current script is inner to the outer script and the function has
|
||||
// singleton type then it should show up here.
|
||||
|
||||
MDefinition *scope = current->getSlot(info().scopeChainSlot());
|
||||
scope->setFoldedUnchecked();
|
||||
|
||||
JSObject *environment = script()->function()->environment();
|
||||
while (environment && !environment->isGlobal()) {
|
||||
if (environment->isCall() &&
|
||||
!environment->asCall().isForEval() &&
|
||||
environment->asCall().callee().nonLazyScript() == outerScript)
|
||||
{
|
||||
JS_ASSERT(environment->hasSingletonType());
|
||||
pcall.set(environment);
|
||||
return true;
|
||||
}
|
||||
environment = environment->enclosingScope();
|
||||
}
|
||||
|
||||
// Look for the call object on the current frame, if we are compiling the
|
||||
// outer script itself. Don't do this if we are at entry to the outer
|
||||
// script, as the call object we see will not be the real one --- after
|
||||
// entering the Ion code a different call object will be created.
|
||||
|
||||
if (script() == outerScript && fp && info().osrPc()) {
|
||||
JSObject *scope = fp.scopeChain();
|
||||
if (scope->isCall() && scope->asCall().callee().nonLazyScript() == outerScript) {
|
||||
JS_ASSERT(scope->hasSingletonType());
|
||||
pcall.set(scope);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
|
||||
{
|
||||
RootedObject call(cx);
|
||||
if (hasStaticScopeObject(sc, &call) && call) {
|
||||
RootedPropertyName name(cx, ScopeCoordinateName(cx, script(), pc));
|
||||
return getStaticName(call, name);
|
||||
}
|
||||
|
||||
MDefinition *obj = walkScopeChain(sc.hops);
|
||||
|
||||
RootedShape shape(cx, ScopeCoordinateToStaticScopeShape(cx, script(), pc));
|
||||
@ -8122,6 +8180,34 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
|
||||
bool
|
||||
IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
|
||||
{
|
||||
RootedObject call(cx);
|
||||
if (hasStaticScopeObject(sc, &call)) {
|
||||
uint32_t depth = current->stackDepth() + 1;
|
||||
if (depth > current->nslots()) {
|
||||
if (!current->increaseSlots(depth - current->nslots()))
|
||||
return false;
|
||||
}
|
||||
MDefinition *value = current->pop();
|
||||
RootedPropertyName name(cx, ScopeCoordinateName(cx, script(), pc));
|
||||
|
||||
if (call) {
|
||||
// Push the object on the stack to match the bound object expected in
|
||||
// the global and property set cases.
|
||||
MInstruction *constant = MConstant::New(ObjectValue(*call));
|
||||
current->add(constant);
|
||||
current->push(constant);
|
||||
current->push(value);
|
||||
return setStaticName(call, name);
|
||||
}
|
||||
|
||||
// The call object has type information we need to respect but we
|
||||
// couldn't find it. Just do a normal property assign.
|
||||
MDefinition *obj = walkScopeChain(sc.hops);
|
||||
current->push(obj);
|
||||
current->push(value);
|
||||
return jsop_setprop(name);
|
||||
}
|
||||
|
||||
MDefinition *rval = current->peek(-1);
|
||||
MDefinition *obj = walkScopeChain(sc.hops);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user