Merge inbound to m-c. a=merge
Merge inbound to m-c. a=merge
CLOSED TREE
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -52,17 +52,17 @@ nsCoreUtils::HasClickListener(nsIContent
(listenerManager->HasListenersFor(nsGkAtoms::onclick) ||
listenerManager->HasListenersFor(nsGkAtoms::onmousedown) ||
listenerManager->HasListenersFor(nsGkAtoms::onmouseup));
}
void
nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
int32_t aRowIndex, nsITreeColumn *aColumn,
- const nsCString& aPseudoElt)
+ const nsAString& aPseudoElt)
{
nsCOMPtr<nsIDOMElement> tcElm;
aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
if (!tcElm)
return;
nsCOMPtr<nsIContent> tcContent(do_QueryInterface(tcElm));
nsIDocument *document = tcContent->GetCurrentDoc();
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -39,17 +39,17 @@ public:
* @param aTreeBoxObj [in] tree box object
* @param aRowIndex [in] row index
* @param aColumn [in] column object
* @param aPseudoElm [in] pseudo elemenet inside the cell, see
* nsITreeBoxObject for available values
*/
static void DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
int32_t aRowIndex, nsITreeColumn *aColumn,
- const nsCString& aPseudoElt = EmptyCString());
+ const nsAString& aPseudoElt = EmptyString());
/**
* Send mouse event to the given element.
*
* @param aEventType [in] an event type (see BasicEvents.h for constants)
* @param aX [in] x coordinate in dev pixels
* @param aY [in] y coordinate in dev pixels
* @param aContent [in] the element
@@ -309,9 +309,8 @@ public:
static bool IsWhitespace(char16_t aChar)
{
return aChar == ' ' || aChar == '\n' ||
aChar == '\r' || aChar == '\t' || aChar == 0xa0;
}
};
#endif
-
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -15,16 +15,18 @@ this.EXPORTED_SYMBOLS = ['AccessFu']; //
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
const ACCESSFU_DISABLE = 0; // jshint ignore:line
const ACCESSFU_ENABLE = 1;
const ACCESSFU_AUTO = 2;
const SCREENREADER_SETTING = 'accessibility.screenreader';
+const QUICKNAV_MODES_PREF = 'accessibility.accessfu.quicknav_modes';
+const QUICKNAV_INDEX_PREF = 'accessibility.accessfu.quicknav_index';
this.AccessFu = { // jshint ignore:line
/**
* Initialize chrome-layer accessibility functionality.
* If accessibility is enabled on the platform, then a special accessibility
* mode is started.
*/
attach: function attach(aWindow) {
@@ -98,21 +100,28 @@ this.AccessFu = { // jshint ignore:line
let stylesheet = Utils.win.document.createProcessingInstruction(
'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"');
Utils.win.document.insertBefore(stylesheet, Utils.win.document.firstChild);
this.stylesheet = Cu.getWeakReference(stylesheet);
// Populate quicknav modes
this._quicknavModesPref =
- new PrefCache(
- 'accessibility.accessfu.quicknav_modes',
- (aName, aValue) => {
- this.Input.quickNavMode.updateModes(aValue);
- }, true);
+ new PrefCache(QUICKNAV_MODES_PREF, (aName, aValue, aFirstRun) => {
+ this.Input.quickNavMode.updateModes(aValue);
+ if (!aFirstRun) {
+ // If the modes change, reset the current mode index to 0.
+ Services.prefs.setIntPref(QUICKNAV_INDEX_PREF, 0);
+ }
+ }, true);
+
+ this._quicknavCurrentModePref =
+ new PrefCache(QUICKNAV_INDEX_PREF, (aName, aValue) => {
+ this.Input.quickNavMode.updateCurrentMode(Number(aValue));
+ }, true);
// Check for output notification
this._notifyOutputPref =
new PrefCache('accessibility.accessfu.notify_output');
this.Input.start();
Output.start();
@@ -662,27 +671,31 @@ var Input = {
aGesture.touches[0].y);
break;
case 'doubletap1':
this.activateCurrent();
break;
case 'taphold1':
this.sendContextMenuMessage();
break;
+ case 'doubletaphold1':
+ Utils.dispatchChromeEvent('accessibility-control', 'quicknav-menu');
+ break;
case 'swiperight1':
this.moveCursor('moveNext', 'Simple', 'gestures');
break;
case 'swipeleft1':
this.moveCursor('movePrevious', 'Simple', 'gesture');
break;
case 'swipeup1':
- this.contextAction('backward');
+ this.moveCursor(
+ 'movePrevious', this.quickNavMode.current, 'gesture', true);
break;
case 'swipedown1':
- this.contextAction('forward');
+ this.moveCursor('moveNext', this.quickNavMode.current, 'gesture', true);
break;
case 'exploreend1':
case 'dwellend1':
this.activateCurrent(null, true);
break;
case 'swiperight2':
if (aGesture.edge) {
Utils.dispatchChromeEvent('accessibility-control',
@@ -824,27 +837,22 @@ var Input = {
{rule: aRule, x: aX, y: aY, origin: 'top'});
} else {
let win = Utils.win;
Utils.winUtils.sendMouseEvent('mousemove',
aX - win.mozInnerScreenX, aY - win.mozInnerScreenY, 0, 0, 0);
}
},
- moveCursor: function moveCursor(aAction, aRule, aInputType) {
+ moveCursor: function moveCursor(aAction, aRule, aInputType, aAdjustRange) {
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
mm.sendAsyncMessage('AccessFu:MoveCursor',
- {action: aAction, rule: aRule,
- origin: 'top', inputType: aInputType});
- },
-
- contextAction: function contextAction(aDirection) {
- // XXX: For now, the only supported context action is adjusting a range.
- let mm = Utils.getMessageManager(Utils.CurrentBrowser);
- mm.sendAsyncMessage('AccessFu:AdjustRange', {direction: aDirection});
+ { action: aAction, rule: aRule,
+ origin: 'top', inputType: aInputType,
+ adjustRange: aAdjustRange });
},
moveByGranularity: function moveByGranularity(aDetails) {
const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
if (!this.editState.editing) {
if (aDetails.granularity === MOVEMENT_GRANULARITY_PARAGRAPH) {
this.moveCursor('move' + aDetails.direction, 'Paragraph', 'gesture');
@@ -952,31 +960,34 @@ var Input = {
},
quickNavMode: {
get current() {
return this.modes[this._currentIndex];
},
previous: function quickNavMode_previous() {
- if (--this._currentIndex < 0) {
- this._currentIndex = this.modes.length - 1;
- }
+ Services.prefs.setIntPref(QUICKNAV_INDEX_PREF,
+ this._currentIndex > 0 ?
+ this._currentIndex - 1 : this.modes.length - 1);
},
next: function quickNavMode_next() {
- if (++this._currentIndex >= this.modes.length) {
- this._currentIndex = 0;
- }
+ Services.prefs.setIntPref(QUICKNAV_INDEX_PREF,
+ this._currentIndex + 1 >= this.modes.length ?
+ 0 : this._currentIndex + 1);
},
updateModes: function updateModes(aModes) {
if (aModes) {
this.modes = aModes.split(',');
} else {
this.modes = [];
}
},
- _currentIndex: -1
+ updateCurrentMode: function updateCurrentMode(aModeIndex) {
+ Logger.debug('Quicknav mode:', this.modes[aModeIndex]);
+ this._currentIndex = aModeIndex;
+ }
}
};
AccessFu.Input = Input;
--- a/accessible/jsat/ContentControl.jsm
+++ b/accessible/jsat/ContentControl.jsm
@@ -89,23 +89,28 @@ this.ContentControl.prototype = {
Logger.logException(
x, 'Error handling message: ' + JSON.stringify(aMessage.json));
}
},
handleMoveCursor: function cc_handleMoveCursor(aMessage) {
let origin = aMessage.json.origin;
let action = aMessage.json.action;
+ let adjustRange = aMessage.json.adjustRange;
let vc = this.vc;
if (origin != 'child' && this.sendToChild(vc, aMessage)) {
// Forwarded succesfully to child cursor.
return;
}
+ if (adjustRange && this.adjustRange(vc.position, action === 'moveNext')) {
+ return;
+ }
+
let moved = vc[action](TraversalRules[aMessage.json.rule]);
if (moved) {
if (origin === 'child') {
// We just stepped out of a child, clear child cursor.
Utils.getMessageManager(aMessage.target).sendAsyncMessage(
'AccessFu:ClearCursor', {});
} else {
@@ -117,20 +122,24 @@ this.ContentControl.prototype = {
} else if (action === 'movePrevious') {
childAction = 'moveLast';
}
// Attempt to forward move to a potential child cursor in our
// new position.
this.sendToChild(vc, aMessage, { action: childAction }, true);
}
- } else if (!this._childMessageSenders.has(aMessage.target)) {
- // We failed to move, and the message is not from a child, so forward
- // to parent.
+ } else if (!this._childMessageSenders.has(aMessage.target) &&
+ origin !== 'top') {
+ // We failed to move, and the message is not from a parent, so forward
+ // to it.
this.sendToParent(aMessage);
+ } else {
+ this._contentScope.get().sendAsyncMessage('AccessFu:Present',
+ Presentation.noMove(action));
}
},
handleEvent: function cc_handleEvent(aEvent) {
if (aEvent.type === 'mousemove') {
this.handleMoveToPoint(
{ json: { x: aEvent.screenX, y: aEvent.screenY, rule: 'Simple' } });
}
@@ -164,17 +173,17 @@ this.ContentControl.prototype = {
handleActivate: function cc_handleActivate(aMessage) {
let activateAccessible = (aAccessible) => {
Logger.debug(() => {
return ['activateAccessible', Logger.accessibleToString(aAccessible)];
});
try {
if (aMessage.json.activateIfKey &&
- aAccessible.role != Roles.KEY) {
+ !Utils.isActivatableOnFingerUp(aAccessible)) {
// Only activate keys, don't do anything on other objects.
return;
}
} catch (e) {
// accessible is invalid. Silently fail.
return;
}
@@ -205,17 +214,17 @@ this.ContentControl.prototype = {
for (let eventType of ['mousedown', 'mouseup']) {
let evt = this.document.createEvent('MouseEvents');
evt.initMouseEvent(eventType, true, true, this.window,
x, y, 0, 0, 0, false, false, false, false, 0, null);
node.dispatchEvent(evt);
}
}
- if (aAccessible.role !== Roles.KEY) {
+ if (!Utils.isActivatableOnFingerUp(aAccessible)) {
// Keys will typically have a sound of their own.
this._contentScope.get().sendAsyncMessage('AccessFu:Present',
Presentation.actionInvoked(aAccessible, 'click'));
}
};
let focusedAcc = Utils.AccRetrieval.getAccessibleFor(
this.document.activeElement);
@@ -252,16 +261,47 @@ this.ContentControl.prototype = {
let vc = this.vc;
if (!this.sendToChild(vc, aMessage, null, true)) {
let position = vc.position;
activateAccessible(getActivatableDescendant(position) || position);
}
},
+ adjustRange: function cc_adjustRange(aAccessible, aStepUp) {
+ let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible;
+ try {
+ acc.QueryInterface(Ci.nsIAccessibleValue);
+ } catch (x) {
+ // This is not an adjustable, return false.
+ return false;
+ }
+
+ let elem = acc.DOMNode;
+ if (!elem) {
+ return false;
+ }
+
+ if (elem.tagName === 'INPUT' && elem.type === 'range') {
+ elem[aStepUp ? 'stepDown' : 'stepUp']();
+ let evt = this.document.createEvent('UIEvent');
+ evt.initEvent('change', true, true);
+ elem.dispatchEvent(evt);
+ } else {
+ let evt = this.document.createEvent('KeyboardEvent');
+ let keycode = aStepUp ? content.KeyEvent.DOM_VK_DOWN :
+ content.KeyEvent.DOM_VK_UP;
+ evt.initKeyEvent(
+ "keypress", false, true, null, false, false, false, false, keycode, 0);
+ elem.dispatchEvent(evt);
+ }
+
+ return true;
+ },
+
handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
// XXX: Add sendToChild. Right now this is only used in Android, so no need.
let direction = aMessage.json.direction;
let granularity;
switch(aMessage.json.granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
granularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -112,16 +112,21 @@ Presenter.prototype = {
editingModeChanged: function editingModeChanged(aIsEditing) {}, // jshint ignore:line
/**
* Announce something. Typically an app state change.
*/
announce: function announce(aAnnouncement) {}, // jshint ignore:line
+ /**
+ * User tried to move cursor forward or backward with no success.
+ * @param {string} aMoveMethod move method that was used (eg. 'moveNext').
+ */
+ noMove: function noMove(aMoveMethod) {},
/**
* Announce a live region.
* @param {PivotContext} aContext context object for an accessible.
* @param {boolean} aIsPolite A politeness level for a live region.
* @param {boolean} aIsHide An indicator of hide/remove event.
* @param {string} aModifiedText Optional modified text.
*/
@@ -477,17 +482,17 @@ B2GPresenter.prototype.pivotChanged =
return {
type: this.type,
details: {
eventType: 'vc-change',
data: UtteranceGenerator.genForContext(aContext),
options: {
pattern: this.PIVOT_CHANGE_HAPTIC_PATTERN,
- isKey: aContext.accessible.role === Roles.KEY,
+ isKey: Utils.isActivatableOnFingerUp(aContext.accessible),
reason: this.pivotChangedReasons[aReason],
isUserInput: aIsUserInput
}
}
};
};
B2GPresenter.prototype.valueChanged =
@@ -531,16 +536,27 @@ B2GPresenter.prototype.announce =
type: this.type,
details: {
eventType: 'announcement',
data: aAnnouncement
}
};
};
+B2GPresenter.prototype.noMove =
+ function B2GPresenter_noMove(aMoveMethod) {
+ return {
+ type: this.type,
+ details: {
+ eventType: 'no-move',
+ data: aMoveMethod
+ }
+ };
+ };
+
/**
* A braille presenter
*/
function BraillePresenter() {}
BraillePresenter.prototype = Object.create(Presenter.prototype);
BraillePresenter.prototype.type = 'Braille';
@@ -631,16 +647,20 @@ this.Presentation = { // jshint ignore:l
announce: function Presentation_announce(aAnnouncement) {
// XXX: Typically each presenter uses the UtteranceGenerator,
// but there really isn't a point here.
return [p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)) // jshint ignore:line
for each (p in this.presenters)]; // jshint ignore:line
},
+ noMove: function Presentation_noMove(aMoveMethod) {
+ return [p.noMove(aMoveMethod) for each (p in this.presenters)]; // jshint ignore:line
+ },
+
liveRegion: function Presentation_liveRegion(aAccessible, aIsPolite, aIsHide,
aModifiedText) {
let context;
if (!aModifiedText) {
context = new PivotContext(aAccessible, null, -1, -1, true,
aIsHide ? true : false);
}
return [p.liveRegion(context, aIsPolite, aIsHide, aModifiedText) // jshint ignore:line
--- a/accessible/jsat/TraversalRules.jsm
+++ b/accessible/jsat/TraversalRules.jsm
@@ -29,16 +29,20 @@ XPCOMUtils.defineLazyModuleGetter(this,
let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter) {
this._explicitMatchRoles = new Set(aRoles);
this._matchRoles = aRoles;
if (aRoles.indexOf(Roles.LABEL) < 0) {
this._matchRoles.push(Roles.LABEL);
}
+ if (aRoles.indexOf(Roles.INTERNAL_FRAME) < 0) {
+ // Used for traversing in to child OOP frames.
+ this._matchRoles.push(Roles.INTERNAL_FRAME);
+ }
this._matchFunc = aMatchFunc || function() { return Filters.MATCH; };
this.preFilter = aPreFilter || gSimplePreFilter;
}
BaseTraversalRule.prototype = {
getMatchRoles: function BaseTraversalRule_getmatchRoles(aRules) {
aRules.value = this._matchRoles;
return aRules.value.length;
@@ -93,19 +97,17 @@ var gSimpleTraversalRoles =
Roles.HEADER,
Roles.HEADING,
Roles.SLIDER,
Roles.SPINBUTTON,
Roles.OPTION,
Roles.LISTITEM,
Roles.GRID_CELL,
Roles.COLUMNHEADER,
- Roles.ROWHEADER,
- // Used for traversing in to child OOP frames.
- Roles.INTERNAL_FRAME];
+ Roles.ROWHEADER];
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
// An object is simple, if it either has a single child lineage,
// or has a flat subtree.
function isSingleLineage(acc) {
for (let child = acc; child; child = child.firstChild) {
if (Utils.visibleChildCount(child) > 1) {
return false;
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -465,16 +465,24 @@ this.Utils = { // jshint ignore:line
// emulator add-on.
window.dispatchEvent(new window.CustomEvent(aType, {
bubbles: true,
cancelable: true,
detail: details
}));
}
+ },
+
+ isActivatableOnFingerUp: function isActivatableOnFingerUp(aAccessible) {
+ if (aAccessible.role === Roles.KEY) {
+ return true;
+ }
+ let quick_activate = this.getAttributes(aAccessible)['moz-quick-activate'];
+ return quick_activate && JSON.parse(quick_activate);
}
};
/**
* State object used internally to process accessible's states.
* @param {Number} aBase Base state.
* @param {Number} aExtended Extended state.
*/
@@ -944,17 +952,17 @@ this.PrefCache = function PrefCache(aNam
this.name = aName;
this.callback = aCallback;
let branch = Services.prefs;
this.value = this._getValue(branch);
if (this.callback && aRunCallbackNow) {
try {
- this.callback(this.name, this.value);
+ this.callback(this.name, this.value, true);
} catch (x) {
Logger.logException(x);
}
}
branch.addObserver(aName, this, true);
};
@@ -977,19 +985,20 @@ PrefCache.prototype = {
} catch (x) {
// Pref does not exist.
return null;
}
},
observe: function observe(aSubject) {
this.value = this._getValue(aSubject.QueryInterface(Ci.nsIPrefBranch));
+ Logger.info('pref changed', this.name, this.value);
if (this.callback) {
try {
- this.callback(this.name, this.value);
+ this.callback(this.name, this.value, false);
} catch (x) {
Logger.logException(x);
}
}
},
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
--- a/accessible/jsat/content-script.js
+++ b/accessible/jsat/content-script.js
@@ -87,56 +87,29 @@ function scroll(aMessage) {
if (!forwardToChild(aMessage, scroll, position)) {
sendAsyncMessage('AccessFu:DoScroll',
{ bounds: Utils.getBounds(position, true),
page: aMessage.json.page,
horizontal: aMessage.json.horizontal });
}
}
-function adjustRange(aMessage) {
- function sendUpDownKey(aAccessible) {
- let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible;
- let elem = acc.DOMNode;
- if (elem) {
- if (elem.tagName === 'INPUT' && elem.type === 'range') {
- elem[aMessage.json.direction === 'forward' ? 'stepDown' : 'stepUp']();
- let changeEvent = content.document.createEvent('UIEvent');
- changeEvent.initEvent('change', true, true);
- elem.dispatchEvent(changeEvent);
- } else {
- let evt = content.document.createEvent('KeyboardEvent');
- let keycode = aMessage.json.direction == 'forward' ?
- content.KeyEvent.DOM_VK_DOWN : content.KeyEvent.DOM_VK_UP;
- evt.initKeyEvent(
- "keypress", false, true, null, false, false, false, false, keycode, 0);
- elem.dispatchEvent(evt);
- }
- }
- }
-
- let position = Utils.getVirtualCursor(content.document).position;
- if (!forwardToChild(aMessage, adjustRange, position)) {
- sendUpDownKey(position);
- }
-}
addMessageListener(
'AccessFu:Start',
function(m) {
if (m.json.logLevel) {
Logger.logLevel = Logger[m.json.logLevel];
}
Logger.debug('AccessFu:Start');
if (m.json.buildApp)
Utils.MozBuildApp = m.json.buildApp;
addMessageListener('AccessFu:ContextMenu', activateContextMenu);
addMessageListener('AccessFu:Scroll', scroll);
- addMessageListener('AccessFu:AdjustRange', adjustRange);
if (!contentControl) {
contentControl = new ContentControl(this);
}
contentControl.start();
if (!eventManager) {
eventManager = new EventManager(this, contentControl);
--- a/accessible/tests/mochitest/actions/test_treegrid.xul
+++ b/accessible/tests/mochitest/actions/test_treegrid.xul
@@ -150,18 +150,17 @@
{
var treeNode = getNode("tabletree");
waitForEvent(EVENT_REORDER, treeNode, doTestActions);
treeNode.view = new nsTreeTreeView();
}
function test1()
{
- var boxObj = getNode("tabletree").treeBoxObject;
- boxObj.view.setCellValue(0, boxObj.columns.firstColumn, "false");
+ getNode("tabletree").view.setCellValue(0, boxObj.columns.firstColumn, "false");
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
@@ -191,9 +190,8 @@
</tree>
<vbox id="debug"/>
<button oncommand="test1();" label="uncheck"/>
</vbox>
</hbox>
</window>
-
--- a/accessible/tests/mochitest/hittest/test_zoom_tree.xul
+++ b/accessible/tests/mochitest/hittest/test_zoom_tree.xul
@@ -35,26 +35,24 @@
var treecol1 = tabDocument.getElementById("treecol1");
// tree columns
hitTest(tree, treecols, treecol1);
// tree rows and cells
var treeBoxObject = tree.treeBoxObject;
var treeBodyBoxObj = tree.treeBoxObject.treeBody.boxObject;
- var xObj = {}, yObj = {}, widthObj = {}, heightObj = {};
- treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell",
- xObj, yObj, widthObj, heightObj);
+ var rect = treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell");
var treeAcc = getAccessible(tree, [nsIAccessibleTable]);
var cellAcc = treeAcc.getCellAt(1, 0);
var rowAcc = cellAcc.parent;
- var cssX = xObj.value + treeBodyBoxObj.x;
- var cssY = yObj.value + treeBodyBoxObj.y;
+ var cssX = rect.x + treeBodyBoxObj.x;
+ var cssY = rect.y + treeBodyBoxObj.y;
var [x, y] = CSSToDevicePixels(tabWindow, cssX, cssY);
testChildAtPoint(treeAcc, x, y, rowAcc, cellAcc);
testChildAtPoint(rowAcc, x, y, cellAcc, cellAcc);
// do zoom
zoomDocument(tabDocument, 1.5);
@@ -95,9 +93,8 @@
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</hbox>
</window>
-
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -13,11 +13,12 @@ support-files =
skip-if = buildapp == 'mulet'
[test_content_text.html]
skip-if = buildapp == 'mulet'
[test_explicit_names.html]
[test_gesture_tracker.html]
[test_landmarks.html]
[test_live_regions.html]
[test_output.html]
+[test_quicknav_modes.html]
[test_tables.html]
[test_pointer_relay.html]
[test_traversal.html]
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -130,17 +130,17 @@ var AccessFuTest = {
} catch (ex) {
// StopIteration exception.
this.finish();
return;
}
testFunc();
},
- runTests: function AccessFuTest_runTests() {
+ runTests: function AccessFuTest_runTests(aAdditionalPrefs) {
if (gTestFuncs.length === 0) {
ok(false, "No tests specified!");
SimpleTest.finish();
return;
}
// Create an Iterator for gTestFuncs array.
gIterator = Iterator(gTestFuncs); // jshint ignore:line
@@ -151,20 +151,21 @@ var AccessFuTest = {
AccessFu.attach(getMainChromeWindow(window));
AccessFu.readyCallback = function readyCallback() {
// Enable logging to the console service.
Logger.test = true;
Logger.logLevel = Logger.DEBUG;
};
- SpecialPowers.pushPrefEnv({
- 'set': [['accessibility.accessfu.notify_output', 1],
- ['dom.mozSettings.enabled', true]]
- }, function () {
+ var prefs = [['accessibility.accessfu.notify_output', 1],
+ ['dom.mozSettings.enabled', true]];
+ prefs.push.apply(prefs, aAdditionalPrefs);
+
+ SpecialPowers.pushPrefEnv({ 'set': prefs }, function () {
if (AccessFuTest._waitForExplicitFinish) {
// Run all test functions asynchronously.
AccessFuTest.nextTest();
} else {
// Run all test functions synchronously.
[testFunc() for (testFunc of gTestFuncs)]; // jshint ignore:line
AccessFuTest.finish();
}
@@ -359,29 +360,39 @@ var ContentMessages = {
clearCursor: {
name: 'AccessFu:ClearCursor',
json: {
origin: 'top'
}
},
- adjustRangeUp: {
- name: 'AccessFu:AdjustRange',
- json: {
- origin: 'top',
- direction: 'backward'
+ moveOrAdjustUp: function moveOrAdjustUp(aRule) {
+ return {
+ name: 'AccessFu:MoveCursor',
+ json: {
+ origin: 'top',
+ action: 'movePrevious',
+ inputType: 'gesture',
+ rule: (aRule || 'Simple'),
+ adjustRange: true
+ }
}
},
- adjustRangeDown: {
- name: 'AccessFu:AdjustRange',
- json: {
- origin: 'top',
- direction: 'forward'
+ moveOrAdjustDown: function moveOrAdjustUp(aRule) {
+ return {
+ name: 'AccessFu:MoveCursor',
+ json: {
+ origin: 'top',
+ action: 'moveNext',
+ inputType: 'gesture',
+ rule: (aRule || 'Simple'),
+ adjustRange: true
+ }
}
},
focusSelector: function focusSelector(aSelector, aBlur) {
return {
name: 'AccessFuTest:Focus',
json: {
selector: aSelector,
@@ -649,16 +660,22 @@ function ExpectedAnnouncement(aAnnouncem
eventType: AndroidEvent.ANNOUNCEMENT,
text: [ aAnnouncement],
addedCount: aAnnouncement.length
}], aOptions);
}
ExpectedAnnouncement.prototype = Object.create(ExpectedPresent.prototype);
+function ExpectedNoMove(aOptions) {
+ ExpectedPresent.call(this, {eventType: 'no-move' }, null, aOptions);
+}
+
+ExpectedNoMove.prototype = Object.create(ExpectedPresent.prototype);
+
var AndroidEvent = {
VIEW_CLICKED: 0x01,
VIEW_LONG_CLICKED: 0x02,
VIEW_SELECTED: 0x04,
VIEW_FOCUSED: 0x08,
VIEW_TEXT_CHANGED: 0x10,
WINDOW_STATE_CHANGED: 0x20,
VIEW_HOVER_ENTER: 0x80,
--- a/accessible/tests/mochitest/jsat/test_content_integration.html
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -29,16 +29,17 @@
iframe.addEventListener('mozbrowserloadend', function () {
var contentTest = new AccessFuContentTest(
[
// Simple traversal forward
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(
['Phone status bar', 'Traversal Rule test document'],
{ focused: 'body' })],
+ [ContentMessages.simpleMovePrevious, new ExpectedNoMove()],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
[ContentMessages.simpleMoveNext, new ExpectedCursorChange(
['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'],
{ focused: 'iframe' })],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'},
{'string': 'checkbutton'}, {'string': 'listStart'},
@@ -47,24 +48,24 @@
// check checkbox
[ContentMessages.activateCurrent(),
new ExpectedClickAction({ no_android: true }),
new ExpectedCheckAction(true, { android_todo: true })],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['much range', {'string': 'label'}])],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])],
- [ContentMessages.adjustRangeUp, new ExpectedValueChange('6')],
+ [ContentMessages.moveOrAdjustUp(), new ExpectedValueChange('6')],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
// Simple traversal backward
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(['much range', '6', {'string': 'slider'}, 'such app'])],
- [ContentMessages.adjustRangeDown, new ExpectedValueChange('5')],
+ [ContentMessages.moveOrAdjustDown(), new ExpectedValueChange('5')],
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(['much range', {'string': 'label'}])],
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(['many option', {'string': 'stateChecked'},
{'string': 'checkbutton'}, {'string': 'listStart'},
{'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])],
// uncheck checkbox
[ContentMessages.activateCurrent(),
@@ -86,16 +87,42 @@
['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
// Move from an inner frame to the last element in the parent doc
[ContentMessages.simpleMoveLast,
new ExpectedCursorChange(
['Home', {'string': 'pushbutton'}], { b2g_todo: true })],
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
+ [ContentMessages.simpleMoveNext,
+ new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
+ [ContentMessages.moveOrAdjustDown('FormElement'),
+ new ExpectedCursorChange(['Back', {"string": "pushbutton"}])],
+ [ContentMessages.moveOrAdjustDown('FormElement'),
+ new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'},
+ {'string': 'checkbutton'}, {'string': 'listStart'},
+ {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}, 'such app'])],
+ [ContentMessages.moveOrAdjustDown('FormElement'),
+ new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])],
+ // Calling AdjustOrMove should adjust the range.
+ [ContentMessages.moveOrAdjustDown('FormElement'),
+ new ExpectedValueChange('4')],
+ [ContentMessages.moveOrAdjustUp('FormElement'),
+ new ExpectedValueChange('5')],
+ [ContentMessages.simpleMovePrevious,
+ new ExpectedCursorChange(['much range', {'string': 'label'}])],
+ [ContentMessages.moveOrAdjustUp('FormElement'),
+ new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'},
+ {'string': 'checkbutton'}, {'string': 'listStart'},
+ {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])],
+ [ContentMessages.moveOrAdjustUp('FormElement'),
+ new ExpectedCursorChange(['Back', {"string": "pushbutton"}])],
+
+ [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
+
// Moving to the absolute first item from an embedded document
// fails. Bug 972035.
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
@@ -220,17 +247,18 @@
[doc.defaultView.showAlert,
new ExpectedCursorChange(['This is an alert!',
{'string': 'headingLevel', 'args': [1]}, {'string': 'dialog'}])],
[function hideAlertAndFocusHomeButton() {
doc.defaultView.hideAlert();
doc.querySelector('button#home').focus();
}, new ExpectedCursorChange(['Home', {'string': 'pushbutton'},
- 'Traversal Rule test document'])]
+ 'Traversal Rule test document'])],
+ [ContentMessages.simpleMoveNext, new ExpectedNoMove()]
]);
addA11yLoadEvent(function() {
contentTest.start(function () {
closeBrowserWindow();
SimpleTest.finish();
});
}, doc.defaultView)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html
@@ -0,0 +1,103 @@
+<html>
+
+<head>
+ <title>AccessFu test for enabling</title>
+
+ <link rel="stylesheet" type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript"
+ src="../common.js"></script>
+ <script type="application/javascript"
+ src="./jsatcommon.js"></script>
+ <script type="application/javascript">
+
+ function prefStart() {
+ // Start AccessFu via pref.
+ SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
+ AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
+ }
+
+ function nextMode(aCurrentMode, aNextMode) {
+ return function() {
+ is(AccessFu.Input.quickNavMode.current, aCurrentMode,
+ 'initial current mode is correct');
+ AccessFu.Input.quickNavMode.next();
+ _expectMode(aNextMode, AccessFuTest.nextTest);
+ }
+ }
+
+ function prevMode(aCurrentMode, aNextMode) {
+ return function() {
+ is(AccessFu.Input.quickNavMode.current, aCurrentMode,
+ 'initial current mode is correct');
+ AccessFu.Input.quickNavMode.previous();
+ _expectMode(aNextMode, AccessFuTest.nextTest);
+ }
+ }
+
+ function setMode(aModeIndex, aExpectedMode) {
+ return function() {
+ SpecialPowers.setIntPref(
+ 'accessibility.accessfu.quicknav_index', aModeIndex);
+ _expectMode(aExpectedMode, AccessFuTest.nextTest);
+ }
+ }
+
+ function reconfigureModes() {
+ SpecialPowers.setCharPref('accessibility.accessfu.quicknav_modes',
+ 'Landmark,Button,Entry,Graphic');
+ // When the modes are reconfigured, the current mode should
+ // be set to the first in the new list.
+ _expectMode('Landmark', AccessFuTest.nextTest);
+ }
+
+ function _expectMode(aExpectedMode, aCallback) {
+ if (AccessFu.Input.quickNavMode.current === aExpectedMode) {
+ ok(true, 'correct mode');
+ aCallback();
+ } else {
+ AccessFuTest.once_log('Quicknav mode: ' + aExpectedMode, function() {
+ ok(true, 'correct mode');
+ aCallback();
+ });
+ }
+ }
+
+ // Listen for initial 'EventManager.start' and disable AccessFu.
+ function prefStop() {
+ ok(AccessFu._enabled, "AccessFu was started via preference.");
+ AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish);
+ SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
+ }
+
+ function doTest() {
+ AccessFuTest.addFunc(prefStart);
+ AccessFuTest.addFunc(nextMode('Link', 'Heading'));
+ AccessFuTest.addFunc(nextMode('Heading', 'FormElement'));
+ AccessFuTest.addFunc(nextMode('FormElement', 'Link'));
+ AccessFuTest.addFunc(nextMode('Link', 'Heading'));
+ AccessFuTest.addFunc(prevMode('Heading', 'Link'));
+ AccessFuTest.addFunc(prevMode('Link', 'FormElement'));
+ AccessFuTest.addFunc(setMode(1, 'Heading'));
+ AccessFuTest.addFunc(reconfigureModes);
+ AccessFuTest.addFunc(prefStop);
+ AccessFuTest.waitForExplicitFinish();
+ AccessFuTest.runTests([ // Will call SimpleTest.finish();
+ ['accessibility.accessfu.quicknav_modes', 'Link,Heading,FormElement']]);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+
+</head>
+<body>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=811307"
+ title="[AccessFu] Add mochitest for enabling">
+ Mozilla Bug 811307
+ </a>
+</body>
+</html>
\ No newline at end of file
--- a/accessible/tests/mochitest/name/test_tree.xul
+++ b/accessible/tests/mochitest/name/test_tree.xul
@@ -27,17 +27,17 @@
<script type="application/javascript">
<![CDATA[
function treeTester(aID)
{
this.DOMNode = getNode(aID);
this.invoke = function treeTester_invoke()
{
- this.DOMNode.treeBoxObject.view = new nsTreeTreeView();
+ this.DOMNode.view = new nsTreeTreeView();
}
this.check = function treeTester_check(aEvent)
{
var tree = {
role: ROLE_OUTLINE,
children: [
{
@@ -85,17 +85,17 @@
}
function tableTester(aID, aIsTable, aCol1ID, aCol2ID)
{
this.DOMNode = getNode(aID);
this.invoke = function tableTester_invoke()
{
- this.DOMNode.treeBoxObject.view = new nsTableTreeView(2);
+ this.DOMNode.view = new nsTableTreeView(2);
}
this.check = function tableTester_check(aEvent)
{
var tree = {
role: aIsTable ? ROLE_TABLE : ROLE_TREE_TABLE,
children: [
{
@@ -204,9 +204,8 @@
<treecol id="tt_col2" flex="1" label="column 2"/>
</treecols>
<treechildren/>
</tree>
</vbox> <!-- close tests area -->
</hbox> <!-- close main area -->
</window>
-
--- a/accessible/tests/mochitest/selectable/test_tree.xul
+++ b/accessible/tests/mochitest/selectable/test_tree.xul
@@ -37,17 +37,17 @@
* accessible.
*/
function statesChecker(aTreeID, aView)
{
this.DOMNode = getNode(aTreeID);
this.invoke = function invoke()
{
- this.DOMNode.treeBoxObject.view = aView;
+ this.DOMNode.view = aView;
}
this.check = function check()
{
var tree = getAccessible(this.DOMNode);
var isTreeMultiSelectable = false;
var seltype = this.DOMNode.getAttribute("seltype");
if (seltype != "single" && seltype != "cell" && seltype != "text")
@@ -181,9 +181,8 @@
<treechildren/>
</tree>
<vbox id="debug"/>
</vbox>
</hbox>
</window>
-
--- a/accessible/tests/mochitest/states/test_tree.xul
+++ b/accessible/tests/mochitest/states/test_tree.xul
@@ -33,17 +33,17 @@
* accessible.
*/
function statesChecker(aTreeID, aView)
{
this.DOMNode = getNode(aTreeID);
this.invoke = function statesChecker_invoke()
{
- this.DOMNode.treeBoxObject.view = aView;
+ this.DOMNode.view = aView;
}
this.check = function statesChecker_check()
{
var tree = getAccessible(this.DOMNode);
// tree states
testStates(tree, STATE_READONLY);
@@ -145,9 +145,8 @@
<treechildren/>
</tree>
<vbox id="debug"/>
</vbox>
</hbox>
</window>
-
--- a/accessible/tests/mochitest/tree/test_tree.xul
+++ b/accessible/tests/mochitest/tree/test_tree.xul
@@ -67,17 +67,17 @@
var accTreeForTree = {
role: aRole,
children: [
accTreeForColumns
]
};
var treeBoxObject = aTree.treeBoxObject;
- var view = treeBoxObject.view;
+ var view = aTree.view;
var columnCount = treeBoxObject.columns.count;
for (var idx = 0; idx < columnCount; idx++)
accTreeForColumns.children.push({ COLUMNHEADER: [ ] });
if (!aTree.hasAttribute("hidecolumnpicker"))
accTreeForColumns.children.push({ PUSHBUTTON: [ { MENUPOPUP: [] } ] });
for (var idx = 0; idx < view.rowCount; idx++)
@@ -90,17 +90,17 @@
* Event queue invoker object to test accessible tree for XUL tree element.
*/
function treeChecker(aID, aView, aRole)
{
this.DOMNode = getNode(aID);
this.invoke = function invoke()
{
- this.DOMNode.treeBoxObject.view = aView;
+ this.DOMNode.view = aView;
}
this.check = function check(aEvent)
{
testAccessibleTreeFor(this.DOMNode, aRole);
}
this.getID = function getID()
{
return "Tree testing of " + aID;
@@ -175,9 +175,8 @@
<treechildren/>
</tree>
<vbox id="debug"/>
</vbox>
</hbox>
</window>
-
--- a/accessible/tests/mochitest/treeview.js
+++ b/accessible/tests/mochitest/treeview.js
@@ -12,17 +12,17 @@ function loadXULTreeAndDoTest(aDoTestFun
this.treeNode = getNode(aTreeID);
this.eventSeq = [
new invokerChecker(EVENT_REORDER, this.treeNode)
];
this.invoke = function loadXULTree_invoke()
{
- this.treeNode.treeBoxObject.view = aTreeView;
+ this.treeNode.view = aTreeView;
}
this.getID = function loadXULTree_getID()
{
return "Load XUL tree " + prettyName(aTreeID);
}
}
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -194,17 +194,17 @@ XULTreeAccessible::ChildAtPoint(int32_t
nsIntRect rootRect = rootFrame->GetScreenRect();
int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
int32_t row = -1;
nsCOMPtr<nsITreeColumn> column;
- nsAutoCString childEltUnused;
+ nsAutoString childEltUnused;
mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
childEltUnused);
// If we failed to find tree cell for the given point then it might be
// tree columns.
if (row == -1 || !column)
return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild);
@@ -741,17 +741,17 @@ XULTreeItemAccessibleBase::Bounds() cons
nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
if (!boxObj)
return nsIntRect();
nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
int32_t x = 0, y = 0, width = 0, height = 0;
- nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyCString(),
+ nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyString(),
&x, &y, &width, &height);
if (NS_FAILED(rv))
return nsIntRect();
boxObj->GetWidth(&width);
int32_t tcX = 0, tcY = 0;
boxObj->GetScreenX(&tcX);
@@ -991,25 +991,25 @@ XULTreeItemAccessibleBase::DispatchClick
nsCOMPtr<nsITreeColumns> columns;
mTree->GetColumns(getter_AddRefs(columns));
if (!columns)
return;
// Get column and pseudo element.
nsCOMPtr<nsITreeColumn> column;
- nsAutoCString pseudoElm;
+ nsAutoString pseudoElm;
if (aActionIndex == eAction_Click) {
// Key column is visible and clickable.
columns->GetKeyColumn(getter_AddRefs(column));
} else {
// Primary column contains a twisty we should click on.
columns->GetPrimaryColumn(getter_AddRefs(column));
- pseudoElm = NS_LITERAL_CSTRING("twisty");
+ pseudoElm = NS_LITERAL_STRING("twisty");
}
if (column)
nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm);
}
Accessible*
XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset,
@@ -1191,9 +1191,8 @@ XULTreeColumAccessible::GetSiblingAtOffs
if (treeAcc)
return treeAcc->GetTreeItemAccessible(aOffset - 1);
}
}
}
return nullptr;
}
-
--- a/accessible/xul/XULTreeGridAccessible.cpp
+++ b/accessible/xul/XULTreeGridAccessible.cpp
@@ -336,17 +336,17 @@ XULTreeGridRowAccessible::ChildAtPoint(i
nsIntRect rootRect = rootFrame->GetScreenRect();
int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
int32_t row = -1;
nsCOMPtr<nsITreeColumn> column;
- nsAutoCString childEltUnused;
+ nsAutoString childEltUnused;
mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
childEltUnused);
// Return if we failed to find tree cell in the row for the given point.
if (row != mRow || !column)
return nullptr;
return GetCellAccessible(column);
@@ -517,17 +517,17 @@ XULTreeGridCellAccessible::Bounds() cons
// Get bounds for tree cell and add x and y of treechildren element to
// x and y of the cell.
nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
if (!boxObj)
return nsIntRect();
int32_t x = 0, y = 0, width = 0, height = 0;
nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn,
- NS_LITERAL_CSTRING("cell"),
+ NS_LITERAL_STRING("cell"),
&x, &y, &width, &height);
if (NS_FAILED(rv))
return nsIntRect();
int32_t tcX = 0, tcY = 0;
boxObj->GetScreenX(&tcX);
boxObj->GetScreenY(&tcY);
x += tcX;
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -3,17 +3,16 @@ dnl Local autoconf macros used with mozi
dnl The contents of this file are under the Public Domain.
dnl
builtin(include, build/autoconf/hotfixes.m4)dnl
builtin(include, build/autoconf/acwinpaths.m4)dnl
builtin(include, build/autoconf/hooks.m4)dnl
builtin(include, build/autoconf/config.status.m4)dnl
builtin(include, build/autoconf/toolchain.m4)dnl
-builtin(include, build/autoconf/ccache.m4)dnl
builtin(include, build/autoconf/wrapper.m4)dnl
builtin(include, build/autoconf/nspr.m4)dnl
builtin(include, build/autoconf/nspr-build.m4)dnl
builtin(include, build/autoconf/nss.m4)dnl
builtin(include, build/autoconf/pkg.m4)dnl
builtin(include, build/autoconf/codeset.m4)dnl
builtin(include, build/autoconf/altoptions.m4)dnl
builtin(include, build/autoconf/mozprog.m4)dnl
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -789,16 +789,18 @@ pref("dom.ipc.systemMessageCPULockTimeou
pref("dom.disable_window_open_dialog_feature", true);
// Enable before keyboard events and after keyboard events.
pref("dom.beforeAfterKeyboardEvent.enabled", true);
// Screen reader support
pref("accessibility.accessfu.activate", 2);
pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem");
+// Active quicknav mode, index value of list from quicknav_modes
+pref("accessibility.accessfu.quicknav_index", 0);
// Setting for an utterance order (0 - description first, 1 - description last).
pref("accessibility.accessfu.utterance", 1);
// Whether to skip images with empty alt text
pref("accessibility.accessfu.skip_empty_images", true);
// Enable hit-target fluffing
pref("ui.touch.radius.enabled", true);
pref("ui.touch.radius.leftmm", 3);
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -452,16 +452,26 @@ SettingsListener.observe("theme.selected
Services.prefs.setCharPref('dom.mozApps.selected_theme', newTheme);
Services.prefs.savePrefFile(null);
Services.obs.notifyObservers(null, 'app-theme-changed', newTheme);
}
});
// =================== Various simple mapping ======================
let settingsToObserve = {
+ 'accessibility.screenreader_quicknav_modes': {
+ prefName: 'accessibility.accessfu.quicknav_modes',
+ resetToPref: true,
+ defaultValue: ''
+ },
+ 'accessibility.screenreader_quicknav_index': {
+ prefName: 'accessibility.accessfu.quicknav_index',
+ resetToPref: true,
+ defaultValue: 0
+ },
'app.update.channel': {
resetToPref: true
},
'app.update.interval': 86400,
'app.update.url': {
resetToPref: true
},
'apz.force-enable': {
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -703,23 +703,22 @@ var BookmarksEventHandler = {
fillInBHTooltip: function BEH_fillInBHTooltip(aDocument, aEvent) {
var node;
var cropped = false;
var targetURI;
if (aDocument.tooltipNode.localName == "treechildren") {
var tree = aDocument.tooltipNode.parentNode;
- var row = {}, column = {};
var tbo = tree.treeBoxObject;
- tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, column, {});
- if (row.value == -1)
+ var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
+ if (cell.row == -1)
return false;
- node = tree.view.nodeForTreeIndex(row.value);
- cropped = tbo.isCellCropped(row.value, column.value);
+ node = tree.view.nodeForTreeIndex(cell.row);
+ cropped = tbo.isCellCropped(cell.row, cell.col);
}
else {
// Check whether the tooltipNode is a Places node.
// In such a case use it, otherwise check for targetURI attribute.
var tooltipNode = aDocument.tooltipNode;
if (tooltipNode._placesNode)
node = tooltipNode._placesNode;
else {
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -503,17 +503,17 @@ function makeGeneralTab()
metaGroup.collapsed = true;
else {
var metaTagsCaption = document.getElementById("metaTagsCaption");
if (length == 1)
metaTagsCaption.label = gBundle.getString("generalMetaTag");
else
metaTagsCaption.label = gBundle.getFormattedString("generalMetaTags", [length]);
var metaTree = document.getElementById("metatree");
- metaTree.treeBoxObject.view = gMetaView;
+ metaTree.view = gMetaView;
for (var i = 0; i < length; i++)
gMetaView.addRow([metaNodes[i].name || metaNodes[i].httpEquiv, metaNodes[i].content]);
metaGroup.collapsed = false;
}
// get the date of last modification
--- a/browser/base/content/sync/quota.js
+++ b/browser/base/content/sync/quota.js
@@ -156,20 +156,19 @@ let gUsageTreeView = {
/*
* Handle click events on the tree.
*/
onTreeClick: function onTreeClick(event) {
if (event.button == 2)
return;
- let row = {}, col = {};
- this.treeBox.getCellAt(event.clientX, event.clientY, row, col, {});
- if (col.value && col.value.id == "enabled")
- this.toggle(row.value);
+ let cell = this.treeBox.getCellAt(event.clientX, event.clientY);
+ if (cell.col && cell.col.id == "enabled")
+ this.toggle(cell.row);
},
/*
* Toggle enabled state of an engine.
*/
toggle: function toggle(row) {
// Update the tree
let collection = this._collections[row];
--- a/browser/components/feeds/FeedWriter.js
+++ b/browser/components/feeds/FeedWriter.js
@@ -853,17 +853,16 @@ FeedWriter.prototype = {
* Application" item is being selected with the keyboard. We do this
* by ignoring command events while the dropdown is closed (user
* arrowing through the combobox), but handling them while the
* combobox dropdown is open (user pressed enter when an item was
* selected). If we don't show the filepicker here, it will be shown
* when clicking "Subscribe Now".
*/
var popupbox = this._handlersMenuList.firstChild.boxObject;
- popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject);
if (popupbox.popupState == "hiding") {
this._chooseClientApp(function(aResult) {
if (!aResult) {
// Select the (per-prefs) selected handler if no application
// was selected
this._setSelectedHandler(this._getFeedType());
}
}.bind(this));
--- a/browser/components/loop/test/functional/test_1_browser_call.py
+++ b/browser/components/loop/test/functional/test_1_browser_call.py
@@ -1,14 +1,14 @@
from marionette_test import MarionetteTestCase
from by import By
import urlparse
-from marionette.errors import NoSuchElementException, StaleElementException
+from errors import NoSuchElementException, StaleElementException
# noinspection PyUnresolvedReferences
-from marionette.wait import Wait
+from wait import Wait
from time import sleep
import os
import sys
sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
from serversetup import LoopTestServers
from config import *
--- a/browser/components/loop/test/xpcshell/head.js
+++ b/browser/components/loop/test/xpcshell/head.js
@@ -3,16 +3,17 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Http.jsm");
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource:///modules/loop/MozLoopService.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
const { MozLoopServiceInternal } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
"resource:///modules/loop/MozLoopPushHandler.jsm");
const kMockWebSocketChannelName = "Mock WebSocket Channel";
const kWebSocketChannelContractID = "@mozilla.org/network/protocol;1?name=wss";
--- a/browser/components/places/content/sidebarUtils.js
+++ b/browser/components/places/content/sidebarUtils.js
@@ -5,66 +5,63 @@
var SidebarUtils = {
handleTreeClick: function SU_handleTreeClick(aTree, aEvent, aGutterSelect) {
// right-clicks are not handled here
if (aEvent.button == 2)
return;
var tbo = aTree.treeBoxObject;
- var row = { }, col = { }, obj = { };
- tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
+ var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
- if (row.value == -1 || obj.value == "twisty")
+ if (cell.row == -1 || cell.childElt == "twisty")
return;
var mouseInGutter = false;
if (aGutterSelect) {
- var x = { }, y = { }, w = { }, h = { };
- tbo.getCoordsForCellItem(row.value, col.value, "image",
- x, y, w, h);
+ var rect = tbo.getCoordsForCellItem(cell.row, cell.col, "image");
// getCoordsForCellItem returns the x coordinate in logical coordinates
// (i.e., starting from the left and right sides in LTR and RTL modes,
// respectively.) Therefore, we make sure to exclude the blank area
// before the tree item icon (that is, to the left or right of it in
// LTR and RTL modes, respectively) from the click target area.
var isRTL = window.getComputedStyle(aTree, null).direction == "rtl";
if (isRTL)
- mouseInGutter = aEvent.clientX > x.value;
+ mouseInGutter = aEvent.clientX > rect.x;
else
- mouseInGutter = aEvent.clientX < x.value;
+ mouseInGutter = aEvent.clientX < rect.x;
}
#ifdef XP_MACOSX
var modifKey = aEvent.metaKey || aEvent.shiftKey;
#else
var modifKey = aEvent.ctrlKey || aEvent.shiftKey;
#endif
- var isContainer = tbo.view.isContainer(row.value);
+ var isContainer = tbo.view.isContainer(cell.row);
var openInTabs = isContainer &&
(aEvent.button == 1 ||
(aEvent.button == 0 && modifKey)) &&
- PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(row.value), true);
+ PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(cell.row), true);
if (aEvent.button == 0 && isContainer && !openInTabs) {
- tbo.view.toggleOpenState(row.value);
+ tbo.view.toggleOpenState(cell.row);
return;
}
else if (!mouseInGutter && openInTabs &&
aEvent.originalTarget.localName == "treechildren") {
- tbo.view.selection.select(row.value);
+ tbo.view.selection.select(cell.row);
PlacesUIUtils.openContainerNodeInTabs(aTree.selectedNode, aEvent, aTree);
}
else if (!mouseInGutter && !isContainer &&
aEvent.originalTarget.localName == "treechildren") {
// Clear all other selection since we're loading a link now. We must
// do this *before* attempting to load the link since openURL uses
// selection as an indication of which link to load.
- tbo.view.selection.select(row.value);
+ tbo.view.selection.select(cell.row);
PlacesUIUtils.openNodeWithEvent(aTree.selectedNode, aEvent, aTree);
}
},
handleTreeKeyPress: function SU_handleTreeKeyPress(aEvent) {
// XXX Bug 627901: Post Fx4, this method should take a tree parameter.
let tree = aEvent.target;
let node = tree.selectedNode;
@@ -79,24 +76,23 @@ var SidebarUtils = {
* hovered over.
*/
handleTreeMouseMove: function SU_handleTreeMouseMove(aEvent) {
if (aEvent.target.localName != "treechildren")
return;
var tree = aEvent.target.parentNode;
var tbo = tree.treeBoxObject;
- var row = { }, col = { }, obj = { };
- tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
+ var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
- // row.value is -1 when the mouse is hovering an empty area within the tree.
+ // cell.row is -1 when the mouse is hovering an empty area within the tree.
// To avoid showing a URL from a previously hovered node for a currently
// hovered non-url node, we must clear the moused-over URL in these cases.
- if (row.value != -1) {
- var node = tree.view.nodeForTreeIndex(row.value);
+ if (cell.row != -1) {
+ var node = tree.view.nodeForTreeIndex(cell.row);
if (PlacesUtils.nodeIsURI(node))
this.setMouseoverURL(node.uri);
else
this.setMouseoverURL("");
}
else
this.setMouseoverURL("");
},
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -742,52 +742,50 @@
this._controller.setDataTransfer(event);
event.stopPropagation();
]]></handler>
<handler event="dragover"><![CDATA[
if (event.target.localName != "treechildren")
return;
- let row = { }, col = { }, child = { };
- this.treeBoxObject.getCellAt(event.clientX, event.clientY,
- row, col, child);
- let node = row.value != -1 ?
- this.view.nodeForTreeIndex(row.value) :
+ let cell = this.treeBoxObject.getCellAt(event.clientX, event.clientY);
+ let node = cell.row != -1 ?
+ this.view.nodeForTreeIndex(cell.row) :
this.result.root;
// cache the dropTarget for the view
PlacesControllerDragHelper.currentDropTarget = node;
// We have to calculate the orientation since view.canDrop will use
// it and we want to be consistent with the dropfeedback.
let tbo = this.treeBoxObject;
let rowHeight = tbo.rowHeight;
let eventY = event.clientY - tbo.treeBody.boxObject.y -
- rowHeight * (row.value - tbo.getFirstVisibleRow());
+ rowHeight * (cell.row - tbo.getFirstVisibleRow());
let orientation = Ci.nsITreeView.DROP_BEFORE;
- if (row.value == -1) {
+ if (cell.row == -1) {
// If the row is not valid we try to insert inside the resultNode.
orientation = Ci.nsITreeView.DROP_ON;
}
else if (PlacesUtils.nodeIsContainer(node) &&
eventY > rowHeight * 0.75) {
// If we are below the 75% of a container the treeview we try
// to drop after the node.
orientation = Ci.nsITreeView.DROP_AFTER;
}
else if (PlacesUtils.nodeIsContainer(node) &&
eventY > rowHeight * 0.25) {
// If we are below the 25% of a container the treeview we try
// to drop inside the node.
orientation = Ci.nsITreeView.DROP_ON;
}
- if (!this.view.canDrop(row.value, orientation, event.dataTransfer))
+ if (!this.view.canDrop(cell.row, orientation, event.dataTransfer))
return;
event.preventDefault();
event.stopPropagation();
]]></handler>
<handler event="dragend"><![CDATA[
PlacesControllerDragHelper.currentDropTarget = null;
--- a/browser/components/places/tests/browser/browser_forgetthissite_single.js
+++ b/browser/components/places/tests/browser/browser_forgetthissite_single.js
@@ -57,17 +57,14 @@ function test() {
organizer.removeEventListener("unload", arguments.callee, false);
// Proceed
funcNext();
}, false);
// Close Library window.
organizer.close();
}, true);
// Get cell coordinates
- var x = {}, y = {}, width = {}, height = {};
- tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "text",
- x, y, width, height);
+ var rect = tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "text");
// Initiate a context menu for the selected cell
- EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, {type: "contextmenu"}, organizer);
+ EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {type: "contextmenu"}, organizer);
});
}
}
-
--- a/browser/components/places/tests/browser/browser_library_infoBox.js
+++ b/browser/components/places/tests/browser/browser_library_infoBox.js
@@ -47,17 +47,17 @@ gTests.push({
isnot(childNode, null, "History node first child is not null.");
PO._places.selectNode(childNode);
checkInfoBoxSelected(PO);
ok(infoBoxExpanderWrapper.hidden,
"Expander button is hidden for history child node.");
checkAddInfoFieldsCollapsed(PO);
// open history item
- var view = ContentTree.view.treeBoxObject.view;
+ var view = ContentTree.view.view;
ok(view.rowCount > 0, "History item exists.");
view.selection.select(0);
ok(infoBoxExpanderWrapper.hidden,
"Expander button is hidden for history item.");
checkAddInfoFieldsCollapsed(PO);
historyNode.containerOpen = false;
@@ -84,17 +84,17 @@ gTests.push({
"Correctly selected recently bookmarked node.");
PO._places.selectNode(childNode);
checkInfoBoxSelected(PO);
ok(!infoBoxExpanderWrapper.hidden,
"Expander button is not hidden for recently bookmarked node.");
checkAddInfoFieldsNotCollapsed(PO);
// open first bookmark
- var view = ContentTree.view.treeBoxObject.view;
+ var view = ContentTree.view.view;
ok(view.rowCount > 0, "Bookmark item exists.");
view.selection.select(0);
checkInfoBoxSelected(PO);
ok(!infoBoxExpanderWrapper.hidden,
"Expander button is not hidden for bookmark item.");
checkAddInfoFieldsNotCollapsed(PO);
checkAddInfoFields(PO, "bookmark item");
--- a/browser/components/places/tests/browser/browser_library_middleclick.js
+++ b/browser/components/places/tests/browser/browser_library_middleclick.js
@@ -267,15 +267,13 @@ function runNextTest() {
function mouseEventOnCell(aTree, aRowIndex, aColumnIndex, aEventDetails) {
var selection = aTree.view.selection;
selection.select(aRowIndex);
aTree.treeBoxObject.ensureRowIsVisible(aRowIndex);
var column = aTree.columns[aColumnIndex];
// get cell coordinates
- var x = {}, y = {}, width = {}, height = {};
- aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text",
- x, y, width, height);
+ var rect = aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text");
- EventUtils.synthesizeMouse(aTree.body, x.value, y.value,
+ EventUtils.synthesizeMouse(aTree.body, rect.x, rect.y,
aEventDetails, gLibrary);
}
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -191,17 +191,15 @@ function synthesizeClickOnSelectedTreeCe
if (tbo.view.selection.count != 1)
throw new Error("The test node should be successfully selected");
// Get selection rowID.
let min = {}, max = {};
tbo.view.selection.getRangeAt(0, min, max);
let rowID = min.value;
tbo.ensureRowIsVisible(rowID);
// Calculate the click coordinates.
- let x = {}, y = {}, width = {}, height = {};
- tbo.getCoordsForCellItem(rowID, aTree.columns[0], "text",
- x, y, width, height);
- x = x.value + width.value / 2;
- y = y.value + height.value / 2;
+ var rect = tbo.getCoordsForCellItem(rowID, aTree.columns[0], "text");
+ var x = rect.x + rect.width / 2;
+ var y = rect.y + rect.height / 2;
// Simulate the click.
EventUtils.synthesizeMouse(aTree.body, x, y, aOptions || {},
aTree.ownerDocument.defaultView);
}
--- a/browser/components/preferences/cookies.js
+++ b/browser/components/preferences/cookies.js
@@ -33,17 +33,17 @@ var gCookiesWindow = {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.removeObserver(this, "cookie-changed");
os.removeObserver(this, "perm-changed");
},
_populateList: function (aInitialLoad) {
this._loadCookies();
- this._tree.treeBoxObject.view = this._view;
+ this._tree.view = this._view;
if (aInitialLoad)
this.sort("rawHost");
if (this._view.rowCount > 0)
this._tree.view.selection.select(0);
if (aInitialLoad) {
if ("arguments" in window &&
window.arguments[0] &&
@@ -785,17 +785,17 @@ var gCookiesWindow = {
// Clear the Tree Display
this._view._filtered = false;
this._view._rowCount = 0;
this._tree.treeBoxObject.rowCountChanged(0, -this._view._filterSet.length);
this._view._filterSet = [];
// Just reload the list to make sure deletions are respected
this._loadCookies();
- this._tree.treeBoxObject.view = this._view;
+ this._tree.view = this._view;
// Restore sort order
var sortby = this._lastSortProperty;
if (sortby == "") {
this._lastSortAscending = false;
this.sort("rawHost");
}
else {
--- a/browser/components/preferences/permissions.js
+++ b/browser/components/preferences/permissions.js
@@ -327,17 +327,17 @@ var gPermissionManager = {
while (enumerator.hasMoreElements()) {
var nextPermission = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
this._addPermissionToList(nextPermission);
}
this._view._rowCount = this._permissions.length;
// sort and display the table
- this._tree.treeBoxObject.view = this._view;
+ this._tree.view = this._view;
this.onPermissionSort("rawHost", false);
// disable "remove all" button if there are none
document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0;
},
_addPermissionToList: function (aPermission)
{
@@ -365,9 +365,8 @@ function setHost(aHost)
{
gPermissionManager.setHost(aHost);
}
function initWithParams(aParams)
{
gPermissionManager.init(aParams);
}
-
--- a/browser/components/preferences/tests/browser_bug705422.js
+++ b/browser/components/preferences/tests/browser_bug705422.js
@@ -77,34 +77,33 @@ function runTest(win, searchTerm, cookie
// "delete all cookies" should be enabled
isDisabled(win, false);
// select first cookie and delete
var tree = win.document.getElementById("cookiesList");
var deleteButton = win.document.getElementById("removeCookie");
- var x = {}, y = {}, width = {}, height = {};
- tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "cell", x, y, width, height);
- EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, {}, win);
+ var rect = tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "cell");
+ EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {}, win);
EventUtils.synthesizeMouseAtCenter(deleteButton, {}, win);
// count cookies should be matches-1
is(win.gCookiesWindow._view.rowCount, matches-1, "Deleted selected cookie");
// select two adjacent cells and delete
- EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, {}, win);
+ EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {}, win);
deleteButton = win.document.getElementById("removeCookies");
var eventObj = {};
if (navigator.platform.indexOf("Mac") >= 0)
eventObj.metaKey = true;
else
eventObj.ctrlKey = true;
- tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell", x, y, width, height);
- EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, eventObj, win);
+ rect = tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell");
+ EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, eventObj, win);
EventUtils.synthesizeMouseAtCenter(deleteButton, {}, win);
// count cookies should be matches-3
is(win.gCookiesWindow._view.rowCount, matches-3, "Deleted selected two adjacent cookies");
// "delete all cookies" should be enabled
isDisabled(win, false);
--- a/browser/components/preferences/translation.js
+++ b/browser/components/preferences/translation.js
@@ -15,17 +15,17 @@ XPCOMUtils.defineLazyGetter(this, "gLang
const kPermissionType = "translate";
const kLanguagesPref = "browser.translation.neverForLanguages";
function Tree(aId, aData)
{
this._data = aData;
this._tree = document.getElementById(aId);
- this._tree.treeBoxObject.view = this;
+ this._tree.view = this;
}
Tree.prototype = {
get boxObject() this._tree.treeBoxObject,
get isEmpty() !this._data.length,
get hasSelection() this.selection.count > 0,
getSelectedItems: function() {
let result = [];
--- a/browser/components/search/test/browser_405664.js
+++ b/browser/components/search/test/browser_405664.js
@@ -1,16 +1,16 @@
function test() {
var searchBar = BrowserSearch.searchBar;
ok(searchBar, "got search bar");
searchBar.focus();
var pbo = searchBar._popup.popupBoxObject;
- ok(pbo, "popup is nsIPopupBoxObject");
+ ok(pbo, "popup is PopupBoxObject");
EventUtils.synthesizeKey("VK_UP", { altKey: true });
is(pbo.popupState, "showing", "popup is opening after Alt+Up");
EventUtils.synthesizeKey("VK_ESCAPE", {});
is(pbo.popupState, "closed", "popup is closed after ESC");
EventUtils.synthesizeKey("VK_DOWN", { altKey: true });
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -139,34 +139,33 @@ function startNewSession() {
getBrowserWindow().BrowserHome();
}
function onListClick(aEvent) {
// don't react to right-clicks
if (aEvent.button == 2)
return;
- var row = {}, col = {};
- treeView.treeBox.getCellAt(aEvent.clientX, aEvent.clientY, row, col, {});
- if (col.value) {
+ var cell = treeView.treeBox.getCellAt(aEvent.clientX, aEvent.clientY);
+ if (cell.col) {
// Restore this specific tab in the same window for middle/double/accel clicking
// on a tab's title.
#ifdef XP_MACOSX
let accelKey = aEvent.metaKey;
#else
let accelKey = aEvent.ctrlKey;
#endif
if ((aEvent.button == 1 || aEvent.button == 0 && aEvent.detail == 2 || accelKey) &&
- col.value.id == "title" &&
- !treeView.isContainer(row.value)) {
- restoreSingleTab(row.value, aEvent.shiftKey);
+ cell.col.id == "title" &&
+ !treeView.isContainer(cell.row)) {
+ restoreSingleTab(cell.row, aEvent.shiftKey);
aEvent.stopPropagation();
}
- else if (col.value.id == "restore")
- toggleRowChecked(row.value);
+ else if (cell.col.id == "restore")
+ toggleRowChecked(cell.row);
}
}
function onListKeyDown(aEvent) {
switch (aEvent.keyCode)
{
case KeyEvent.DOM_VK_SPACE:
toggleRowChecked(document.getElementById("tabList").currentIndex);
--- a/browser/components/sessionstore/test/browser_590563.js
+++ b/browser/components/sessionstore/test/browser_590563.js
@@ -33,25 +33,23 @@ function test() {
});
}
function middleClickTest(win) {
let browser = win.gBrowser.selectedBrowser;
let tree = browser.contentDocument.getElementById("tabList");
is(tree.view.rowCount, 3, "There should be three items");
- let x = {}, y = {}, width = {}, height = {};
-
// click on the first tab item
- tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[1], "text", x, y, width, height);
- EventUtils.synthesizeMouse(tree.body, x.value, y.value, { button: 1 },
+ var rect = tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[1], "text");
+ EventUtils.synthesizeMouse(tree.body, rect.x, rect.y, { button: 1 },
browser.contentWindow);
// click on the second tab item
- tree.treeBoxObject.getCoordsForCellItem(2, tree.columns[1], "text", x, y, width, height);
- EventUtils.synthesizeMouse(tree.body, x.value, y.value, { button: 1 },
+ rect = tree.treeBoxObject.getCoordsForCellItem(2, tree.columns[1], "text");
+ EventUtils.synthesizeMouse(tree.body, rect.x, rect.y, { button: 1 },
browser.contentWindow);
is(win.gBrowser.tabs.length, 3,
"The total number of tabs should be 3 after restoring 2 tabs by middle click.");
is(win.gBrowser.visibleTabs.length, 3,
"The total number of visible tabs should be 3 after restoring 2 tabs by middle click");
}
--- a/browser/devtools/shared/widgets/FastListWidget.js
+++ b/browser/devtools/shared/widgets/FastListWidget.js
@@ -190,17 +190,17 @@ FastListWidget.prototype = {
* The element to make visible.
*/
ensureElementIsVisible: function(element) {
if (!element) {
return;
}
// Ensure the element is visible but not scrolled horizontally.
- let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+ let boxObject = this._list.boxObject;
boxObject.ensureElementIsVisible(element);
boxObject.scrollBy(-this._list.clientWidth, 0);
},
/**
* Sets the text displayed in this container when empty.
* @param string aValue
*/
--- a/browser/devtools/shared/widgets/SideMenuWidget.jsm
+++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm
@@ -209,17 +209,17 @@ SideMenuWidget.prototype = {
* The element to make visible.
*/
ensureElementIsVisible: function(aElement) {
if (!aElement) {
return;
}
// Ensure the element is visible but not scrolled horizontally.
- let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+ let boxObject = this._list.boxObject;
boxObject.ensureElementIsVisible(aElement);
boxObject.scrollBy(-this._list.clientWidth, 0);
},
/**
* Shows all the groups, even the ones with no visible children.
*/
showEmptyGroups: function() {
--- a/browser/devtools/shared/widgets/SimpleListWidget.jsm
+++ b/browser/devtools/shared/widgets/SimpleListWidget.jsm
@@ -166,17 +166,17 @@ SimpleListWidget.prototype = {
* The element to make visible.
*/
ensureElementIsVisible: function(aElement) {
if (!aElement) {
return;
}
// Ensure the element is visible but not scrolled horizontally.
- let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+ let boxObject = this._list.boxObject;
boxObject.ensureElementIsVisible(aElement);
boxObject.scrollBy(-this._list.clientWidth, 0);
},
/**
* Sets the text displayed permanently in this container as a header.
* @param string aValue
*/
--- a/browser/devtools/shared/widgets/VariablesView.jsm
+++ b/browser/devtools/shared/widgets/VariablesView.jsm
@@ -982,17 +982,17 @@ VariablesView.prototype = {
this._parent.removeAttribute("actions-first");
}
},
/**
* Gets the parent node holding this view.
* @return nsIDOMNode
*/
- get boxObject() this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject),
+ get boxObject() this._list.boxObject,
/**
* Gets the parent node holding this view.
* @return nsIDOMNode
*/
get parentNode() this._parent,
/**
--- a/browser/metro/base/content/bindings/bindings.xml
+++ b/browser/metro/base/content/bindings/bindings.xml
@@ -20,24 +20,21 @@
<handlers>
<handler event="scroll">
<![CDATA[
// if there no more items to insert, just return early
if (this._items.length == 0)
return;
if (this._contentScrollHeight == -1) {
- let scrollheight = {};
- this.scrollBoxObject.getScrolledSize({}, scrollheight);
- this._contentScrollHeight = scrollheight.value;
+ this._contentScrollHeight = this.scrollBoxObject.scrolledHeight;
}
- let y = {};
- this.scrollBoxObject.getPosition({}, y);
- let scrollRatio = (y.value + this._childrenHeight) / this._contentScrollHeight;
+ let y = this.scrollBoxObject.positionY;
+ let scrollRatio = (y + this._childrenHeight) / this._contentScrollHeight;
// If we're scrolled 80% to the bottom of the list, append the next
// set of items
if (scrollRatio > 0.8)
this._insertItems();
]]>
</handler>
</handlers>
--- a/browser/metro/base/content/input.js
+++ b/browser/metro/base/content/input.js
@@ -470,27 +470,27 @@ var ScrollUtils = {
// if element is content or the startui page, get the browser scroll interface
if (elem.ownerDocument == Browser.selectedBrowser.contentDocument) {
elem = Browser.selectedBrowser;
}
for (; elem; elem = elem.parentNode) {
try {
if (elem.anonScrollBox) {
scrollbox = elem.anonScrollBox;
- qinterface = scrollbox.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+ qinterface = scrollbox.boxObject;
} else if (elem.scrollBoxObject) {
scrollbox = elem;
qinterface = elem.scrollBoxObject;
break;
} else if (elem.customDragger) {
scrollbox = elem;
break;
} else if (elem.boxObject) {
let qi = (elem._cachedSBO) ? elem._cachedSBO
- : elem.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+ : elem.boxObject;
if (qi) {
scrollbox = elem;
scrollbox._cachedSBO = qinterface = qi;
break;
}
}
} catch (e) { /* we aren't here to deal with your exceptions, we'll just keep
traversing until we find something more well-behaved, as we
@@ -507,50 +507,43 @@ var ScrollUtils = {
/**
* The default dragger object used by TouchModule when dragging a scrollable
* element that provides no customDragger. Simply performs the expected
* regular scrollBy calls on the scroller.
*/
_defaultDragger: {
isDraggable: function isDraggable(target, scroller) {
- let sX = {}, sY = {},
- pX = {}, pY = {};
- scroller.getPosition(pX, pY);
- scroller.getScrolledSize(sX, sY);
let rect = target.getBoundingClientRect();
- return { x: (sX.value > rect.width || pX.value != 0),
- y: (sY.value > rect.height || pY.value != 0) };
+ return { x: (scroller.scrolledWidth > rect.width || scroller.positionX != 0),
+ y: (scroller.scrolledHeight > rect.height || scroller.positionY != 0) };
},
dragStart: function dragStart(cx, cy, target, scroller) {
scroller.element.addEventListener("PanBegin", this._showScrollbars, false);
},
dragStop: function dragStop(dx, dy, scroller) {
scroller.element.removeEventListener("PanBegin", this._showScrollbars, false);
return this.dragMove(dx, dy, scroller);
},
dragMove: function dragMove(dx, dy, scroller) {
- if (scroller.getPosition) {
try {
- let oldX = {}, oldY = {};
- scroller.getPosition(oldX, oldY);
+ let oldX = scroller.positionX,
+ oldY = scroller.positionY;
scroller.scrollBy(dx, dy);
- let newX = {}, newY = {};
- scroller.getPosition(newX, newY);
+ let newX = scroller.positionX,
+ newY = scroller.positionY;
- return (newX.value != oldX.value) || (newY.value != oldY.value);
+ return (newX != oldX) || (newY != oldY);
} catch (e) { /* we have no time for whiny scrollers! */ }
- }
-
return false;
},
_showScrollbars: function _showScrollbars(aEvent) {
let scrollbox = aEvent.target;
scrollbox.setAttribute("panning", "true");
let hideScrollbars = function() {
--- a/browser/modules/UITour.jsm
+++ b/browser/modules/UITour.jsm
@@ -1064,17 +1064,17 @@ this.UITour = {
function openMenuButton(aMenuBtn) {
if (!aMenuBtn || !aMenuBtn.boxObject || aMenuBtn.open) {
if (aOpenCallback)
aOpenCallback();
return;
}
if (aOpenCallback)
aMenuBtn.addEventListener("popupshown", onPopupShown);
- aMenuBtn.boxObject.QueryInterface(Ci.nsIMenuBoxObject).openMenu(true);
+ aMenuBtn.boxObject.openMenu(true);
}
function onPopupShown(event) {
this.removeEventListener("popupshown", onPopupShown);
aOpenCallback(event);
}
if (aMenuName == "appMenu") {
aWindow.PanelUI.panel.setAttribute("noautohide", "true");
@@ -1096,17 +1096,17 @@ this.UITour = {
openMenuButton(target.node);
}).catch(Cu.reportError);
}
},
hideMenu: function(aWindow, aMenuName) {
function closeMenuButton(aMenuBtn) {
if (aMenuBtn && aMenuBtn.boxObject)
- aMenuBtn.boxObject.QueryInterface(Ci.nsIMenuBoxObject).openMenu(false);
+ aMenuBtn.boxObject.openMenu(false);
}
if (aMenuName == "appMenu") {
aWindow.PanelUI.panel.removeAttribute("noautohide");
aWindow.PanelUI.hide();
this.recreatePopup(aWindow.PanelUI.panel);
} else if (aMenuName == "bookmarks") {
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
deleted file mode 100644
--- a/build/autoconf/ccache.m4
+++ /dev/null
@@ -1,36 +0,0 @@
-dnl This Source Code Form is subject to the terms of the Mozilla Public
-dnl License, v. 2.0. If a copy of the MPL was not distributed with this
-dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-dnl ======================================================
-dnl = Enable compiling with ccache
-dnl ======================================================
-AC_DEFUN([MOZ_CHECK_CCACHE],
-[
-MOZ_ARG_WITH_STRING(ccache,
-[ --with-ccache[=path/to/ccache]
- Enable compiling with ccache],
- CCACHE=$withval, CCACHE="no")
-
-if test "$CCACHE" != "no"; then
- if test -z "$CCACHE" -o "$CCACHE" = "yes"; then
- CCACHE=
- else
- if test ! -e "$CCACHE"; then
- AC_MSG_ERROR([$CCACHE not found])
- fi
- fi
- MOZ_PATH_PROGS(CCACHE, $CCACHE ccache)
- if test -z "$CCACHE" -o "$CCACHE" = ":"; then
- AC_MSG_ERROR([ccache not found])
- elif test -x "$CCACHE"; then
- CC="$CCACHE $CC"
- CXX="$CCACHE $CXX"
- MOZ_USING_CCACHE=1
- else
- AC_MSG_ERROR([$CCACHE is not executable])
- fi
-fi
-
-AC_SUBST(MOZ_USING_CCACHE)
-])
--- a/build/autoconf/nspr-build.m4
+++ b/build/autoconf/nspr-build.m4
@@ -192,16 +192,21 @@ AC_SUBST(NSPR_PKGCONF_CHECK)
fi # _IS_OUTER_CONFIGURE
])
AC_DEFUN([MOZ_SUBCONFIGURE_NSPR], [
if test -z "$MOZ_NATIVE_NSPR"; then
ac_configure_args="$_SUBDIR_CONFIG_ARGS --with-dist-prefix=$MOZ_BUILD_ROOT/dist --with-mozilla"
+ if test -n "$MOZ_USING_CCACHE"; then
+ # Avoid double prepending ccache by omitting --with-ccache in building NSPR.
+ ac_configure_args="`echo $ac_configure_args | sed -e 's/--with-ccache[[^ ]]*//'`"
+ fi
+
if test -z "$MOZ_DEBUG"; then
ac_configure_args="$ac_configure_args --disable-debug"
else
ac_configure_args="$ac_configure_args --enable-debug"
if test -n "$MOZ_NO_DEBUG_RTL"; then
ac_configure_args="$ac_configure_args --disable-debug-rtl"
fi
fi
--- a/build/autoconf/wrapper.m4
+++ b/build/autoconf/wrapper.m4
@@ -7,16 +7,46 @@ dnl = Enable compiling with various comp
dnl =======================================================================
AC_DEFUN([MOZ_CHECK_COMPILER_WRAPPER],
[
MOZ_ARG_WITH_STRING(compiler_wrapper,
[ --with-compiler-wrapper[=path/to/wrapper]
Enable compiling with wrappers such as distcc and ccache],
COMPILER_WRAPPER=$withval, COMPILER_WRAPPER="no")
+MOZ_ARG_WITH_STRING(ccache,
+[ --with-ccache[=path/to/ccache]
+ Enable compiling with ccache],
+ CCACHE=$withval, CCACHE="no")
+
+if test "$CCACHE" != "no"; then
+ if test -z "$CCACHE" -o "$CCACHE" = "yes"; then
+ CCACHE=
+ else
+ if test ! -e "$CCACHE"; then
+ AC_MSG_ERROR([$CCACHE not found])
+ fi
+ fi
+ MOZ_PATH_PROGS(CCACHE, $CCACHE ccache)
+ if test -z "$CCACHE" -o "$CCACHE" = ":"; then
+ AC_MSG_ERROR([ccache not found])
+ elif test -x "$CCACHE"; then
+ if test "$COMPILER_WRAPPER" != "no"; then
+ COMPILER_WRAPPER="$CCACHE $COMPILER_WRAPPER"
+ else
+ COMPILER_WRAPPER="$CCACHE"
+ fi
+ MOZ_USING_CCACHE=1
+ else
+ AC_MSG_ERROR([$CCACHE is not executable])
+ fi
+fi
+
+AC_SUBST(MOZ_USING_CCACHE)
+
if test "$COMPILER_WRAPPER" != "no"; then
case "$target" in
*-mingw*)
dnl When giving a windows path with backslashes, js/src/configure
dnl fails because of double wrapping because the test further below
dnl doesn't work with backslashes. While fixing that test to work
dnl might seem better, a lot of the make build backend actually
dnl doesn't like backslashes, so normalize windows paths to use
--- a/client.mk
+++ b/client.mk
@@ -86,16 +86,19 @@ ifneq (,$(findstring mingw,$(CONFIG_GUES
# check for CRLF line endings
ifneq (0,$(shell $(PERL) -e 'binmode(STDIN); while (<STDIN>) { if (/\r/) { print "1"; exit } } print "0"' < $(TOPSRCDIR)/client.mk))
$(error This source tree appears to have Windows-style line endings. To \
convert it to Unix-style line endings, check \
"https://developer.mozilla.org/en-US/docs/Developer_Guide/Mozilla_build_FAQ\#Win32-specific_questions" \
for a workaround of this issue.)
endif
+
+# Set this for baseconfig.mk
+HOST_OS_ARCH=WINNT
endif
####################################
# Load mozconfig Options
# See build pages, http://www.mozilla.org/build/ for how to set up mozconfig.
define CR
@@ -162,16 +165,19 @@ OBJDIR_TARGETS = install export libs cle
#######################################################################
# Rules
# The default rule is build
build::
$(MAKE) -f $(TOPSRCDIR)/client.mk $(if $(MOZ_PGO),profiledbuild,realbuild) CREATE_MOZCONFIG_JSON=
+# Include baseconfig.mk for its $(MAKE) validation.
+include $(TOPSRCDIR)/config/baseconfig.mk
+
# Define mkdir
include $(TOPSRCDIR)/config/makefiles/makeutils.mk
include $(TOPSRCDIR)/config/makefiles/autotargets.mk
# Create a makefile containing the mk_add_options values from mozconfig,
# but only do so when OBJDIR is defined (see further above).
ifdef MOZ_BUILD_PROJECTS
ifdef MOZ_CURRENT_PROJECT
--- a/configure.in
+++ b/configure.in
@@ -7322,18 +7322,16 @@ dnl ====================================
MOZ_ARG_ENABLE_BOOL(gczeal,
[ --enable-gczeal Enable zealous JavaScript GCing],
JS_GC_ZEAL=1,
JS_GC_ZEAL= )
if test -n "$JS_GC_ZEAL" -o -n "$MOZ_DEBUG"; then
AC_DEFINE(JS_GC_ZEAL)
fi
-MOZ_CHECK_CCACHE
-
dnl ========================================================
dnl = Enable static checking using gcc-dehydra
dnl ========================================================
MOZ_ARG_WITH_STRING(static-checking,
[ --with-static-checking=path/to/gcc_dehydra.so
Enable static checking of code using GCC-dehydra],
DEHYDRA_PATH=$withval,
@@ -9187,21 +9185,16 @@ if test -n "$_subconfigure_subdir"; then
srcdir="$_save_srcdir"
fi
# No need to run subconfigures when building with LIBXUL_SDK_DIR
if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
export WRAP_LDFLAGS
-if test -n "$MOZ_USING_CCACHE"; then
- # Avoid double prepending ccache by omitting --with-ccache in building NSPR.
- _SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--with-ccache[[^ ]]*//'`"
-fi
-
MOZ_SUBCONFIGURE_NSPR()
dnl ========================================================
dnl = Setup a nice relatively clean build environment for
dnl = sub-configures.
dnl ========================================================
CC="$_SUBDIR_CC"
CXX="$_SUBDIR_CXX"
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -128,18 +128,18 @@ class AnimationPlayer;
class Link;
class UndoManager;
class DOMRect;
class DOMRectList;
class DestinationInsertionPointList;
// IID for the dom::Element interface
#define NS_ELEMENT_IID \
-{ 0xb0135f9d, 0xa476, 0x4711, \
- { 0x8b, 0xb9, 0xca, 0xe5, 0x2a, 0x05, 0xf9, 0xbe } }
+{ 0xaa79cb98, 0xc785, 0x44c5, \
+ { 0x80, 0x80, 0x2e, 0x5f, 0x0c, 0xa5, 0xbd, 0x63 } }
class Element : public FragmentOrElement
{
public:
#ifdef MOZILLA_INTERNAL_API
explicit Element(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) :
FragmentOrElement(aNodeInfo),
mState(NS_EVENT_STATE_MOZ_READONLY)
@@ -669,16 +669,20 @@ public:
}
void SetPointerCapture(int32_t aPointerId, ErrorResult& aError)
{
bool activeState = false;
if (!nsIPresShell::GetPointerInfo(aPointerId, activeState)) {
aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
return;
}
+ if (!IsInDoc()) {
+ aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
if (!activeState) {
return;
}
nsIPresShell::SetPointerCapturingContent(aPointerId, this);
}
void ReleasePointerCapture(int32_t aPointerId, ErrorResult& aError)
{
bool activeState = false;
--- a/content/base/public/File.h
+++ b/content/base/public/File.h
@@ -86,21 +86,27 @@ public:
static already_AddRefed<File>
Create(nsISupports* aParent, const nsAString& aContentType,
uint64_t aLength);
static already_AddRefed<File>
Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
uint64_t aLength);
+ // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
+ // freed by moz_free so it must be allocated by moz_malloc or something
+ // compatible with it.
static already_AddRefed<File>
CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
const nsAString& aName, const nsAString& aContentType,
uint64_t aLastModifiedDate);
+ // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
+ // freed by moz_free so it must be allocated by moz_malloc or something
+ // compatible with it.
static already_AddRefed<File>
CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
const nsAString& aContentType);
static already_AddRefed<File>
CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
uint64_t aStartPos, uint64_t aLength,
const nsAString& aContentType);
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -33,17 +33,16 @@ class nsIDocShell;
class nsDocShell;
class nsDOMNavigationTiming;
class nsFrameLoader;
class nsHTMLCSSStyleSheet;
class nsHTMLDocument;
class nsHTMLStyleSheet;
class nsIAtom;
class nsIBFCacheEntry;
-class nsIBoxObject;
class nsIChannel;
class nsIContent;
class nsIContentSink;
class nsIDocShell;
class nsIDocumentEncoder;
class nsIDocumentObserver;
class nsIDOMDocument;
class nsIDOMDocumentFragment;
@@ -90,16 +89,17 @@ class SVGAttrAnimationRuleProcessor;
namespace css {
class Loader;
class ImageLoader;
} // namespace css
namespace dom {
class AnimationTimeline;
class Attr;
+class BoxObject;
class CDATASection;
class Comment;
struct CustomElementDefinition;
class DocumentFragment;
class DocumentType;
class DOMImplementation;
class DOMStringList;
class Element;
@@ -1495,17 +1495,17 @@ public:
* @param aElement canonical nsIContent pointer of the box object's element
*/
virtual void ClearBoxObjectFor(nsIContent *aContent) = 0;
/**
* Get the box object for an element. This is not exposed through a
* scriptable interface except for XUL documents.
*/
- virtual already_AddRefed<nsIBoxObject>
+ virtual already_AddRefed<mozilla::dom::BoxObject>
GetBoxObjectFor(mozilla::dom::Element* aElement,
mozilla::ErrorResult& aRv) = 0;
/**
* Get the compatibility mode for this document
*/
nsCompatibility GetCompatibilityMode() const {
return mCompatMode;
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -243,18 +243,18 @@ private:
// Categories of node properties
// 0 is global.
#define DOM_USER_DATA 1
#define SMIL_MAPPED_ATTR_ANIMVAL 2
// IID for the nsINode interface
#define NS_INODE_IID \
-{ 0x3a60353e, 0x04e5, 0x49ca, \
- { 0x84, 0x1c, 0x59, 0xc6, 0xde, 0xe6, 0x36, 0xcc } }
+{ 0x8deda3f4, 0x0f45, 0x497a, \
+ { 0x89, 0x7c, 0xe6, 0x09, 0x12, 0x8a, 0xad, 0xd8 } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
* nsIContent and nsIDocument share. An instance of this interface has a list
* of nsIContent children and provides access to them.
*/
class nsINode : public mozilla::dom::EventTarget
{
--- a/content/base/src/ImportManager.cpp
+++ b/content/base/src/ImportManager.cpp
@@ -479,17 +479,17 @@ ImportLoader::Open()
return;
}
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
rv = secMan->CheckLoadURIWithPrincipal(principal, mURI,
nsIScriptSecurityManager::STANDARD);
NS_ENSURE_SUCCESS_VOID(rv);
- nsCOMPtr<nsILoadGroup> loadGroup = mImportParent->GetDocumentLoadGroup();
+ nsCOMPtr<nsILoadGroup> loadGroup = master->GetDocumentLoadGroup();
nsCOMPtr<nsIChannelPolicy> channelPolicy;
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS_VOID(rv);
if (csp) {
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
channelPolicy->SetContentSecurityPolicy(csp);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -215,16 +215,17 @@
#include "nsIDocumentActivity.h"
#include "nsIStructuredCloneContainer.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
#include "mozilla/dom/DOMStringList.h"
#include "nsWindowMemoryReporter.h"
#include "nsLocation.h"
#include "mozilla/dom/FontFaceSet.h"
+#include "mozilla/dom/BoxObject.h"
#ifdef MOZ_MEDIA_NAVIGATOR
#include "mozilla/MediaManager.h"
#endif // MOZ_MEDIA_NAVIGATOR
#ifdef MOZ_WEBRTC
#include "IPeerConnection.h"
#endif // MOZ_WEBRTC
@@ -6942,17 +6943,17 @@ nsDocument::DoNotifyPossibleTitleChange(
}
// Fire a DOM event for the title change.
nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
NS_LITERAL_STRING("DOMTitleChanged"),
true, true);
}
-already_AddRefed<nsIBoxObject>
+already_AddRefed<BoxObject>
nsDocument::GetBoxObjectFor(Element* aElement, ErrorResult& aRv)
{
if (!aElement) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsIDocument* doc = aElement->OwnerDoc();
@@ -6969,17 +6970,17 @@ nsDocument::GetBoxObjectFor(Element* aEl
"UseOfGetBoxObjectForWarning");
}
if (!mBoxObjectTable) {
mBoxObjectTable = new nsInterfaceHashtable<nsPtrHashKey<nsIContent>, nsPIBoxObject>(6);
} else {
nsCOMPtr<nsPIBoxObject> boxObject = mBoxObjectTable->Get(aElement);
if (boxObject) {
- return boxObject.forget();
+ return boxObject.forget().downcast<BoxObject>();
}
}
int32_t namespaceID;
nsCOMPtr<nsIAtom> tag = BindingManager()->ResolveTag(aElement, &namespaceID);
nsAutoCString contractID("@mozilla.org/layout/xul-boxobject");
if (namespaceID == kNameSpaceID_XUL) {
@@ -7010,17 +7011,17 @@ nsDocument::GetBoxObjectFor(Element* aEl
}
boxObject->Init(aElement);
if (mBoxObjectTable) {
mBoxObjectTable->Put(aElement, boxObject.get());
}
- return boxObject.forget();
+ return boxObject.forget().downcast<BoxObject>();
}
void
nsDocument::ClearBoxObjectFor(nsIContent* aContent)
{
if (mBoxObjectTable) {
nsPIBoxObject *boxObject = mBoxObjectTable->GetWeak(aContent);
if (boxObject) {
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -25,18 +25,16 @@
#include "nsStubDocumentObserver.h"
#include "nsIScriptGlobalObject.h"
#include "nsIContent.h"
#include "nsIPrincipal.h"
#include "nsIParser.h"
#include "nsBindingManager.h"
#include "nsInterfaceHashtable.h"
#include "nsJSThingHashtable.h"
-#include "nsIBoxObject.h"
-#include "nsPIBoxObject.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIURI.h"
#include "nsScriptLoader.h"
#include "nsIRadioGroupContainer.h"
#include "nsILayoutHistoryState.h"
#include "nsIRequest.h"
#include "nsILoadGroup.h"
#include "nsTObserverArray.h"
@@ -90,20 +88,22 @@ class nsChildContentList;
class nsHTMLStyleSheet;
class nsHTMLCSSStyleSheet;
class nsDOMNavigationTiming;
class nsWindowSizes;
class nsHtml5TreeOpExecutor;
class nsDocumentOnStack;
class nsPointerLockPermissionRequest;
class nsISecurityConsoleMessage;
+class nsPIBoxObject;
namespace mozilla {
class EventChainPreVisitor;
namespace dom {
+class BoxObject;
class UndoManager;
struct LifecycleCallbacks;
class CallbackFunction;
}
}
/**
* Right now our identifier map entries contain information for 'name'
@@ -997,18 +997,20 @@ public:
virtual void BlockOnload();
virtual void UnblockOnload(bool aFireSync);
virtual void AddStyleRelevantLink(mozilla::dom::Link* aLink);
virtual void ForgetLink(mozilla::dom::Link* aLink);
void ClearBoxObjectFor(nsIContent* aContent);
- already_AddRefed<nsIBoxObject> GetBoxObjectFor(mozilla::dom::Element* aElement,
- mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
+
+ virtual already_AddRefed<mozilla::dom::BoxObject>
+ GetBoxObjectFor(mozilla::dom::Element* aElement,
+ mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
virtual Element*
GetAnonymousElementByAttribute(nsIContent* aElement,
nsIAtom* aAttrName,
const nsAString& aAttrValue) const;
virtual Element* ElementFromPointHelper(float aX, float aY,
bool aIgnoreRootScrollFrame,
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -491,16 +491,17 @@ GK_ATOM(itemref, "itemref")
GK_ATOM(itemscope, "itemscope")
GK_ATOM(itemtype, "itemtype")
GK_ATOM(kbd, "kbd")
GK_ATOM(noautofocus, "noautofocus")
GK_ATOM(keepcurrentinview, "keepcurrentinview")
GK_ATOM(keepobjectsalive, "keepobjectsalive")
GK_ATOM(key, "key")
GK_ATOM(keycode, "keycode")
+GK_ATOM(keyschange, "keyschange")
GK_ATOM(keydown, "keydown")
GK_ATOM(keygen, "keygen")
GK_ATOM(keypress, "keypress")
GK_ATOM(keyset, "keyset")
GK_ATOM(keysystem, "keysystem")
GK_ATOM(keytext, "keytext")
GK_ATOM(keyup, "keyup")
GK_ATOM(kind, "kind")
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -1243,17 +1243,17 @@ nsScriptLoader::ReadyToExecuteScripts()
nsScriptLoader* ancestor = doc->ScriptLoader();
if (!ancestor->SelfReadyToExecuteScripts() &&
ancestor->AddPendingChildLoader(this)) {
AddExecuteBlocker();
return false;
}
}
- if (!mDocument->IsMasterDocument()) {
+ if (mDocument && !mDocument->IsMasterDocument()) {
nsRefPtr<ImportManager> im = mDocument->ImportManager();
nsRefPtr<ImportLoader> loader = im->Find(mDocument);
MOZ_ASSERT(loader, "How can we have an import document without a loader?");
// The referring link that counts in the execution order calculation
// (in spec: flagged as branch)
nsCOMPtr<nsINode> referrer = loader->GetMainReferrer();
MOZ_ASSERT(referrer, "There has to be a main referring link for each imports");
--- a/content/base/test/test_bug527896.html
+++ b/content/base/test/test_bug527896.html
@@ -17,18 +17,16 @@ https://bugzilla.mozilla.org/show_bug.cg
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 527896 **/
SimpleTest.waitForExplicitFinish();
-SimpleTest.expectAssertions(1);
-
var docWrittenSrcExecuted = false;
var scriptInsertedSrcExecuted = false;
// the iframe test runs with the HTML5 parser
var iframe = document.getElementsByTagName('iframe')[0];
iframe.contentWindow.document.open();
iframe.contentWindow.document.write("<!DOCTYPE html>");
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1159,17 +1159,18 @@ nsresult HTMLMediaElement::LoadResource(
nsRefPtr<MediaSourceDecoder> decoder = new MediaSourceDecoder(this);
if (!source->Attach(decoder)) {
// TODO: Handle failure: run "If the media data cannot be fetched at
// all, due to network errors, causing the user agent to give up
// trying to fetch the resource" section of resource fetch algorithm.
return NS_ERROR_FAILURE;
}
mMediaSource = source.forget();
- nsRefPtr<MediaResource> resource = MediaSourceDecoder::CreateResource();
+ nsRefPtr<MediaResource> resource =
+ MediaSourceDecoder::CreateResource(mMediaSource->GetPrincipal());
return FinishDecoderSetup(decoder, resource, nullptr, nullptr);
}
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
// check for a Content Security Policy to pass down to the channel
// created to load the media content
nsCOMPtr<nsIChannelPolicy> channelPolicy;
--- a/content/html/content/test/forms/test_meter_element.html
+++ b/content/html/content/test/forms/test_meter_element.html
@@ -16,22 +16,16 @@ https://bugzilla.mozilla.org/show_bug.cg
<div id="content" style="visibility: hidden;">
<form id='f' method='get' target='submit_frame' action='foo'>
<meter id='m' value=0.5></meter>
</form>
</div>
<pre id="test">
<script type="application/javascript">
-if (navigator.platform.startsWith("Win")) {
- SimpleTest.expectAssertions(0, 1);
-} else {
- SimpleTest.expectAssertions(1);
-}
-
/** Test for <meter> **/
function checkFormIDLAttribute(aElement)
{
is('form' in aElement, false, "<meter> shouldn't have a form attribute");
}
function checkAttribute(aElement, aAttribute, aNewValue, aExpectedValueForIDL)
--- a/content/html/content/test/test_bug242709.html
+++ b/content/html/content/test/test_bug242709.html
@@ -12,18 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=242709">Mozilla Bug 242709</a>
<p id="display"></p>
<div id="content">
<iframe src="bug242709_iframe.html" id="a"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
-SimpleTest.expectAssertions(1);
-
/** Test for Bug 242709 **/
SimpleTest.waitForExplicitFinish();
var submitted = function() {
ok(true, "Disabling button after form submission doesn't prevent submitting");
SimpleTest.finish();
}
--- a/content/html/content/test/test_bug277890.html
+++ b/content/html/content/test/test_bug277890.html
@@ -12,18 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=277890">Mozilla Bug 277890</a>
<p id="display"></p>
<div id="content">
<iframe src="bug277890_iframe.html" id="a"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
-SimpleTest.expectAssertions(1);
-
/** Test for Bug 277890 **/
SimpleTest.waitForExplicitFinish();
var submitted = function() {
ok(true, "Disabling button after form submission doesn't prevent submitting");
SimpleTest.finish();
}
--- a/content/html/content/test/test_bug523771.html
+++ b/content/html/content/test/test_bug523771.html
@@ -15,22 +15,16 @@ https://bugzilla.mozilla.org/show_bug.cg
<form action="form_submit_server.sjs" target="target_iframe" id="form"
method="POST" enctype="multipart/form-data">
<input id=singleFile name=singleFile type=file>
<input id=multiFile name=multiFile type=file multiple>
</form>
<pre id="test">
<script class="testbody" type="text/javascript">
-if (navigator.platform.startsWith("Win")) {
- SimpleTest.expectAssertions(0, 1);
-} else {
- SimpleTest.expectAssertions(1);
-}
-
var filesToKill = [];
singleFileInput = document.getElementById('singleFile');
multiFileInput = document.getElementById('multiFile');
var input1File = { name: "523771_file1", type: "", body: "file1 contents"};
var input2Files =
[{ name: "523771_file2", type: "", body: "second file contents" },
{ name: "523771_file3.txt", type: "text/plain", body: "123456" },
{ name: "523771_file4.html", type: "text/html", body: "<html>content</html>" }
--- a/content/html/content/test/test_iframe_sandbox_inheritance.html
+++ b/content/html/content/test/test_iframe_sandbox_inheritance.html
@@ -9,19 +9,16 @@ Implement HTML5 sandbox attribute for IF
<title>Test for Bug 341604</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<script type="application/javascript">
/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
/** Inheritance Tests **/
-// Assertion failure in docshell/shistory/src/nsSHEntry.cpp (currently line 625).
-// Bug 901876 raised.
-SimpleTest.expectAssertions(1);
SimpleTest.waitForExplicitFinish();
// A postMessage handler that is used by sandboxed iframes without
// 'allow-same-origin' to communicate pass/fail back to this main page.
// It expects to be called with an object like {ok: true/false, desc:
// <description of the test> which it then forwards to ok().
window.addEventListener("message", receiveMessage, false);
--- a/content/html/content/test/test_iframe_sandbox_navigation.html
+++ b/content/html/content/test/test_iframe_sandbox_navigation.html
@@ -10,17 +10,16 @@ Implement HTML5 sandbox attribute for IF
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<script type="application/javascript">
/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
/** Navigation tests Part 1**/
-SimpleTest.expectAssertions(1, 3);
SimpleTest.waitForExplicitFinish();
// a postMessage handler that is used by sandboxed iframes without
// 'allow-same-origin'/other windows to communicate pass/fail back to this main page.
// it expects to be called with an object like {ok: true/false, desc:
// <description of the test> which it then forwards to ok()
window.addEventListener("message", receiveMessage, false);
var testPassesReceived = 0;
--- a/content/html/document/test/test_bug448564.html
+++ b/content/html/document/test/test_bug448564.html
@@ -15,18 +15,16 @@ https://bugzilla.mozilla.org/show_bug.cg
<iframe src="bug448564-iframe-2.html"></iframe>
<iframe src="bug448564-iframe-3.html"></iframe>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
-SimpleTest.expectAssertions(3);
-
/** Test for Bug 448564 **/
/**
* The three iframes are going to be loaded with some dirty constructed forms.
* Each of them will be submitted before the load event and a SJS will replace
* the frame content with the query string.
* Then, on the load event, our test file will check the content of each iframes
* and check if the query string were correctly formatted (implying that all
--- a/content/html/document/test/test_bug478251.html
+++ b/content/html/document/test/test_bug478251.html
@@ -12,18 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=478251">Mozilla Bug 478251</a>
<p id="display"><iframe id="t"></iframe></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
-SimpleTest.expectAssertions(9, 10);
-
/** Test for Bug 478251 **/
var doc = $("t").contentDocument;
doc.open();
doc.write();
doc.close();
is(doc.documentElement.textContent, "", "Writing || failed");
doc.open();
--- a/content/media/eme/CDMCallbackProxy.cpp
+++ b/content/media/eme/CDMCallbackProxy.cpp
@@ -267,28 +267,48 @@ CDMCallbackProxy::SessionError(const nsC
}
void
CDMCallbackProxy::KeyIdUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId)
{
MOZ_ASSERT(mProxy->IsOnGMPThread());
- CDMCaps::AutoLock caps(mProxy->Capabilites());
- caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+ bool keysChange = false;
+ {
+ CDMCaps::AutoLock caps(mProxy->Capabilites());
+ keysChange = caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+ }
+ if (keysChange) {
+ nsRefPtr<nsIRunnable> task;
+ task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
+ &CDMProxy::OnKeysChange,
+ NS_ConvertUTF8toUTF16(aSessionId));
+ NS_DispatchToMainThread(task);
+ }
}
void
CDMCallbackProxy::KeyIdNotUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId)
{
MOZ_ASSERT(mProxy->IsOnGMPThread());
- CDMCaps::AutoLock caps(mProxy->Capabilites());
- caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+ bool keysChange = false;
+ {
+ CDMCaps::AutoLock caps(mProxy->Capabilites());
+ keysChange = caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+ }
+ if (keysChange) {
+ nsRefPtr<nsIRunnable> task;
+ task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
+ &CDMProxy::OnKeysChange,
+ NS_ConvertUTF8toUTF16(aSessionId));
+ NS_DispatchToMainThread(task);
+ }
}
void
CDMCallbackProxy::SetCaps(uint64_t aCaps)
{
MOZ_ASSERT(mProxy->IsOnGMPThread());
CDMCaps::AutoLock caps(mProxy->Capabilites());
--- a/content/media/eme/CDMCaps.cpp
+++ b/content/media/eme/CDMCaps.cpp
@@ -83,53 +83,63 @@ CDMCaps::AutoLock::IsKeyUsable(const Cen
for (size_t i = 0; i < keys.Length(); i++) {
if (keys[i].mId == aKeyId) {
return true;
}
}
return false;
}
-void
+bool
CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
const nsString& aSessionId)
{
mData.mMonitor.AssertCurrentThreadOwns();
- mData.mUsableKeyIds.AppendElement(UsableKey(aKeyId, aSessionId));
+ UsableKey key(aKeyId, aSessionId);
+ if (mData.mUsableKeyIds.Contains(key)) {
+ return false;
+ }
+ mData.mUsableKeyIds.AppendElement(key);
auto& waiters = mData.mWaitForKeys;
size_t i = 0;
while (i < waiters.Length()) {
auto& w = waiters[i];
if (w.mKeyId == aKeyId) {
if (waiters[i].mTarget) {
EME_LOG("SetKeyUsable() notified waiter.");
w.mTarget->Dispatch(w.mContinuation, NS_DISPATCH_NORMAL);
} else {
w.mContinuation->Run();
}
waiters.RemoveElementAt(i);
} else {
i++;
}
}
+ return true;
}
-void
+bool
CDMCaps::AutoLock::SetKeyUnusable(const CencKeyId& aKeyId,
const nsString& aSessionId)
{
mData.mMonitor.AssertCurrentThreadOwns();
+ UsableKey key(aKeyId, aSessionId);
+ if (!mData.mUsableKeyIds.Contains(key)) {
+ return false;
+ }
auto& keys = mData.mUsableKeyIds;
for (size_t i = 0; i < keys.Length(); i++) {
if (keys[i].mId == aKeyId &&
keys[i].mSessionId == aSessionId) {
keys.RemoveElementAt(i);
break;
}
}
+ return true;
}
void
CDMCaps::AutoLock::CallWhenKeyUsable(const CencKeyId& aKey,
nsIRunnable* aContinuation,
nsIThread* aTarget)
{
mData.mMonitor.AssertCurrentThreadOwns();
--- a/content/media/eme/CDMCaps.h
+++ b/content/media/eme/CDMCaps.h
@@ -33,18 +33,23 @@ public:
~AutoLock();
// Returns true if the capabilities of the CDM are known, i.e. they have
// been reported by the CDM to Gecko.
bool AreCapsKnown();
bool IsKeyUsable(const CencKeyId& aKeyId);
- void SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
- void SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
+ // Returns true if setting this key usable results in the usable keys
+ // changing for this session, i.e. the key was not previously marked usable.
+ bool SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
+
+ // Returns true if setting this key unusable results in the usable keys
+ // changing for this session, i.e. the key was previously marked usable.
+ bool SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
void DropKeysForSession(const nsAString& aSessionId);
void GetUsableKeysForSession(const nsAString& aSessionId,
nsTArray<CencKeyId>& aOutKeyIds);
// Sets the capabilities of the CDM. aCaps is the logical OR of the
// GMP_EME_CAP_* flags from gmp-decryption.h.
void SetCaps(uint64_t aCaps);
@@ -94,16 +99,21 @@ private:
const nsString& aSessionId)
: mId(aId)
, mSessionId(aSessionId)
{}
UsableKey(const UsableKey& aOther)
: mId(aOther.mId)
, mSessionId(aOther.mSessionId)
{}
+ bool operator==(const UsableKey& aOther) const {
+ return mId == aOther.mId &&
+ mSessionId == aOther.mSessionId;
+ };
+
CencKeyId mId;
nsString mSessionId;
};
nsTArray<UsableKey> mUsableKeyIds;
nsTArray<WaitForKeys> mWaitForKeys;
nsTArray<nsRefPtr<nsIRunnable>> mWaitForCaps;
--- a/content/media/eme/CDMProxy.cpp
+++ b/content/media/eme/CDMProxy.cpp
@@ -421,16 +421,29 @@ CDMProxy::OnSessionMessage(const nsAStri
}
nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
if (session) {
session->DispatchKeyMessage(aMessage, aDestinationURL);
}
}
void
+CDMProxy::OnKeysChange(const nsAString& aSessionId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mKeys.IsNull()) {
+ return;
+ }
+ nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+ if (session) {
+ session->DispatchKeysChange();
+ }
+}
+
+void
CDMProxy::OnExpirationChange(const nsAString& aSessionId,
GMPTimestamp aExpiryTime)
{
MOZ_ASSERT(NS_IsMainThread());
NS_WARNING("CDMProxy::OnExpirationChange() not implemented");
}
void
--- a/content/media/eme/CDMProxy.h
+++ b/content/media/eme/CDMProxy.h
@@ -157,16 +157,19 @@ public:
GMPErr aResult,
const nsTArray<uint8_t>& aDecryptedData);
// GMP thread only.
void gmp_Terminated();
CDMCaps& Capabilites();
+ // Main thread only.
+ void OnKeysChange(const nsAString& aSessionId);
+
#ifdef DEBUG
bool IsOnGMPThread();
#endif
private:
struct InitData {
uint32_t mPromiseId;
--- a/content/media/eme/MediaKeySession.cpp
+++ b/content/media/eme/MediaKeySession.cpp
@@ -8,16 +8,17 @@
#include "mozilla/dom/MediaKeySession.h"
#include "mozilla/dom/MediaKeyError.h"
#include "mozilla/dom/MediaKeyMessageEvent.h"
#include "mozilla/dom/MediaEncryptedEvent.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/CDMProxy.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/Move.h"
+#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaKeySession,
DOMEventTargetHelper,
mMediaKeyError,
mKeys,
@@ -279,10 +280,29 @@ void
MediaKeySession::DispatchKeyError(uint32_t aSystemCode)
{
RefPtr<MediaKeyError> event(new MediaKeyError(this, aSystemCode));
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
asyncDispatcher->PostDOMEvent();
}
+void
+MediaKeySession::DispatchKeysChange()
+{
+ if (IsClosed()) {
+ return;
+ }
+ DebugOnly<nsresult> rv =
+ nsContentUtils::DispatchTrustedEvent(mKeys->GetOwnerDoc(),
+ this,
+ NS_LITERAL_STRING("keyschange"),
+ false,
+ false);
+#ifdef DEBUG
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to dispatch keyschange event");
+ }
+#endif
+}
+
} // namespace dom
} // namespace mozilla
--- a/content/media/eme/MediaKeySession.h
+++ b/content/media/eme/MediaKeySession.h
@@ -79,16 +79,18 @@ public:
already_AddRefed<Promise> GetUsableKeyIds(ErrorResult& aRv);
void DispatchKeyMessage(const nsTArray<uint8_t>& aMessage,
const nsAString& aURL);
void DispatchKeyError(uint32_t system_code);
+ void DispatchKeysChange();
+
void OnClosed();
bool IsClosed() const;
private:
~MediaKeySession();
nsRefPtr<Promise> mClosed;
--- a/content/media/eme/MediaKeys.cpp
+++ b/content/media/eme/MediaKeys.cpp
@@ -586,10 +586,16 @@ CopyArrayBufferViewOrArrayBufferData(con
bufferview.ComputeLengthAndData();
aOutData.AppendElements(bufferview.Data(), bufferview.Length());
} else {
return false;
}
return true;
}
+nsIDocument*
+MediaKeys::GetOwnerDoc() const
+{
+ return mElement ? mElement->OwnerDoc() : nullptr;
+}
+
} // namespace dom
} // namespace mozilla
--- a/content/media/eme/MediaKeys.h
+++ b/content/media/eme/MediaKeys.h
@@ -117,16 +117,20 @@ public:
// Returns true if this MediaKeys has been bound to a media element.
bool IsBoundToMediaElement() const;
// Return NS_OK if the principals are the same as when the MediaKeys
// was created, failure otherwise.
nsresult CheckPrincipals();
+ // Returns a pointer to the bound media element's owner doc.
+ // If we're not bound, this returns null.
+ nsIDocument* GetOwnerDoc() const;
+
private:
static bool IsTypeSupported(const nsAString& aKeySystem,
const Optional<nsAString>& aInitDataType = Optional<nsAString>(),
const Optional<nsAString>& aContentType = Optional<nsAString>());
bool IsInPrivateBrowsing();
already_AddRefed<Promise> Init(ErrorResult& aRv);
--- a/content/media/mediasource/MediaSource.cpp
+++ b/content/media/mediasource/MediaSource.cpp
@@ -17,16 +17,17 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/TimeRanges.h"
#include "mozilla/mozalloc.h"
#include "nsContentTypeParser.h"
#include "nsDebug.h"
#include "nsError.h"
#include "nsIRunnable.h"
+#include "nsIScriptObjectPrincipal.h"
#include "nsPIDOMWindow.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "prlog.h"
struct JSContext;
class JSObject;
@@ -389,22 +390,29 @@ MediaSource::GetBuffered(TimeRanges* aBu
MSE_DEBUG("MediaSource(%p)::GetBuffered ranges=%s", this, DumpTimeRanges(intersectionRanges).get());
}
MediaSource::MediaSource(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
, mDuration(UnspecifiedNaN<double>())
, mDecoder(nullptr)
+ , mPrincipal(nullptr)
, mReadyState(MediaSourceReadyState::Closed)
, mFirstSourceBufferInitialized(false)
{
MOZ_ASSERT(NS_IsMainThread());
mSourceBuffers = new SourceBufferList(this);
mActiveSourceBuffers = new SourceBufferList(this);
+
+ nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
+ if (sop) {
+ mPrincipal = sop->GetPrincipal();
+ }
+
MSE_API("MediaSource(%p)::MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p",
this, aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get());
}
void
MediaSource::SetReadyState(MediaSourceReadyState aState)
{
MOZ_ASSERT(NS_IsMainThread());
--- a/content/media/mediasource/MediaSource.h
+++ b/content/media/mediasource/MediaSource.h
@@ -80,16 +80,21 @@ public:
void SetReadyState(MediaSourceReadyState aState);
// Used by SourceBuffer to call CreateSubDecoder.
MediaSourceDecoder* GetDecoder()
{
return mDecoder;
}
+ nsIPrincipal* GetPrincipal()
+ {
+ return mPrincipal;
+ }
+
// Called by SourceBuffers to notify this MediaSource that data has
// been evicted from the buffered data. The start and end times
// that were evicted are provided.
void NotifyEvicted(double aStart, double aEnd);
// Queue InitializationEvent to run on the main thread. Called when a
// SourceBuffer has an initialization segment appended, but only
// dispatched the first time (using mFirstSourceBufferInitialized).
@@ -123,16 +128,18 @@ private:
double mDuration;
nsRefPtr<SourceBufferList> mSourceBuffers;
nsRefPtr<SourceBufferList> mActiveSourceBuffers;
nsRefPtr<MediaSourceDecoder> mDecoder;
+ nsRefPtr<nsIPrincipal> mPrincipal;
+
MediaSourceReadyState mReadyState;
bool mFirstSourceBufferInitialized;
};
NS_DEFINE_STATIC_IID_ACCESSOR(MediaSource, MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)
} // namespace dom
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -102,19 +102,19 @@ MediaSourceDecoder::Shutdown()
}
// Kick WaitForData out of its slumber.
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mon.NotifyAll();
}
/*static*/
already_AddRefed<MediaResource>
-MediaSourceDecoder::CreateResource()
+MediaSourceDecoder::CreateResource(nsIPrincipal* aPrincipal)
{
- return nsRefPtr<MediaResource>(new MediaSourceResource()).forget();
+ return nsRefPtr<MediaResource>(new MediaSourceResource(aPrincipal)).forget();
}
void
MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
{
MOZ_ASSERT(!mMediaSource && !mDecoderStateMachine && NS_IsMainThread());
mMediaSource = aMediaSource;
}
--- a/content/media/mediasource/MediaSourceDecoder.h
+++ b/content/media/mediasource/MediaSourceDecoder.h
@@ -36,17 +36,17 @@ public:
virtual MediaDecoder* Clone() MOZ_OVERRIDE;
virtual MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
virtual nsresult Load(nsIStreamListener**, MediaDecoder*) MOZ_OVERRIDE;
virtual nsresult GetSeekable(dom::TimeRanges* aSeekable) MOZ_OVERRIDE;
virtual void Shutdown() MOZ_OVERRIDE;
- static already_AddRefed<MediaResource> CreateResource();
+ static already_AddRefed<MediaResource> CreateResource(nsIPrincipal* aPrincipal = nullptr);
void AttachMediaSource(dom::MediaSource* aMediaSource);
void DetachMediaSource();
already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
void AddTrackBuffer(TrackBuffer* aTrackBuffer);
void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
--- a/content/media/mediasource/MediaSourceResource.h
+++ b/content/media/mediasource/MediaSourceResource.h
@@ -21,22 +21,22 @@ extern PRLogModuleInfo* GetMediaSourceAP
#define UNIMPLEMENTED() MSE_DEBUG("MediaSourceResource(%p): UNIMPLEMENTED FUNCTION at %s:%d", this, __FILE__, __LINE__)
namespace mozilla {
class MediaSourceResource MOZ_FINAL : public MediaResource
{
public:
- MediaSourceResource() {}
+ MediaSourceResource(nsIPrincipal* aPrincipal = nullptr)
+ : mPrincipal(aPrincipal) {}
virtual nsresult Close() MOZ_OVERRIDE { return NS_OK; }
virtual void Suspend(bool aCloseImmediately) MOZ_OVERRIDE { UNIMPLEMENTED(); }
virtual void Resume() MOZ_OVERRIDE { UNIMPLEMENTED(); }
- virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() MOZ_OVERRIDE { UNIMPLEMENTED(); return nullptr; }
virtual bool CanClone() MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder) MOZ_OVERRIDE { UNIMPLEMENTED(); return nullptr; }
virtual void SetReadMode(MediaCacheStream::ReadMode aMode) MOZ_OVERRIDE { UNIMPLEMENTED(); }
virtual void SetPlaybackRate(uint32_t aBytesPerSecond) MOZ_OVERRIDE { UNIMPLEMENTED(); }
virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
virtual nsresult Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
virtual int64_t Tell() MOZ_OVERRIDE { UNIMPLEMENTED(); return -1; }
@@ -47,16 +47,21 @@ public:
virtual int64_t GetNextCachedData(int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return -1; }
virtual int64_t GetCachedDataEnd(int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return -1; }
virtual bool IsDataCachedToEndOfResource(int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
virtual bool IsSuspendedByCache() MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
virtual bool IsSuspended() MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
+ virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() MOZ_OVERRIDE
+ {
+ return nsRefPtr<nsIPrincipal>(mPrincipal).forget();
+ }
+
virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) MOZ_OVERRIDE
{
UNIMPLEMENTED();
aRanges.AppendElement(MediaByteRange(0, GetLength()));
return NS_OK;
}
virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; }
@@ -71,16 +76,17 @@ private:
return size;
}
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
{
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
+ nsRefPtr<nsIPrincipal> mPrincipal;
const nsCString mType;
};
} // namespace mozilla
#undef UNIMPLEMENTED
#endif /* MOZILLA_MEDIASOURCERESOURCE_H_ */
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/1080986.html
@@ -0,0 +1,3 @@
+<html>
+<audio autoplay src="1080986.wav"></audio>
+</html>
new file mode 100644
index 0000000000000000000000000000000000000000..b96c59b7ec2ecdc5033904eb9ceb779adb05d154
GIT binary patch
literal 592
zc$^hcT}YE*6n@_CCl^^QFDjWt+TTUA#c*?Y5lw40`qwd67vdo7rmmVIQK3Yj-2@s~
zS6vi{8Fi6el#pnV&6El;gCHzpHODj!o!_?adwM;G1Lr(E&-vlh1_ObB0@VA%N1HCk
zb`}8;(*LNyrvgBMT_Pufbs<SY@KoS*ur3fPT*IO*O`dY6`=GNN7oxGKq~crVz{*o|
zvo>P2WoMOp`h#pNzsy7VN~KG4s)wz(c}ek#Au)j^vzdMRO)Zo=k79Ff^^Nt#c%Mz-
zy0V>RqC!m@y~bT%nVLrXI)_aae*L*x%iC-bhG-QXe933LrCrprc^7^PCla<!J-@Ok
z7uS1v#p=en+y}K)+{uoLX_T5jxJ?_^1Gxsq)h%XHnIO1Fn^GO9qEBgOmpN!u8}nSn
z8RLGYSILMQ`8KNf%qOBpq*yGP(PP<#S16X7%VG!{;KYD6LA$7Cx4FmxG%~{oPGSs8
zEMpi6eCJt&M3TSQh$Fa)esr>rbErXtLo7s+Uc6=tkHL%Me8e2TQo(w3@GqlC(S{<7
z@|r~JF-Z@0;4$Z!<S^gSl<XO<*(<5p2p4Lx8;dNFznh^071)afPV*nDunTEg+=@Y|
z+lLYq;3NCFOoOvb@U86kkRvi5<_k_qpJZBAI`Uj$DJo@O7u?tnkJS1RMgt=9h8nrG
QPev(BF34@h`CHEY54@=vF#rGn
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -69,12 +69,13 @@ load 986901.html
load 990794.html
load 1015662.html
skip-if(Android||B2G) test-pref(media.navigator.permission.disabled,true) load 1028458.html # bug 1048863
load buffer-source-ended-1.html
HTTP load media-element-source-seek-1.html
load offline-buffer-source-ended-1.html
load oscillator-ended-1.html
load oscillator-ended-2.html
+load 1080986.html
include ../../mediasource/test/crashtests/crashtests.list
# This needs to run at the end to avoid leaking busted state into other tests.
skip-if(winWidget) load 691096-1.html
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -644,29 +644,28 @@ var gEMETests = [
keys: {
// "keyid" : "key"
"7e571d017e571d017e571d017e571d01" : "7e5711117e5711117e5711117e571111",
"7e571d027e571d027e571d027e571d02" : "7e5722227e5722227e5722227e572222",
},
sessionType:"temporary",
duration:0.47
},
- // XXX Bug 1082239
- //{
- // name:"gizmo-frag-cencinit.mp4",
- // fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
- // type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
- // keys: {
- // // "keyid" : "key"
- // "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
- // "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
- // },
- // sessionType:"temporary",
- // duration:2.00,
- //},
+ {
+ name:"gizmo-frag-cencinit.mp4",
+ fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
+ type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+ "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+ },
+ sessionType:"temporary",
+ duration:2.00,
+ },
];
function checkMetadata(msg, e, test) {
if (test.width) {
is(e.videoWidth, test.width, msg + " video width");
}
if (test.height) {
is(e.videoHeight, test.height, msg + " video height");
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -472,16 +472,17 @@ skip-if = buildapp == 'b2g' # bug 102168
[test_texttrackcue.html]
[test_texttracklist.html]
[test_texttrackregion.html]
[test_timeupdate_small_files.html]
[test_trackelementevent.html]
[test_trackevent.html]
[test_unseekable.html]
[test_video_to_canvas.html]
+[test_video_in_audio_element.html]
[test_videoDocumentTitle.html]
[test_VideoPlaybackQuality.html]
[test_VideoPlaybackQuality_disabled.html]
[test_volume.html]
[test_vttparser.html]
[test_webvtt_disabled.html]
# The tests below contain backend-specific tests. Write backend independent
--- a/content/media/test/test_encryptedMediaExtensions.html
+++ b/content/media/test/test_encryptedMediaExtensions.html
@@ -148,16 +148,35 @@ function PlayTest(test, elem)
return;
}
// This file isn't fragmented; set the media source normally.
elem.src = test.name;
elem.play();
}
+function KeysChangeFunc(session, keys) {
+ session.keyIdsReceived = [];
+ for (var keyid in keys) {
+ info("Set " + keyid + " to false in session.keyIdsReceived");
+ session.keyIdsReceived[keyid] = false;
+ }
+ return function(ev) {
+ var session = ev.target;
+ session.gotKeysChanged = true;
+ session.getUsableKeyIds().then(function(keyIds) {
+ for (var k = 0; k < keyIds.length; k++) {
+ var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
+ ok(kid in session.keyIdsReceived, "session.keyIdsReceived contained " + kid + " as expected.");
+ session.keyIdsReceived[kid] = true;
+ }
+ }, bail("Failed to get keyIds"));
+ }
+}
+
function startTest(test, token)
{
manager.started(test._token);
var v = document.createElement("video");
var gotEncrypted = false;
var gotPlaying = false;
@@ -165,24 +184,27 @@ function startTest(test, token)
gotEncrypted = true;
info(token + " got encrypted event");
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
token + " MediaKeys should support this keysystem");
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
info(token + " created MediaKeys object ok");
+ mediaKeys.sessions = [];
return v.setMediaKeys(mediaKeys);
}, bail("failed to create MediaKeys object")).then(function() {
info(token + " set MediaKeys on <video> element ok");
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
"MediaKeys should still support keysystem after CDM created...");
var session = v.mediaKeys.createSession(test.sessionType);
+ v.mediaKeys.sessions.push(session);
+ session.addEventListener("keyschange", KeysChangeFunc(session, test.keys), false);
session.addEventListener("message", UpdateSessionFunc(test));
session.generateRequest(ev.initDataType, ev.initData).then(function() {
}, bail(token + " Failed to initialise MediaKeySession"));
}, bail(token + " Failed to set MediaKeys on <video> element"));
});
v.addEventListener("playing", function () { gotPlaying = true; });
@@ -193,16 +215,27 @@ function startTest(test, token)
ok(gotEncrypted, token + " encrypted event should have fired");
ok(gotPlaying, token + " playing event should have fired");
ok(Math.abs(test.duration - v.duration) < 0.1,
token + " Duration of video should be corrrect");
ok(Math.abs(test.duration - v.currentTime) < 0.1,
token + " Current time should be same as duration");
+ // Verify all sessions had all keys went sent the to the CDM usable, and thus
+ // that we received keyschange event(s).
+ var sessions = v.mediaKeys.sessions;
+ is(sessions.length, 1, "should have 1 session");
+ for (var i = 0; i < sessions.length; i++) {
+ var session = sessions[i];
+ ok(session.gotKeysChanged, "Should have received at least one keychange event");
+ for (var kid in session.keyIdsReceived) {
+ ok(session.keyIdsReceived[kid], "key with id " + kid + " was usable as expected");
+ }
+ }
});
v.addEventListener("error", bail(token + " got error event"));
PlayTest(test, v);
}
function testIsTypeSupported()
--- a/content/media/test/test_imagecapture.html
+++ b/content/media/test/test_imagecapture.html
@@ -33,16 +33,17 @@ function gcTest(track) {
};
imageCapture.onerror = function(error) {
ok(false, "takePhoto failure in gc testing");
reject();
};
imageCapture.takePhoto();
}
+ info("Call gc ");
SpecialPowers.gc();
});
}
// Continue calling takePhoto() in rapid succession.
function rapidTest(track) {
return new Promise(function(resolve, reject) {
var imageCapture = new ImageCapture(track);
@@ -106,18 +107,30 @@ function trackTest(track) {
track.enabled = false;
imageCapture.takePhoto()
});
}
function init() {
return new Promise(function(resolve, reject) {
+ var constraints;
+ if (SpecialPowers.Services.appinfo.widgetToolkit == "gonk") {
+ info("B2G ImageCapture test");
+ // Reduce repeat count due to b2g emulator is very slow.
+ repeat = 20;
+ // Use gonk camera, MedieEngine will be the backend of ImageCapture.
+ constraints = {video: true};
+ } else {
+ // use fake camera, MediaStreamGraph will be the backend of ImageCapture.
+ constraints = {video: true, fake: true}
+ }
+
window.navigator.mozGetUserMedia(
- {video: true, fake: true},
+ constraints,
function(stream) {
var track = stream.getVideoTracks()[0];
resolve(track);
},
function(err) {
reject(err);
}
);
@@ -132,20 +145,21 @@ function start() {
info("ImageCapture blob test.");
return blobTest(track);
}).then(function(track) {
info("ImageCapture rapid takePhoto() test.");
return rapidTest(track);
}).then(function(track) {
info("ImageCapture multiple instances test.");
return gcTest(track);
- }).then(function() {
- SimpleTest.finish();
- });
+ }).then(SimpleTest.finish);
}
+SimpleTest.requestCompleteLog();
SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({"set": [["dom.imagecapture.enabled", true]]}, start);
+SpecialPowers.pushPrefEnv({"set": [["dom.imagecapture.enabled", true],
+ ["media.navigator.permission.disabled", true]
+ ]}, start);
</script>
</pre>
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_video_in_audio_element.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1060896
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1060896</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="application/javascript">
+
+ /**
+ * Test for Bug 1060896; tests that loading a video inside an audio element works.
+ **/
+
+ var manager = new MediaTestManager;
+
+ function ended(event) {
+ var a = event.target;
+ removeNodeAndSource(a);
+ manager.finished(a.token);
+ }
+
+ function initTest(test, token) {
+ var a = document.createElement('audio');
+ a.token = token;
+ manager.started(token);
+ a.autoplay = true;
+
+ a.addEventListener("ended", ended, false);
+
+ a.src = test.name;
+ }
+
+ var videos = gSmallTests.filter(function(x){return /^video/.test(x.type);});
+
+ manager.runTests(videos, initTest);
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1060896">Mozilla Bug 1060896</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/media/wave/WaveReader.cpp
+++ b/content/media/wave/WaveReader.cpp
@@ -546,27 +546,27 @@ WaveReader::LoadListChunk(uint32_t aChun
// List chunks are always word (two byte) aligned.
NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
"LoadListChunk called with unaligned resource");
static const unsigned int MAX_CHUNK_SIZE = 1 << 16;
static_assert(uint64_t(MAX_CHUNK_SIZE) < UINT_MAX / sizeof(char),
"MAX_CHUNK_SIZE too large for enumerator.");
- if (aChunkSize > MAX_CHUNK_SIZE) {
+ if (aChunkSize > MAX_CHUNK_SIZE || aChunkSize < 4) {
return false;
}
nsAutoArrayPtr<char> chunk(new char[aChunkSize]);
if (!ReadAll(chunk.get(), aChunkSize)) {
return false;
}
static const uint32_t INFO_LIST_MAGIC = 0x494e464f;
- const char *p = chunk.get();
+ const char* p = chunk.get();
if (ReadUint32BE(&p) != INFO_LIST_MAGIC) {
return false;
}
const waveIdToName ID_TO_NAME[] = {
{ 0x49415254, NS_LITERAL_CSTRING("artist") }, // IART
{ 0x49434d54, NS_LITERAL_CSTRING("comments") }, // ICMT
{ 0x49474e52, NS_LITERAL_CSTRING("genre") }, // IGNR
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -68,17 +68,17 @@
#include "nsXULControllers.h"
#include "nsIBoxObject.h"
#include "nsPIBoxObject.h"
#include "XULDocument.h"
#include "nsXULPopupListener.h"
#include "nsRuleWalker.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsCSSParser.h"
-#include "nsIListBoxObject.h"
+#include "ListBoxObject.h"
#include "nsContentUtils.h"
#include "nsContentList.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/MouseEvents.h"
#include "nsIDOMMutationEvent.h"
#include "nsPIDOMWindow.h"
#include "nsJSPrincipals.h"
#include "nsDOMAttributeMap.h"
@@ -104,16 +104,17 @@
#include "nsXBLBinding.h"
#include "mozilla/EventDispatcher.h"
#include "mozAutoDocUpdate.h"
#include "nsIDOMXULCommandEvent.h"
#include "nsCCUncollectableMarker.h"
#include "nsICSSDeclaration.h"
#include "mozilla/dom/XULElementBinding.h"
+#include "mozilla/dom/BoxObject.h"
using namespace mozilla;
using namespace mozilla::dom;
#ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
uint32_t nsXULPrototypeAttribute::gNumElements;
uint32_t nsXULPrototypeAttribute::gNumAttributes;
uint32_t nsXULPrototypeAttribute::gNumCacheTests;
@@ -1500,17 +1501,17 @@ nsXULElement::GetControllers(ErrorResult
NS_IMETHODIMP
nsXULElement::GetBoxObject(nsIBoxObject** aResult)
{
ErrorResult rv;
*aResult = GetBoxObject(rv).take();
return rv.ErrorCode();
}
-already_AddRefed<nsIBoxObject>
+already_AddRefed<BoxObject>
nsXULElement::GetBoxObject(ErrorResult& rv)
{
// XXX sXBL/XBL2 issue! Owner or current document?
return OwnerDoc()->GetBoxObjectFor(this, rv);
}
// Methods for setting/getting attributes from nsIDOMXULElement
#define NS_IMPL_XUL_STRING_ATTR(_method, _atom) \
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -21,17 +21,16 @@
#include "nsIControllers.h"
#include "nsIDOMElement.h"
#include "nsIDOMXULElement.h"
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsIRDFCompositeDataSource.h"
#include "nsIRDFResource.h"
#include "nsIURI.h"
#include "nsIXULTemplateBuilder.h"
-#include "nsIBoxObject.h"
#include "nsLayoutCID.h"
#include "nsAttrAndChildArray.h"
#include "nsGkAtoms.h"
#include "nsAutoPtr.h"
#include "nsStyledElement.h"
#include "nsIFrameLoader.h"
#include "nsFrameLoader.h"
#include "mozilla/dom/DOMRect.h"
@@ -49,16 +48,19 @@ class nsXULPrototypeNode;
typedef nsTArray<nsRefPtr<nsXULPrototypeNode> > nsPrototypeArray;
namespace mozilla {
class EventChainPreVisitor;
class EventListenerManager;
namespace css {
class StyleRule;
}
+namespace dom {
+class BoxObject;
+}
}
namespace JS {
class SourceBufferHolder;
}
////////////////////////////////////////////////////////////////////////
@@ -582,17 +584,17 @@ public:
bool AllowEvents() const
{
return BoolAttrIsTrue(nsGkAtoms::allowevents);
}
already_AddRefed<nsIRDFCompositeDataSource> GetDatabase();
already_AddRefed<nsIXULTemplateBuilder> GetBuilder();
already_AddRefed<nsIRDFResource> GetResource(mozilla::ErrorResult& rv);
nsIControllers* GetControllers(mozilla::ErrorResult& rv);
- already_AddRefed<nsIBoxObject> GetBoxObject(mozilla::ErrorResult& rv);
+ already_AddRefed<mozilla::dom::BoxObject> GetBoxObject(mozilla::ErrorResult& rv);
void Focus(mozilla::ErrorResult& rv);
void Blur(mozilla::ErrorResult& rv);
void Click(mozilla::ErrorResult& rv);
// The XPCOM DoCommand never fails, so it's OK for us.
already_AddRefed<nsINodeList>
GetElementsByAttribute(const nsAString& aAttribute,
const nsAString& aValue);
already_AddRefed<nsINodeList>
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -39,16 +39,17 @@
#include "nsXMLContentSink.h"
#include "nsXULContentSink.h"
#include "nsXULContentUtils.h"
#include "nsIXULOverlayProvider.h"
#include "nsIStringEnumerator.h"
#include "nsNetUtil.h"
#include "nsParserCIID.h"
#include "nsPIBoxObject.h"
+#include "mozilla/dom/BoxObject.h"
#include "nsXPIDLString.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowRoot.h"
#include "nsXULCommandDispatcher.h"
#include "nsXULElement.h"
#include "prlog.h"
#include "rdf.h"
#include "nsIFrame.h"
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4190,17 +4190,17 @@ nsDocShell::GetChildSHEntry(int32_t aChi
NS_IMETHODIMP
nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
int32_t aChildOffset, uint32_t loadType,
bool aCloneChildren)
{
nsresult rv;
- if (mLSHE && loadType != LOAD_PUSHSTATE) {
+ if (mLSHE && loadType != LOAD_PUSHSTATE && !aCloneRef) {
/* You get here if you are currently building a
* hierarchy ie.,you just visited a frameset page
*/
nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
if (container) {
rv = container->AddChild(aNewEntry, aChildOffset);
}
}
--- a/docshell/test/test_bug580069.html
+++ b/docshell/test/test_bug580069.html
@@ -11,18 +11,16 @@ https://bugzilla.mozilla.org/show_bug.cg
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=580069">Mozilla Bug 580069</a>
<iframe id='iframe' src='file_bug580069_1.html'></iframe>
<script type="application/javascript">
-SimpleTest.expectAssertions(1);
-
SimpleTest.waitForExplicitFinish();
var iframe = document.getElementById('iframe');
var iframeCw = iframe.contentWindow;
// Called when file_bug580069_1.html loads.
function page1Load() {
// This should cause us to load file 2.
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -81,17 +81,16 @@
#include "nsIDOMCSSSupportsRule.h"
#include "nsIDOMMozCSSKeyframeRule.h"
#include "nsIDOMMozCSSKeyframesRule.h"
#include "nsIDOMCSSCounterStyleRule.h"
#include "nsIDOMCSSPageRule.h"
#include "nsIDOMCSSStyleRule.h"
#include "nsIDOMXULCommandDispatcher.h"
#include "nsIControllers.h"
-#include "nsIBoxObject.h"
#ifdef MOZ_XUL
#include "nsITreeSelection.h"
#include "nsITreeContentView.h"
#include "nsITreeView.h"
#include "nsIXULTemplateBuilder.h"
#include "nsITreeColumns.h"
#endif
#include "nsIDOMXPathNSResolver.h"
@@ -246,18 +245,16 @@ static nsDOMClassInfoData sClassInfoData
// XUL classes
#ifdef MOZ_XUL
NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCommandDispatcher, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif
NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControllers, nsNonDOMObjectSH,
DEFAULT_SCRIPTABLE_FLAGS)
- NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(BoxObject, nsDOMGenericSH,
- DEFAULT_SCRIPTABLE_FLAGS)
#ifdef MOZ_XUL
NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeSelection, nsDOMGenericSH,
DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeContentView, nsDOMGenericSH,
DEFAULT_SCRIPTABLE_FLAGS)
#endif
#ifdef MOZ_XUL
@@ -691,20 +688,16 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher)
DOM_CLASSINFO_MAP_END
#endif
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControllers, nsIControllers)
DOM_CLASSINFO_MAP_ENTRY(nsIControllers)
DOM_CLASSINFO_MAP_END
- DOM_CLASSINFO_MAP_BEGIN(BoxObject, nsIBoxObject)
- DOM_CLASSINFO_MAP_ENTRY(nsIBoxObject)
- DOM_CLASSINFO_MAP_END
-
#ifdef MOZ_XUL
DOM_CLASSINFO_MAP_BEGIN(TreeSelection, nsITreeSelection)
DOM_CLASSINFO_MAP_ENTRY(nsITreeSelection)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(TreeContentView, nsITreeContentView)
DOM_CLASSINFO_MAP_ENTRY(nsITreeContentView)
DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
@@ -1387,41 +1380,28 @@ nsDOMClassInfo::ShutDown()
sConstructor_id = JSID_VOID;
sWrappedJSObject_id = JSID_VOID;
NS_IF_RELEASE(sXPConnect);
sIsInitialized = false;
}
-static nsDOMConstructorFunc
-FindConstructorFunc(const nsDOMClassInfoData *aDOMClassInfoData)
-{
- return nullptr;
-}
-
static nsresult
BaseStubConstructor(nsIWeakReference* aWeakOwner,
const nsGlobalNameStruct *name_struct, JSContext *cx,
JS::Handle<JSObject*> obj, const JS::CallArgs &args)
{
MOZ_ASSERT(obj);
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
nsresult rv;
nsCOMPtr<nsISupports> native;
if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
- const nsDOMClassInfoData* ci_data =
- &sClassInfoData[name_struct->mDOMClassInfoID];
- nsDOMConstructorFunc func = FindConstructorFunc(ci_data);
- if (func) {
- rv = func(getter_AddRefs(native));
- } else {
- rv = NS_ERROR_NOT_AVAILABLE;
- }
+ rv = NS_ERROR_NOT_AVAILABLE;
} else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
native = do_CreateInstance(name_struct->mCID, &rv);
} else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
native = do_CreateInstance(name_struct->mAlias->mCID, &rv);
} else {
native = do_CreateInstance(*name_struct->mData->mConstructorCID, &rv);
}
if (NS_FAILED(rv)) {
@@ -1621,17 +1601,17 @@ private:
static bool IsConstructable(const nsDOMClassInfoData *aData)
{
if (IS_EXTERNAL(aData->mCachedClassInfo)) {
const nsExternalDOMClassInfoData* data =
static_cast<const nsExternalDOMClassInfoData*>(aData);
return data->mConstructorCID != nullptr;
}
- return FindConstructorFunc(aData);
+ return nullptr;
}
static bool IsConstructable(const nsGlobalNameStruct *aNameStruct)
{
return
(aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
IsConstructable(&sClassInfoData[aNameStruct->mDOMClassInfoID])) ||
(aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo &&
IsConstructable(aNameStruct->mData)) ||
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -14,17 +14,16 @@ DOMCI_CLASS(CSSImportRule)
DOMCI_CLASS(CSSMediaRule)
DOMCI_CLASS(CSSNameSpaceRule)
// XUL classes
#ifdef MOZ_XUL
DOMCI_CLASS(XULCommandDispatcher)
#endif
DOMCI_CLASS(XULControllers)
-DOMCI_CLASS(BoxObject)
#ifdef MOZ_XUL
DOMCI_CLASS(TreeSelection)
DOMCI_CLASS(TreeContentView)
#endif
#ifdef MOZ_XUL
DOMCI_CLASS(XULTemplateBuilder)
DOMCI_CLASS(XULTreeBuilder)
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -170,16 +170,20 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::bluetooth::BluetoothPairingHandle',
},
'BluetoothPairingListener': {
'nativeType':
'mozilla::dom::bluetooth::BluetoothPairingListener',
},
+'BoxObject': {
+ 'resultNotAddRefed': ['element'],
+},
+
'CameraCapabilities': {
'nativeType': 'mozilla::dom::CameraCapabilities',
'headerFile': 'DOMCameraCapabilities.h'
},
'CameraControl': {
'nativeType': 'mozilla::nsDOMCameraControl',
'headerFile': 'DOMCameraControl.h',
@@ -861,16 +865,20 @@ DOMInterfaces = {
'headerFile' : 'nsPluginArray.h',
'nativeType': 'nsPluginElement',
},
'PluginArray': {
'nativeType': 'nsPluginArray',
},
+'PopupBoxObject': {
+ 'resultNotAddRefed': ['triggerNode', 'anchorNode'],
+},
+
'Position': {
'headerFile': 'nsGeoPosition.h'
},
'PositionError': {
'headerFile': 'nsGeolocation.h'
},
@@ -1797,31 +1805,30 @@ def addExternalIface(iface, nativeType=N
addExternalIface('ApplicationCache', nativeType='nsIDOMOfflineResourceList')
addExternalIface('Counter')
addExternalIface('CSSRule')
addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
addExternalIface('HitRegionOptions', nativeType='nsISupports')
addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
-addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
addExternalIface('MozControllers', nativeType='nsIControllers')
addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback',
notflattened=True)
addExternalIface('MozMmsMessage')
addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
notflattened=True)
addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
addExternalIface('MozSmsMessage')
-addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
- notflattened=True)
addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
headerFile='nsITreeColumns.h')
+addExternalIface('MozTreeView', nativeType='nsITreeView',
+ headerFile='nsITreeView.h')
addExternalIface('MozWakeLockListener', headerFile='nsIDOMWakeLockListener.h')
addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow',
notflattened=True)
addExternalIface('nsIControllers', nativeType='nsIControllers')
addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
headerFile='Crypto.h')
addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
@@ -1830,16 +1837,17 @@ addExternalIface('nsIFile', nativeType='
addExternalIface('nsIMessageBroadcaster', nativeType='nsIMessageBroadcaster',
headerFile='nsIMessageManager.h', notflattened=True)
addExternalIface('nsISelectionListener', nativeType='nsISelectionListener')
addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
addExternalIface('nsISupports', nativeType='nsISupports')
addExternalIface('nsIDocShell', nativeType='nsIDocShell', notflattened=True)
addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
+addExternalIface('nsIScriptableRegion', nativeType='nsIScriptableRegion', notflattened=True)
addExternalIface('OutputStream', nativeType='nsIOutputStream',
notflattened=True)
addExternalIface('Principal', nativeType='nsIPrincipal',
headerFile='nsIPrincipal.h', notflattened=True)
addExternalIface('StackFrame', nativeType='nsIStackFrame',
headerFile='nsIException.h', notflattened=True)
addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
notflattened=True)
--- a/dom/bluetooth2/BluetoothAdapter.cpp
+++ b/dom/bluetooth2/BluetoothAdapter.cpp
@@ -9,16 +9,17 @@
#include "BluetoothUtils.h"
#include "DOMRequest.h"
#include "nsTArrayHelpers.h"
#include "mozilla/dom/BluetoothAdapter2Binding.h"
#include "mozilla/dom/BluetoothAttributeEvent.h"
#include "mozilla/dom/BluetoothStatusChangedEvent.h"
#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/File.h"
#include "mozilla/dom/bluetooth/BluetoothAdapter.h"
#include "mozilla/dom/bluetooth/BluetoothClassOfDevice.h"
#include "mozilla/dom/bluetooth/BluetoothDevice.h"
#include "mozilla/dom/bluetooth/BluetoothDiscoveryHandle.h"
#include "mozilla/dom/bluetooth/BluetoothPairingListener.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
@@ -1020,17 +1021,17 @@ BluetoothAdapter::Disconnect(BluetoothDe
}
bs->Disconnect(address, serviceUuid, results);
return request.forget();
}
already_AddRefed<DOMRequest>
BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
- nsIDOMBlob* aBlob, ErrorResult& aRv)
+ File& aBlob, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
if (!win) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<DOMRequest> request = new DOMRequest(win);
@@ -1040,25 +1041,25 @@ BluetoothAdapter::SendFile(const nsAStri
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
if (XRE_GetProcessType() == GeckoProcessType_Default) {
// In-process transfer
- bs->SendFile(aDeviceAddress, aBlob, results);
+ bs->SendFile(aDeviceAddress, &aBlob, results);
} else {
ContentChild *cc = ContentChild::GetSingleton();
if (!cc) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
- BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob);
+ BlobChild* actor = cc->GetOrCreateActorForBlob(&aBlob);
if (!actor) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
bs->SendFile(aDeviceAddress, nullptr, actor, results);
}
--- a/dom/bluetooth2/BluetoothAdapter.h
+++ b/dom/bluetooth2/BluetoothAdapter.h
@@ -13,16 +13,17 @@
#include "mozilla/dom/BluetoothAdapter2Binding.h"
#include "mozilla/dom/BluetoothDeviceEvent.h"
#include "mozilla/dom/Promise.h"
#include "nsCOMPtr.h"
namespace mozilla {
namespace dom {
class DOMRequest;
+class File;
struct MediaMetaData;
struct MediaPlayStatus;
}
}
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothDevice;
@@ -119,17 +120,17 @@ public:
Disconnect(BluetoothDevice& aDevice,
const Optional<short unsigned int>& aServiceUuid,
ErrorResult& aRv);
already_AddRefed<DOMRequest> GetConnectedDevices(uint16_t aServiceUuid,
ErrorResult& aRv);
// OPP file transfer related methods
already_AddRefed<DOMRequest> SendFile(const nsAString& aDeviceAddress,
- nsIDOMBlob* aBlob,
+ File& aBlob,
ErrorResult& aRv);
already_AddRefed<DOMRequest> StopSendingFile(const nsAString& aDeviceAddress,
ErrorResult& aRv);
already_AddRefed<DOMRequest>
ConfirmReceivingFile(const nsAString& aDeviceAddress,
bool aConfirmation,
ErrorResult& aRv);
--- a/dom/bluetooth2/bluedroid/BluetoothOppManager.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothOppManager.cpp
@@ -10,36 +10,37 @@
#include "BluetoothService.h"
#include "BluetoothSocket.h"
#include "BluetoothUtils.h"
#include "BluetoothUuid.h"
#include "ObexBase.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/File.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "nsAutoPtr.h"
#include "nsCExternalHandlerService.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
-#include "nsIDOMFile.h"
#include "nsIFile.h"
#include "nsIInputStream.h"
#include "nsIMIMEService.h"
#include "nsIOutputStream.h"
#include "nsIVolumeService.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#define TARGET_SUBDIR "Download/Bluetooth/"
USING_BLUETOOTH_NAMESPACE
using namespace mozilla;
+using namespace mozilla::dom;
using namespace mozilla::ipc;
namespace {
// Sending system message "bluetooth-opp-update-progress" every 50kb
static const uint32_t kUpdateProgressBase = 50 * 1024;
/*
* The format of the header of an PUT request is
@@ -344,17 +345,18 @@ BluetoothOppManager::StartSendingNextFil
}
bool
BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
BlobParent* aActor)
{
MOZ_ASSERT(NS_IsMainThread());
- nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+ nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
+ nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
return SendFile(aDeviceAddress, blob.get());
}
bool
BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
nsIDOMBlob* aBlob)
{
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
@@ -820,17 +820,17 @@ public:
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
sBondingRunnableArray.RemoveElement(mRunnable);
ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("CreatedPairedDevice"));
}
private:
- BluetoothReplyRunnable* mRunnable;
+ nsRefPtr<BluetoothReplyRunnable> mRunnable;
};
nsresult
BluetoothServiceBluedroid::CreatePairedDeviceInternal(
const nsAString& aDeviceAddress, int aTimeout,
BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
@@ -855,17 +855,17 @@ public:
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
sUnbondingRunnableArray.RemoveElement(mRunnable);
ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("RemoveDevice"));
}
private:
- BluetoothReplyRunnable* mRunnable;
+ nsRefPtr<BluetoothReplyRunnable> mRunnable;
};
nsresult
BluetoothServiceBluedroid::RemoveDeviceInternal(
const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
--- a/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
@@ -363,24 +363,37 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
if (mImpl->IsShutdownOnMainThread()) {
BT_LOGD("mConsumer is null, aborting receive!");
return;
}
+ if (aConnectionStatus != 0) {
+ mImpl->mConsumer->NotifyError();
+ return;
+ }
+
mImpl->mConsumer->SetAddress(aBdAddress);
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new AcceptTask(mImpl, aFd));
}
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR("BluetoothSocketInterface::Accept failed: %d", (int)aStatus);
+
+ if (!mImpl->IsShutdownOnMainThread()) {
+ // Instead of NotifyError(), call NotifyDisconnect() to trigger
+ // BluetoothOppManager::OnSocketDisconnect() as
+ // DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
+ // order to keep the same behavior and reduce regression risk.
+ mImpl->mConsumer->NotifyDisconnect();
+ }
}
private:
DroidSocketImpl* mImpl;
};
class AcceptRunnable MOZ_FINAL : public SocketIORunnable<DroidSocketImpl>
{
@@ -499,27 +512,43 @@ public:
MOZ_ASSERT(mImpl);
}
void Connect(int aFd, const nsAString& aBdAddress,
int aConnectionStatus) MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
- if (!mImpl->IsShutdownOnMainThread()) {
- mImpl->mConsumer->SetAddress(aBdAddress);
+ if (mImpl->IsShutdownOnMainThread()) {
+ BT_LOGD("mConsumer is null, aborting send!");
+ return;
}
+
+ if (aConnectionStatus != 0) {
+ mImpl->mConsumer->NotifyError();
+ return;
+ }
+
+ mImpl->mConsumer->SetAddress(aBdAddress);
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new SocketConnectTask(mImpl, aFd));
}
void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
BT_WARNING("Connect failed: %d", (int)aStatus);
+
+ if (!mImpl->IsShutdownOnMainThread()) {
+ // Instead of NotifyError(), call NotifyDisconnect() to trigger
+ // BluetoothOppManager::OnSocketDisconnect() as
+ // DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
+ // order to keep the same behavior and reduce regression risk.
+ mImpl->mConsumer->NotifyDisconnect();
+ }
}
private:
DroidSocketImpl* mImpl;
};
bool
BluetoothSocket::ConnectSocket(const nsAString& aDeviceAddress, int aChannel)
--- a/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
@@ -281,17 +281,17 @@ private:
iv.iov_len = MSG1_SIZE;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iv;
msg.msg_iovlen = 1;
ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
- if (res < 0) {
+ if (res <= 0) {
return STATUS_FAIL;
}
mLen += res;
return STATUS_SUCCESS;
}
@@ -306,17 +306,17 @@ private:
struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100];
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iv;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
- if (res < 0) {
+ if (res <= 0) {
return STATUS_FAIL;
}
mLen += res;
if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) {
return STATUS_FAIL;
}
--- a/dom/bluetooth2/bluez/BluetoothOppManager.cpp
+++ b/dom/bluetooth2/bluez/BluetoothOppManager.cpp
@@ -10,36 +10,37 @@
#include "BluetoothService.h"
#include "BluetoothSocket.h"
#include "BluetoothUtils.h"
#include "BluetoothUuid.h"
#include "ObexBase.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/File.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "nsAutoPtr.h"
#include "nsCExternalHandlerService.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
-#include "nsIDOMFile.h"
#include "nsIFile.h"
#include "nsIInputStream.h"
#include "nsIMIMEService.h"
#include "nsIOutputStream.h"
#include "nsIVolumeService.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#define TARGET_SUBDIR "Download/Bluetooth/"
USING_BLUETOOTH_NAMESPACE
using namespace mozilla;
+using namespace mozilla::dom;
using namespace mozilla::ipc;
using mozilla::TimeDuration;
using mozilla::TimeStamp;
namespace {
// Sending system message "bluetooth-opp-update-progress" every 50kb
static const uint32_t kUpdateProgressBase = 50 * 1024;
@@ -366,17 +367,18 @@ BluetoothOppManager::StartSendingNextFil
}
bool
BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
BlobParent* aActor)
{
MOZ_ASSERT(NS_IsMainThread());
- nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+ nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
+ nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
return SendFile(aDeviceAddress, blob.get());
}
bool
BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
nsIDOMBlob* aBlob)
{
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3199,17 +3199,17 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
// in the font, and adjust accordingly.
// (The same will be true for HTML text layout.)
const gfxFont::Metrics& metrics = mTextRun->GetFontGroup()->
GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal);
mCtx->mTarget->SetTransform(mCtx->mTarget->GetTransform().Copy().
PreTranslate(baselineOrigin). // translate origin for rotation
PreRotate(gfx::Float(M_PI / 2.0)). // turn 90deg clockwise
PreTranslate(-baselineOrigin). // undo the translation
- PreTranslate(Point(0, metrics.emAscent - metrics.emDescent) / 2));
+ PreTranslate(Point(0, (metrics.emAscent - metrics.emDescent) / 2)));
// and offset the (alphabetic) baseline of the
// horizontally-shaped text from the (centered)
// default baseline used for vertical
}
RefPtr<GlyphRenderingOptions> renderingOptions = font->GetGlyphRenderingOptions();
GlyphBuffer buffer;
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -73,17 +73,18 @@ WebGLContext::InitWebGL2()
WebGLExtensionID::OES_texture_half_float,
WebGLExtensionID::OES_texture_half_float_linear,
WebGLExtensionID::OES_vertex_array_object,
WebGLExtensionID::WEBGL_depth_texture,
WebGLExtensionID::WEBGL_draw_buffers
};
const GLFeature sFeatureRequiredArr[] = {
GLFeature::instanced_non_arrays,
- GLFeature::transform_feedback2
+ GLFeature::transform_feedback2,
+ GLFeature::invalidate_framebuffer
};
// check WebGL extensions that are supposed to be natively supported
for (size_t i = 0; i < size_t(MOZ_ARRAY_LENGTH(sExtensionNativelySupportedArr)); i++)
{
WebGLExtensionID extension = sExtensionNativelySupportedArr[i];
if (!IsExtensionSupported(extension)) {
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -243,13 +243,14 @@ public:
private:
WebGL2Context();
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info);
+ JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
};
} // namespace mozilla
#endif
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -27,27 +27,83 @@ WebGL2Context::FramebufferTextureLayer(G
}
void
WebGL2Context::GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval)
{
MOZ_CRASH("Not Implemented.");
}
+// Map attachments intended for the default buffer, to attachments for a non-
+// default buffer.
+static void
+TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
+{
+ for (size_t i = 0; i < in.Length(); i++) {
+ switch (in[i]) {
+ case LOCAL_GL_COLOR:
+ out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0);
+ break;
+ case LOCAL_GL_DEPTH:
+ out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT);
+ break;
+ case LOCAL_GL_STENCIL:
+ out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT);
+ break;
+ }
+ }
+}
+
void
WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments)
{
- MOZ_CRASH("Not Implemented.");
+ if (IsContextLost())
+ return;
+ MakeContextCurrent();
+
+ if (target != LOCAL_GL_FRAMEBUFFER)
+ return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
+ for (size_t i = 0; i < attachments.Length(); i++) {
+ if (!ValidateFramebufferAttachment(attachments[i], "invalidateFramebuffer"))
+ return;
+ }
+
+ if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
+ dom::Sequence<GLenum> tmpAttachments;
+ TranslateDefaultAttachments(attachments, &tmpAttachments);
+ gl->fInvalidateFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements());
+ } else {
+ gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
+ }
}
void
-WebGL2Context::InvalidateSubFramebuffer (GLenum target, const dom::Sequence<GLenum>& attachments,
- GLint x, GLint y, GLsizei width, GLsizei height)
+WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
+ GLint x, GLint y, GLsizei width, GLsizei height)
{
- MOZ_CRASH("Not Implemented.");
+ if (IsContextLost())
+ return;
+ MakeContextCurrent();
+
+ if (target != LOCAL_GL_FRAMEBUFFER)
+ return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
+ for (size_t i = 0; i < attachments.Length(); i++) {
+ if (!ValidateFramebufferAttachment(attachments[i], "invalidateSubFramebuffer"))
+ return;
+ }
+
+ if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
+ dom::Sequence<GLenum> tmpAttachments;
+ TranslateDefaultAttachments(attachments, &tmpAttachments);
+ gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements(),
+ x, y, width, height);
+ } else {
+ gl->fInvalidateSubFramebuffer(target, attachments.Length(), attachments.Elements(),
+ x, y, width, height);
+ }
}
void
WebGL2Context::ReadBuffer(GLenum mode)
{
MOZ_CRASH("Not Implemented.");
}
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -287,17 +287,17 @@ WebGL2Context::TexSubImage3D(GLenum rawT
yoffset == 0 &&
zoffset == 0 &&
width == imageInfo.Width() &&
height == imageInfo.Height() &&
depth == imageInfo.Depth();
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
- tex->DoDeferredImageInitialization(texImageTarget, level);
+ tex->EnsureNoUninitializedImageData(texImageTarget, level);
}
}
GLenum driverType = LOCAL_GL_NONE;
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
DriverFormatsFromEffectiveInternalFormat(gl,
existingEffectiveInternalFormat,
@@ -340,8 +340,22 @@ WebGL2Context::CompressedTexImage3D(GLen
void
WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize, const dom::ArrayBufferView& data)
{
MOZ_CRASH("Not Implemented.");
}
+
+JS::Value
+WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname)
+{
+ switch (pname) {
+ case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
+ {
+ GLint i = 0;
+ gl->fGetTexParameteriv(target.get(), pname, &i);
+ return JS::NumberValue(uint32_t(i));
+ }
+ }
+ return WebGLContext::GetTexParameterInternal(target, pname);
+}
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -985,16 +985,18 @@ protected:
void UndoFakeVertexAttrib0();
static CheckedUint32 GetImageSize(GLsizei height,
GLsizei width,
GLsizei depth,
uint32_t pixelSize,
uint32_t alignment);
+ virtual JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname);
+
// Returns x rounded to the next highest multiple of y.
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
return ((x + y - 1) / y) * y;
}
nsRefPtr<gl::GLContext> gl;
CheckedUint32 mGeneration;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -448,17 +448,17 @@ WebGLContext::CopyTexSubImage2D_base(Tex
// the rect doesn't fit in the framebuffer
// first, we initialize the texture as black
if (!sub) {
tex->SetImageInfo(texImageTarget, level, width, height, 1,
effectiveInternalFormat,
WebGLImageDataStatus::UninitializedImageData);
- tex->DoDeferredImageInitialization(texImageTarget, level);
+ tex->EnsureNoUninitializedImageData(texImageTarget, level);
}
// if we are completely outside of the framebuffer, we can exit now with our black texture
if ( x >= framebufferWidth
|| x+width <= 0
|| y >= framebufferHeight
|| y+height <= 0)
{
@@ -596,17 +596,17 @@ WebGLContext::CopyTexSubImage2D(GLenum r
if (imageInfo.HasUninitializedImageData()) {
bool coversWholeImage = xoffset == 0 &&
yoffset == 0 &&
width == texWidth &&
height == texHeight;
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
- tex->DoDeferredImageInitialization(texImageTarget, level);
+ tex->EnsureNoUninitializedImageData(texImageTarget, level);
}
}
TexInternalFormat internalformat;
TexType type;
UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(imageInfo.EffectiveInternalFormat(),
&internalformat, &type);
return CopyTexSubImage2D_base(texImageTarget, level, internalformat, xoffset, yoffset, x, y, width, height, true);
@@ -922,17 +922,17 @@ WebGLContext::GenerateMipmap(GLenum rawT
const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D)
? LOCAL_GL_TEXTURE_2D
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
if (!tex->HasImageInfoAt(imageTarget, 0))
{
return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
}
- if (!tex->IsFirstImagePowerOfTwo())
+ if (!IsWebGL2() && !tex->IsFirstImagePowerOfTwo())
return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
TexInternalFormat internalformat = tex->ImageInfoAt(imageTarget, 0).EffectiveInternalFormat();
if (IsTextureFormatCompressed(internalformat))
return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
(IsGLDepthFormat(internalformat) || IsGLDepthStencilFormat(internalformat)))
@@ -1606,16 +1606,22 @@ WebGLContext::GetTexParameter(GLenum raw
const TexTarget target(rawTarget);
if (!activeBoundTextureForTarget(target)) {
ErrorInvalidOperation("getTexParameter: no texture bound");
return JS::NullValue();
}
+ return GetTexParameterInternal(target, pname);
+}
+
+JS::Value
+WebGLContext::GetTexParameterInternal(const TexTarget& target, GLenum pname)
+{
switch (pname) {
case LOCAL_GL_TEXTURE_MIN_FILTER:
case LOCAL_GL_TEXTURE_MAG_FILTER:
case LOCAL_GL_TEXTURE_WRAP_S:
case LOCAL_GL_TEXTURE_WRAP_T:
{
GLint i = 0;
gl->fGetTexParameteriv(target.get(), pname, &i);
@@ -3425,17 +3431,17 @@ WebGLContext::CompressedTexSubImage2D(GL
if (levelInfo.HasUninitializedImageData()) {
bool coversWholeImage = xoffset == 0 &&
yoffset == 0 &&
width == levelInfo.Width() &&
height == levelInfo.Height();
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
- tex->DoDeferredImageInitialization(texImageTarget, level);
+ tex->EnsureNoUninitializedImageData(texImageTarget, level);
}
}
MakeContextCurrent();
gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, internalformat, byteLength, view.Data());
}
JS::Value
@@ -3961,17 +3967,17 @@ WebGLContext::TexSubImage2D_base(TexImag
if (imageInfo.HasUninitializedImageData()) {
bool coversWholeImage = xoffset == 0 &&
yoffset == 0 &&
width == imageInfo.Width() &&
height == imageInfo.Height();
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
- tex->DoDeferredImageInitialization(texImageTarget, level);
+ tex->EnsureNoUninitializedImageData(texImageTarget, level);
}
}
MakeContextCurrent();
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
uint32_t dstTexelSize = GetBitsPerTexel(existingEffectiveInternalFormat) / 8;
size_t dstPlainRowSize = dstTexelSize * width;
// There are checks above to ensure that this won't overflow.
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -172,16 +172,28 @@ WebGLContext::GetParameter(JSContext* cx
if (mBoundVertexArray == mDefaultVertexArray){
return WebGLObjectAsJSValue(cx, (WebGLVertexArray *) nullptr, rv);
}
return WebGLObjectAsJSValue(cx, mBoundVertexArray.get(), rv);
}
}
+ if (IsWebGL2()) {
+ switch (pname) {
+ case LOCAL_GL_MAX_SAMPLES:
+ case LOCAL_GL_MAX_UNIFORM_BLOCK_SIZE:
+ case LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS: {
+ GLint val;
+ gl->fGetIntegerv(pname, &val);
+ return JS::NumberValue(uint32_t(val));
+ }
+ }
+ }
+
switch (pname) {
//
// String params
//
case LOCAL_GL_VENDOR:
return StringValue(cx, "Mozilla", rv);
case LOCAL_GL_RENDERER:
return StringValue(cx, "Mozilla", rv);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -334,16 +334,28 @@ bool WebGLContext::ValidateGLSLString(co
/**
* Return true if the framebuffer attachment is valid. Attachment must
* be one of depth/stencil/depth_stencil/color attachment.
*/
bool
WebGLContext::ValidateFramebufferAttachment(GLenum attachment, const char* funcName)
{
+ if (!mBoundFramebuffer) {
+ switch (attachment) {
+ case LOCAL_GL_COLOR:
+ case LOCAL_GL_DEPTH:
+ case LOCAL_GL_STENCIL:
+ return true;
+ default:
+ ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName, attachment);
+ return false;
+ }
+ }
+
if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
{
return true;
}
GLenum colorAttachCount = 1;
@@ -799,18 +811,20 @@ WebGLContext::ValidateTexImageSize(TexIm
InfoFrom(func, dims), level, maxTexImageSize);
return false;
}
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
* "If level is greater than zero, and either width or
* height is not a power-of-two, the error INVALID_VALUE is
* generated."
+ *
+ * This restriction does not apply to GL ES Version 3.0+.
*/
- if (level > 0) {
+ if (!IsWebGL2() && level > 0) {
if (!is_pot_assuming_nonnegative(width)) {
ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
InfoFrom(func, dims), width);
return false;
}
if (!is_pot_assuming_nonnegative(height)) {
ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
@@ -822,17 +836,17 @@ WebGLContext::ValidateTexImageSize(TexIm
// TODO: WebGL 2
if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
if (depth < 0) {
ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func, dims));
return false;
}
- if (depth > 0 && !is_pot_assuming_nonnegative(depth)) {
+ if (!IsWebGL2() && !is_pot_assuming_nonnegative(depth)) {
ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
InfoFrom(func, dims), depth);
return false;
}
}
return true;
}
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -181,29 +181,29 @@ void
WebGLTexture::SetCustomMipmap() {
if (mHaveGeneratedMipmap) {
// if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
// we need to compute now all the mipmap image info.
// since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
// and are power-of-two.
ImageInfo imageInfo = ImageInfoAtFace(0, 0);
- NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
+ NS_ASSERTION(mContext->IsWebGL2() || imageInfo.IsPowerOfTwo(),
+ "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
GLsizei size = std::max(std::max(imageInfo.mWidth, imageInfo.mHeight), imageInfo.mDepth);
- // so, the size is a power of two, let's find its log in base 2.
+ // Find floor(log2(size)). (ES 3.0.4, 3.8 - Mipmapping).
size_t maxLevel = 0;
for (GLsizei n = size; n > 1; n >>= 1)
++maxLevel;
EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
for (size_t level = 1; level <= maxLevel; ++level) {
- // again, since the sizes are powers of two, no need for any max(1,x) computation
imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
for(size_t face = 0; face < mFacesCount; ++face)
ImageInfoAtFace(face, level) = imageInfo;
}
}
mHaveGeneratedMipmap = false;
@@ -280,67 +280,69 @@ WebGLTexture::ResolvedFakeBlackStatus()
int dim = mTarget == LOCAL_GL_TEXTURE_2D ? 2 : 3;
if (DoesMinFilterRequireMipmap())
{
if (!IsMipmapComplete()) {
mContext->GenerateWarning
("%s is a %dD texture, with a minification filter requiring a mipmap, "
"and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black, dim);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
- } else if (!ImageInfoBase().IsPowerOfTwo()) {
+ } else if (!mContext->IsWebGL2() && !ImageInfoBase().IsPowerOfTwo()) {
mContext->GenerateWarning
("%s is a %dD texture, with a minification filter requiring a mipmap, "
"and either its width or height is not a power of two.", msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
else // no mipmap required
{
if (!ImageInfoBase().IsPositive()) {
mContext->GenerateWarning
("%s is a %dD texture and its width or height is equal to zero.",
msg_rendering_as_black, dim);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
- } else if (!AreBothWrapModesClampToEdge() && !ImageInfoBase().IsPowerOfTwo()) {
+ } else if (!AreBothWrapModesClampToEdge() && !mContext->IsWebGL2() && !ImageInfoBase().IsPowerOfTwo()) {
mContext->GenerateWarning
("%s is a %dD texture, with a minification filter not requiring a mipmap, "
"with its width or height not a power of two, and with a wrap mode "
"different from CLAMP_TO_EDGE.", msg_rendering_as_black, dim);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
}
else // cube map
{
- bool areAllLevel0ImagesPOT = true;
- for (size_t face = 0; face < mFacesCount; ++face)
- areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
+ bool legalImageSize = true;
+ if (!mContext->IsWebGL2()) {
+ for (size_t face = 0; face < mFacesCount; ++face)
+ legalImageSize &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
+ }
if (DoesMinFilterRequireMipmap())
{
if (!IsMipmapCubeComplete()) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
"and is not mipmap cube complete (as defined in section 3.7.10).",
msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
- } else if (!areAllLevel0ImagesPOT) {
+ } else if (!legalImageSize) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
"and either the width or the height of some level 0 image is not a power of two.",
msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
else // no mipmap required
{
if (!IsCubeComplete()) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
"and is not cube complete (as defined in section 3.7.10).",
msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
- } else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
+ } else if (!AreBothWrapModesClampToEdge() && !legalImageSize) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
"with some level 0 image having width or height not a power of two, and with a wrap mode "
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
}
@@ -417,17 +419,17 @@ WebGLTexture::ResolvedFakeBlackStatus()
// in this case we know that we can't be dealing with a depth texture per WEBGL_depth_texture
// and ANGLE_depth_texture (which allow only one image per texture) so we can assume that
// glTexImage2D is able to upload data to images.
for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
for (size_t face = 0; face < mFacesCount; ++face) {
TexImageTarget imageTarget = TexImageTargetForTargetAndFace(mTarget, face);
const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData) {
- DoDeferredImageInitialization(imageTarget, level);
+ EnsureNoUninitializedImageData(imageTarget, level);
}
}
}
mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
} else {
// The texture only contains uninitialized image data. In this case,
// we can use a black texture for it.
mFakeBlackStatus = WebGLTextureFakeBlackStatus::UninitializedImageData;
@@ -537,20 +539,21 @@ ClearWithTempFB(WebGLContext* context, G
mask |= LOCAL_GL_COLOR_BUFFER_BIT;
// Last chance!
return ClearByMask(context, mask);
}
void
-WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level)
+WebGLTexture::EnsureNoUninitializedImageData(TexImageTarget imageTarget, GLint level)
{
const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
- MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
+ if (!imageInfo.HasUninitializedImageData())
+ return;
mContext->MakeContextCurrent();
// Try to clear with glCLear.
if (imageTarget == LOCAL_GL_TEXTURE_2D) {
bool cleared = ClearWithTempFB(mContext, GLName(),
imageTarget, level,
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -194,17 +194,17 @@ public:
MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
if (imageInfo.mImageDataStatus != newStatus) {
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
imageInfo.mImageDataStatus = newStatus;
}
- void DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level);
+ void EnsureNoUninitializedImageData(TexImageTarget imageTarget, GLint level);
protected:
TexMinFilter mMinFilter;
TexMagFilter mMagFilter;
TexWrap mWrapS, mWrapT;
size_t mFacesCount, mMaxLevelWithCustomImages;
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -19,8 +19,10 @@ skip-if = toolkit == 'android' #bug 8654
[webgl-mochitest/test_webgl_conformance.html]
skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[webgl-mochitest/test_webgl_request_context.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[webgl-mochitest/test_webgl_request_mismatch.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[webgl-mochitest/test_webgl2_not_exposed.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
+[webgl-mochitest/test_webgl2_invalidate_framebuffer.html]
+skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_webgl2_invalidate_framebuffer.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+<title>WebGL2 test: Framebuffers</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="driver-info.js"></script>
+<script src="webgl-util.js"></script>
+<body>
+<canvas id="c" width="64" height="64"></canvas>
+<script>
+
+WebGLUtil.withWebGL2('c', function (gl) {
+ gl.invalidateFramebuffer(gl.FRAMEBUFFER, [gl.COLOR]);
+ ok(gl.getError() == 0, 'invalidateFramebuffer');
+ gl.invalidateSubFramebuffer(gl.FRAMEBUFFER, [gl.COLOR], 0, 0, 64, 64);
+ ok(gl.getError() == 0, 'invalidateSubFramebuffer');
+ gl.invalidateFramebuffer(gl.FRAMEBUFFER, [gl.GL_COLOR_ATTACHMENT0]);
+ ok(gl.getError() == gl.INVALID_ENUM, 'invalidateFrameBuffer should fail with GL_COLOR_ATTACHMENT on the default framebuffer');
+}, function () {
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
--- a/dom/canvas/test/webgl-mochitest/webgl-util.js
+++ b/dom/canvas/test/webgl-mochitest/webgl-util.js
@@ -53,16 +53,54 @@ WebGLUtil = (function() {
if (!gl) {
error('WebGL context could not be retrieved from \'' + canvasId + '\'.');
return null;
}
return gl;
}
+ function withWebGL2(canvasId, callback, onFinished) {
+ var prefArrArr = [
+ ['webgl.force-enabled', true],
+ ['webgl.disable-angle', true],
+ ['webgl.enable-prototype-webgl2', true],
+ ];
+ var prefEnv = {'set': prefArrArr};
+ SpecialPowers.pushPrefEnv(prefEnv, function() {
+ var canvas = document.getElementById(canvasId);
+
+ var gl = null;
+ try {
+ gl = canvas.getContext('webgl2');
+ } catch(e) {}
+
+ if (!gl) {
+ try {
+ gl = canvas.getContext('experimental-webgl2');
+ } catch(e) {}
+ }
+
+ if (!gl) {
+ todo(false, 'WebGL2 is not supported');
+ onFinished();
+ return;
+ }
+
+ function errorFunc(str) {
+ ok(false, 'Error: ' + str);
+ }
+ setErrorFunc(errorFunc);
+ setWarningFunc(errorFunc);
+
+ callback(gl);
+ onFinished();
+ });
+ }
+
function getContentFromElem(elem) {
var str = "";
var k = elem.firstChild;
while (k) {
if (k.nodeType == 3)
str += k.textContent;
k = k.nextSibling;
@@ -120,12 +158,13 @@ WebGLUtil = (function() {
return prog;
}
return {
setErrorFunc: setErrorFunc,
setWarningFunc: setWarningFunc,
getWebGL: getWebGL,
+ withWebGL2: withWebGL2,
createShaderById: createShaderById,
createProgramByIds: createProgramByIds,
};
})();
--- a/dom/events/test/test_bug602962.xul
+++ b/dom/events/test/test_bug602962.xul
@@ -25,36 +25,35 @@ var oldWidth = 0, oldHeight = 0;
var win = null;
function openWindow() {
win = window.open("chrome://mochitests/content/chrome/dom/events/test/bug602962.xul", "_blank", "width=600,height=600");
}
function doTest() {
scrollbox = win.document.getElementById("page-scrollbox");
- sbo = scrollbox.boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject);
+ sbo = scrollbox.boxObject;
content = win.document.getElementById("page-box");
content.style.width = 400 + "px";
win.addEventListener("resize", function() {
win.removeEventListener("resize", arguments.callee, false);
sbo.scrollBy(200, 0);
setTimeout(function() { resize(); }, 0);
}, false);
oldWidth = win.outerWidth;
oldHeight = win.outerHeight;
win.resizeTo(200, 400);
}
function resize() {
- let x = {}, y = {};
- sbo.getPosition(x, y);
- scrollX = x.value, scrollY = y.value;
+ scrollX = sbo.positionX;
+ scrollY = sbo.positionY;
win.addEventListener("resize", function() {
content.style.width = (oldWidth + 400) + "px";
win.removeEventListener("resize", arguments.callee, true);
setTimeout(function() {
finish();
}, 0);
@@ -67,20 +66,18 @@ function finish() {
if (win.outerWidth != oldWidth ||
win.outerHeight != oldHeight) {
// We should eventually get back to the original size.
setTimeout(finish, 0);
return;
}
sbo.scrollBy(scrollX, scrollY);
- let x = {}, y = {};
- sbo.getPosition(x, y);
- is(x.value, 200, "Scroll X should have been restored to the value before the resize");
- is(y.value, 0, "Scroll Y should have been restored to the value before the resize");
+ is(sbo.positionX, 200, "Scroll X should have been restored to the value before the resize");
+ is(sbo.positionY, 0, "Scroll Y should have been restored to the value before the resize");
is(win.outerWidth, oldWidth, "Width should be resized");
is(win.outerHeight, oldHeight, "Height should be resized");
win.close();
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3017,16 +3017,17 @@ TabChild::RecvUIResolutionChanged()
nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
presContext->UIResolutionChanged();
return true;
}
TabChildGlobal::TabChildGlobal(TabChildBase* aTabChild)
: mTabChild(aTabChild)
{
+ SetIsNotDOMBinding();
}
TabChildGlobal::~TabChildGlobal()
{
}
void
TabChildGlobal::Init()
--- a/dom/locales/en-US/chrome/layout/css.properties
+++ b/dom/locales/en-US/chrome/layout/css.properties
@@ -101,16 +101,19 @@ PEExpectedInt=Expected an integer but fo
PEColorBadRGBContents=Expected number or percentage in rgb() but found '%1$S'.
PEColorComponentBadTerm=Expected '%2$S' but found '%1$S'.
PEColorHueEOF=hue
PEExpectedComma=Expected ',' but found '%1$S'.
PEColorSaturationEOF=saturation
PEColorLightnessEOF=lightness
PEColorOpacityEOF=opacity in color value
PEExpectedNumber=Expected a number but found '%1$S'.
+PEPositionEOF=<position>
+PEExpectedPosition=Expected <position> but found '%1$S'.
+PEExpectedRadius=Expected radius but found '%1$S'.
PEExpectedCloseParen=Expected ')' but found '%1$S'.
PEDeclEndEOF=';' or '}' to end declaration
PEParseDeclarationNoColon=Expected ':' but found '%1$S'.
PEParseDeclarationDeclExpected=Expected declaration but found '%1$S'.
PEEndOfDeclEOF=end of declaration
PEImportantEOF=important
PEExpectedImportant=Expected 'important' but found '%1$S'.
PEBadDeclEnd=Expected ';' to terminate declaration but found '%1$S'.
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -2434,17 +2434,17 @@ PeerConnectionWrapper.prototype = {
},
/**
* Checks that we are getting the media streams we expect.
*
* @param {object} stats
* The stats to check from this PeerConnectionWrapper
*/
- checkStats : function PCW_checkStats(stats) {
+ checkStats : function PCW_checkStats(stats, twoMachines) {
function toNum(obj) {
return obj? obj : 0;
}
function numTracks(streams) {
var n = 0;
streams.forEach(function(stream) {
n += stream.getAudioTracks().length + stream.getVideoTracks().length;
});
@@ -2456,17 +2456,23 @@ PeerConnectionWrapper.prototype = {
// Use spec way of enumerating stats
var counters = {};
for (var key in stats) {
if (stats.hasOwnProperty(key)) {
var res = stats[key];
// validate stats
ok(res.id == key, "Coherent stats id");
var nowish = Date.now() + 1000; // TODO: clock drift observed
+ if (twoMachines) {
+ nowish += 10000; // let's be very relaxed about clock sync
+ }
var minimum = this.whenCreated - 1000; // on Windows XP (Bug 979649)
+ if (twoMachines) {
+ minimum -= 10000; // let's be very relaxed about clock sync
+ }
if (isWinXP) {
todo(false, "Can't reliably test rtcp timestamps on WinXP (Bug 979649)");
} else {
ok(res.timestamp >= minimum,
"Valid " + (res.isRemote? "rtcp" : "rtp") + " timestamp " +
res.timestamp + " >= " + minimum + " (" +
(res.timestamp - minimum) + " ms)");
ok(res.timestamp <= nowish,
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -473,26 +473,26 @@ var commandsPeerConnection = [
test.next();
});
}
],
[
'PC_LOCAL_CHECK_STATS',
function (test) {
test.pcLocal.getStats(null, function(stats) {
- test.pcLocal.checkStats(stats);
+ test.pcLocal.checkStats(stats, test.steeplechase);
test.next();
});
}
],
[
'PC_REMOTE_CHECK_STATS',
function (test) {
test.pcRemote.getStats(null, function(stats) {
- test.pcRemote.checkStats(stats);
+ test.pcRemote.checkStats(stats, test.steeplechase);
test.next();
});
}
],
[
'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
function (test) {
var pc = test.pcLocal;
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -735,18 +735,18 @@ void NetworkUtils::postTetherInterfaceLi
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
// Send the dummy command to continue the function chain.
char command[MAX_COMMAND_SIZE];
snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
char buf[BUF_SIZE];
- const char* reason = NS_ConvertUTF16toUTF8(aResult.mResultReason).get();
- memcpy(buf, reason, strlen(reason));
+ NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
+ memcpy(buf, reason.get(), reason.Length() + 1);
split(buf, INTERFACE_DELIMIT, GET_FIELD(mInterfaceList));
doCommand(command, aChain, aCallback);
}
void NetworkUtils::setIpForwardingEnabled(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -668,16 +668,18 @@ var interfaceNamesInGlobalScope =
"MediaStreamAudioSourceNode",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "MediaStreamEvent", pref: "media.peerconnection.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "MediaStreamTrackEvent", pref: "media.peerconnection.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"MediaStreamTrack",
// IMPORTANT: Do not change this list without review from a DOM peer!
+ {name: "MenuBoxObject", xbl: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
"MessageEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"MessagePort",
// IMPORTANT: Do not change this list without review from a DOM peer!
"MimeType",
// IMPORTANT: Do not change this list without review from a DOM peer!
"MimeTypeArray",
// IMPORTANT: Do not change this list without review from a DOM peer!
@@ -858,16 +860,18 @@ var interfaceNamesInGlobalScope =
"PluginArray",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "PointerEvent", pref: "dom.w3c_pointer_events.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"PopStateEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"PopupBlockedEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
+ {name: "PopupBoxObject", xbl: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
"ProcessingInstruction",
// IMPORTANT: Do not change this list without review from a DOM peer!
"ProgressEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Promise",
// IMPORTANT: Do not change this list without review from a DOM peer!
"PropertyNodeList",
// IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BoxObject.webidl
@@ -0,0 +1,33 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Func="IsChromeOrXBL"]
+interface BoxObject {
+ readonly attribute Element? element;
+
+ readonly attribute long x;
+ readonly attribute long y;
+ [Throws]
+ readonly attribute long screenX;
+ [Throws]
+ readonly attribute long screenY;
+ readonly attribute long width;
+ readonly attribute long height;
+
+ nsISupports? getPropertyAsSupports(DOMString propertyName);
+ void setPropertyAsSupports(DOMString propertyName, nsISupports value);
+ [Throws]
+ DOMString? getProperty(DOMString propertyName);
+ void setProperty(DOMString propertyName, DOMString propertyValue);
+ void removeProperty(DOMString propertyName);
+
+ // for stepping through content in the expanded dom with box-ordinal-group order
+ readonly attribute Element? parentBox;
+ readonly attribute Element? firstChild;
+ readonly attribute Element? lastChild;
+ readonly attribute Element? nextSibling;
+ readonly attribute Element? previousSibling;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ContainerBoxObject.webidl
@@ -0,0 +1,12 @@
+
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[NoInterfaceObject]
+interface ContainerBoxObject : BoxObject {
+ [ChromeOnly]
+ readonly attribute nsIDocShell? docShell;
+};
--- a/dom/webidl/LegacyQueryInterface.webidl
+++ b/dom/webidl/LegacyQueryInterface.webidl
@@ -15,16 +15,17 @@ interface LegacyQueryInterface {
// Legacy QueryInterface, only exposed to chrome or XBL code on the
// main thread.
[Exposed=Window]
nsISupports queryInterface(IID iid);
};
Attr implements LegacyQueryInterface;
BarProp implements LegacyQueryInterface;
+BoxObject implements LegacyQueryInterface;
CaretPosition implements LegacyQueryInterface;
Comment implements LegacyQueryInterface;
Crypto implements LegacyQueryInterface;
CSSPrimitiveValue implements LegacyQueryInterface;
CSSStyleDeclaration implements LegacyQueryInterface;
CSSValueList implements LegacyQueryInterface;
DOMImplementation implements LegacyQueryInterface;
DOMParser implements LegacyQueryInterface;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ListBoxObject.webidl
@@ -0,0 +1,21 @@
+
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[NoInterfaceObject]
+interface ListBoxObject : BoxObject {
+
+ long getRowCount();
+ long getNumberOfVisibleRows();
+ long getIndexOfFirstVisibleRow();
+
+ void ensureIndexIsVisible(long rowIndex);
+ void scrollToIndex(long rowIndex);
+ void scrollByLines(long numLines);
+
+ Element? getItemAtIndex(long index);
+ long getIndexOfItem(Element item);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MenuBoxObject.webidl
@@ -0,0 +1,19 @@
+
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Func="IsChromeOrXBL"]
+interface MenuBoxObject : BoxObject {
+
+ void openMenu(boolean openFlag);
+
+ attribute Element? activeChild;
+
+ boolean handleKeyPress(KeyboardEvent keyEvent);
+
+ readonly attribute boolean openedWithKey;
+
+};
rename from layout/xul/nsIPopupBoxObject.idl
rename to dom/webidl/PopupBoxObject.webidl
--- a/layout/xul/nsIPopupBoxObject.idl
+++ b/dom/webidl/PopupBoxObject.webidl
@@ -1,84 +1,77 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "nsISupports.idl"
-
-interface nsIDOMElement;
-interface nsIDOMNode;
-interface nsIDOMEvent;
-interface nsIDOMClientRect;
-
-[scriptable, uuid(492861e3-d168-410f-b2bb-6eb8ce503d4a)]
-interface nsIPopupBoxObject : nsISupports
+[Func="IsChromeOrXBL"]
+interface PopupBoxObject : BoxObject
{
/**
* This method is deprecated. Use openPopup or openPopupAtScreen instead.
*/
- void showPopup(in nsIDOMElement srcContent, in nsIDOMElement popupContent,
- in long xpos, in long ypos,
- in wstring popupType, in wstring anchorAlignment,
- in wstring popupAlignment);
+ void showPopup(Element? srcContent, Element popupContent,
+ long xpos, long ypos,
+ DOMString popupType, DOMString anchorAlignment,
+ DOMString popupAlignment);
/**
* Hide the popup if it is open. The cancel argument is used as a hint that
* the popup is being closed because it has been cancelled, rather than
* something being selected within the panel.
*
* @param cancel if true, then the popup is being cancelled.
*/
- void hidePopup([optional] in bool cancel);
+ void hidePopup(optional boolean cancel = false);
- /**
+ /**
* Allow the popup to automatically position itself.
*/
attribute boolean autoPosition;
/**
* If keyboard navigation is enabled, the keyboard may be used to navigate
* the menuitems on the popup. Enabling keyboard navigation is the default
* behaviour and will install capturing key event listeners on the popup
* that do not propagate key events to the contents. If you wish to place
* elements in a popup which accept key events, such as textboxes, keyboard
* navigation should be disabled.
*
* Setting ignorekeys="true" on the popup element also disables keyboard
* navigation, and is recommended over calling this method.
*/
- void enableKeyboardNavigator(in boolean enableKeyboardNavigator);
+ void enableKeyboardNavigator(boolean enableKeyboardNavigator);
- /**
+ /**
* Enable automatic popup dismissal. This only has effect when called
* on an open popup.
*/
- void enableRollup(in boolean enableRollup);
+ void enableRollup(boolean enableRollup);
/**
* Control whether the event that caused the popup to be automatically
* dismissed ("rolled up") should be consumed, or dispatched as a
* normal event. This should be set immediately before calling showPopup()
* if non-default behavior is desired.
*/
- const uint32_t ROLLUP_DEFAULT = 0; /* widget/platform default */
- const uint32_t ROLLUP_CONSUME = 1; /* consume the rollup event */
- const uint32_t ROLLUP_NO_CONSUME = 2; /* don't consume the rollup event */
- void setConsumeRollupEvent(in uint32_t consume);
+ const unsigned long ROLLUP_DEFAULT = 0; /* widget/platform default */
+ const unsigned long ROLLUP_CONSUME = 1; /* consume the rollup event */
+ const unsigned long ROLLUP_NO_CONSUME = 2; /* don't consume the rollup event */
+ void setConsumeRollupEvent(unsigned long consume);
- /**
+ /**
* Size the popup to the given dimensions
*/
- void sizeTo(in long width, in long height);
+ void sizeTo(long width, long height);
/**
* Move the popup to a point on screen in CSS pixels.
*/
- void moveTo(in long left, in long top);
+ void moveTo(long left, long top);
/**
* Open the popup relative to a specified node at a specific location.
*
* The popup may be either anchored to another node or opened freely.
* To anchor a popup to a node, supply an anchor node and set the position
* to a string indicating the manner in which the popup should be anchored.
* Possible values for position are:
@@ -88,17 +81,17 @@ interface nsIPopupBoxObject : nsISupport
*
* The anchor node does not need to be in the same document as the popup.
*
* If the attributesOverride argument is true, the popupanchor, popupalign
* and position attributes on the popup node override the position value
* argument. If attributesOverride is false, the attributes are only used
* if position is empty.
*
- * For an anchored popup, the x and y arguments may be used to offset the
+ * For an anchored popup, the x and y arguments may be used to offset the
* popup from its anchored position by some distance, measured in CSS pixels.
* x increases to the right and y increases down. Negative values may also
* be used to move to the left and upwards respectively.
*
* Unanchored popups may be created by supplying null as the anchor node.
* An unanchored popup appears at the position specified by x and y,
* relative to the viewport of the document containing the popup node. In
* this case, position and attributesOverride are ignored.
@@ -106,82 +99,75 @@ interface nsIPopupBoxObject : nsISupport
* @param anchorElement the node to anchor the popup to, may be null
* @param position manner is which to anchor the popup to node
* @param x horizontal offset
* @param y vertical offset
* @param isContextMenu true for context menus, false for other popups
* @param attributesOverride true if popup node attributes override position
* @param triggerEvent the event that triggered this popup (mouse click for example)
*/
- void openPopup(in nsIDOMElement anchorElement,
- in AString position,
- in long x, in long y,
- in boolean isContextMenu,
- in boolean attributesOverride,
- in nsIDOMEvent triggerEvent);
+ void openPopup(Element? anchorElement,
+ DOMString position,
+ long x, long y,
+ boolean isContextMenu,
+ boolean attributesOverride,
+ Event? triggerEvent);
/**
* Open the popup at a specific screen position specified by x and y. This
* position may be adjusted if it would cause the popup to be off of the
* screen. The x and y coordinates are measured in CSS pixels, and like all
* screen coordinates, are given relative to the top left of the primary
* screen.
*
* @param isContextMenu true for context menus, false for other popups
* @param x horizontal screen position
* @param y vertical screen position
* @param triggerEvent the event that triggered this popup (mouse click for example)
*/
- void openPopupAtScreen(in long x, in long y,
- in boolean isContextMenu,
- in nsIDOMEvent triggerEvent);
+ void openPopupAtScreen(long x, long y,
+ boolean isContextMenu,
+ Event? triggerEvent);
/**
* Returns the state of the popup:
* closed - the popup is closed
* open - the popup is open
* showing - the popup is in the process of being shown
* hiding - the popup is in the process of being hidden
*/
- readonly attribute AString popupState;
+ readonly attribute DOMString popupState;
/**
* The node that triggered the popup. If the popup is not open, will return
* null.
*/
- readonly attribute nsIDOMNode triggerNode;
+ readonly attribute Node? triggerNode;
/**
* Retrieve the anchor that was specified to openPopup or for menupopups in a
* menu, the parent menu.
*/
- readonly attribute nsIDOMElement anchorNode;
+ readonly attribute Element? anchorNode;
/**
* Retrieve the screen rectangle of the popup, including the area occupied by
* any titlebar or borders present.
*/
- nsIDOMClientRect getOuterScreenRect();
+ DOMRect getOuterScreenRect();
/**
* Move an open popup to the given anchor position. The arguments have the same
* meaning as the corresponding argument to openPopup. This method has no effect
* on popups that are not open.
*/
- void moveToAnchor(in nsIDOMElement anchorElement,
- in AString position,
- in long x, in long y,
- in boolean attributesOverride);
+ void moveToAnchor(Element? anchorElement,
+ DOMString position,
+ long x, long y,
+ boolean attributesOverride);
/** Returns the alignment position where the popup has appeared relative to its
* anchor node or point, accounting for any flipping that occurred.
*/
- readonly attribute AString alignmentPosition;
+ readonly attribute DOMString alignmentPosition;
readonly attribute long alignmentOffset;
-};
-%{C++
-class nsIBoxObject;
-
-nsresult
-NS_NewPopupBoxObject(nsIBoxObject** aResult);
-
-%}
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ScrollBoxObject.webidl
@@ -0,0 +1,70 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[NoInterfaceObject]
+interface ScrollBoxObject : BoxObject {
+
+ /**
+ * Scroll to the given coordinates, in css pixels.
+ * (0,0) will put the top left corner of the scrolled element's padding-box
+ * at the top left corner of the scrollport (which is its inner-border-box).
+ * Values will be clamped to legal values.
+ */
+ [Throws]
+ void scrollTo(long x, long y);
+
+ /**
+ * Scroll the given amount of device pixels to the right and down.
+ * Values will be clamped to make the resuling position legal.
+ */
+ [Throws]
+ void scrollBy(long dx, long dy);
+ [Throws]
+ void scrollByLine(long dlines);
+ [Throws]
+ void scrollByIndex(long dindexes);
+ [Throws]
+ void scrollToLine(long line);
+ [Throws]
+ void scrollToElement(Element child);
+ [Throws]
+ void scrollToIndex(long index);
+
+ /**
+ * Get the current scroll position in css pixels.
+ * @see scrollTo for the definition of x and y.
+ */
+ [Pure, Throws]
+ readonly attribute long positionX;
+ [Pure, Throws]
+ readonly attribute long positionY;
+ [Pure, Throws]
+ readonly attribute long scrolledWidth;
+ [Pure, Throws]
+ readonly attribute long scrolledHeight;
+
+ /**
+ * DEPRECATED: Please use positionX and positionY
+ *
+ * Get the current scroll position in css pixels.
+ * @see scrollTo for the definition of x and y.
+ */
+ [Throws]
+ void getPosition(object x, object y);
+
+ /**
+ * DEPRECATED: Please use scrolledWidth and scrolledHeight
+ */
+ [Throws]
+ void getScrolledSize(object width, object height);
+
+ [Throws]
+ void ensureElementIsVisible(Element child);
+ [Throws]
+ void ensureIndexIsVisible(long index);
+ [Throws]
+ void ensureLineIsVisible(long line);
+};
copy from layout/xul/tree/nsITreeBoxObject.idl
copy to dom/webidl/TreeBoxObject.webidl
--- a/layout/xul/tree/nsITreeBoxObject.idl
+++ b/dom/webidl/TreeBoxObject.webidl
@@ -1,64 +1,68 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "nsISupports.idl"
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
-interface nsIDOMElement;
-interface nsITreeView;
-interface nsITreeSelection;
-interface nsITreeColumn;
-interface nsITreeColumns;
+interface MozTreeView;
+interface MozTreeColumn;
interface nsIScriptableRegion;
-[scriptable, uuid(64BA5199-C4F4-4498-BBDC-F8E4C369086C)]
-interface nsITreeBoxObject : nsISupports
-{
+dictionary TreeCellInfo {
+ long row = 0;
+ MozTreeColumn? col = null;
+ DOMString childElt = "";
+};
+
+[NoInterfaceObject]
+interface TreeBoxObject : BoxObject {
+
/**
* Obtain the columns.
*/
- readonly attribute nsITreeColumns columns;
+ readonly attribute TreeColumns? columns;
/**
* The view that backs the tree and that supplies it with its data.
* It is dynamically settable, either using a view attribute on the
* tree tag or by setting this attribute to a new value.
*/
- attribute nsITreeView view;
+ [SetterThrows]
+ attribute MozTreeView? view;
/**
* Whether or not we are currently focused.
*/
attribute boolean focused;
/**
* Obtain the treebody content node
*/
- readonly attribute nsIDOMElement treeBody;
+ readonly attribute Element? treeBody;
/**
* Obtain the height of a row.
*/
readonly attribute long rowHeight;
/**
* Obtain the width of a row.
*/
readonly attribute long rowWidth;
/**
- * Get the pixel position of the horizontal scrollbar.
+ * Get the pixel position of the horizontal scrollbar.
*/
readonly attribute long horizontalPosition;
/**
- * Return the region for the visible parts of the selection, in device pixels.
+ * Return the region for the visible parts of the selection, in device pixels
*/
readonly attribute nsIScriptableRegion selectionRegion;
/**
* Get the index of the first visible row.
*/
long getFirstVisibleRow();
@@ -70,110 +74,125 @@ interface nsITreeBoxObject : nsISupports
/**
* Gets the number of possible visible rows.
*/
long getPageLength();
/**
* Ensures that a row at a given index is visible.
*/
- void ensureRowIsVisible(in long index);
+ void ensureRowIsVisible(long index);
/**
* Ensures that a given cell in the tree is visible.
*/
- void ensureCellIsVisible(in long row, in nsITreeColumn col);
+ void ensureCellIsVisible(long row, MozTreeColumn? col);
/**
* Scrolls such that the row at index is at the top of the visible view.
*/
- void scrollToRow(in long index);
+ void scrollToRow(long index);
/**
* Scroll the tree up or down by numLines lines. Positive
* values move down in the tree. Prevents scrolling off the
- * end of the tree.
+ * end of the tree.
*/
- void scrollByLines(in long numLines);
+ void scrollByLines(long numLines);
/**
* Scroll the tree up or down by numPages pages. A page
* is considered to be the amount displayed by the tree.
* Positive values move down in the tree. Prevents scrolling
* off the end of the tree.
*/
- void scrollByPages(in long numPages);
-
- /**
- * Scrolls such that a given cell is visible (if possible)
- * at the top left corner of the visible view.
- */
- void scrollToCell(in long row, in nsITreeColumn col);
+ void scrollByPages(long numPages);
/**
- * Scrolls horizontally so that the specified column is
+ * Scrolls such that a given cell is visible (if possible)
+ * at the top left corner of the visible view.
+ */
+ void scrollToCell(long row, MozTreeColumn? col);
+
+ /**
+ * Scrolls horizontally so that the specified column is
* at the left of the view (if possible).
*/
- void scrollToColumn(in nsITreeColumn col);
+ void scrollToColumn(MozTreeColumn? col);
/**
* Scroll to a specific horizontal pixel position.
*/
- void scrollToHorizontalPosition(in long horizontalPosition);
+ void scrollToHorizontalPosition(long horizontalPosition);
/**
* Invalidation methods for fine-grained painting control.
*/
void invalidate();
- void invalidateColumn(in nsITreeColumn col);
- void invalidateRow(in long index);
- void invalidateCell(in long row, in nsITreeColumn col);
- void invalidateRange(in long startIndex, in long endIndex);
- void invalidateColumnRange(in long startIndex, in long endIndex,
- in nsITreeColumn col);
+ void invalidateColumn(MozTreeColumn? col);
+ void invalidateRow(long index);
+ void invalidateCell(long row, MozTreeColumn? col);
+ void invalidateRange(long startIndex, long endIndex);
+ void invalidateColumnRange(long startIndex, long endIndex, MozTreeColumn? col);
/**
* A hit test that can tell you what row the mouse is over.
* returns -1 for invalid mouse coordinates.
*
* The coordinate system is the client coordinate system for the
* document this boxObject lives in, and the units are CSS pixels.
*/
- long getRowAt(in long x, in long y);
+ long getRowAt(long x, long y);
/**
- * A hit test that can tell you what cell the mouse is over. Row is the row index
- * hit, returns -1 for invalid mouse coordinates. ColID is the column hit.
- * ChildElt is the pseudoelement hit: this can have values of
+ * A hit test that can tell you what cell the mouse is over.
+ * TreeCellInfo.row is the row index hit, returns -1 for invalid mouse
+ * coordinates. TreeCellInfo.col is the column hit.
+ * TreeCellInfo.childElt is the pseudoelement hit: this can have values of
* "cell", "twisty", "image", and "text".
*
* The coordinate system is the client coordinate system for the
* document this boxObject lives in, and the units are CSS pixels.
*/
- void getCellAt(in long x, in long y, out long row, out nsITreeColumn col, out ACString childElt);
+ [Throws]
+ TreeCellInfo getCellAt(long x, long y);
- /**
- * Find the coordinates of an element within a specific cell.
+ /**
+ * DEPRECATED: please use above version
+ */
+ [Throws]
+ void getCellAt(long x, long y, object row, object column, object childElt);
+
+ /**
+ * Find the coordinates of an element within a specific cell.
*/
- void getCoordsForCellItem(in long row, in nsITreeColumn col, in ACString element,
- out long x, out long y, out long width, out long height);
+ [Throws]
+ DOMRect? getCoordsForCellItem(long row, MozTreeColumn col, DOMString element);
- /**
+ /**
+ * DEPRECATED: Please use above version
+ */
+ [Throws]
+ void getCoordsForCellItem(long row, MozTreeColumn col, DOMString element,
+ object x, object y, object width, object height);
+
+ /**
* Determine if the text of a cell is being cropped or not.
*/
- boolean isCellCropped(in long row, in nsITreeColumn col);
+ [Throws]
+ boolean isCellCropped(long row, MozTreeColumn? col);
/**
* The view is responsible for calling these notification methods when
* rows are added or removed. Index is the position at which the new
* rows were added or at which rows were removed. For
* non-contiguous additions/removals, this method should be called multiple times.
*/
- void rowCountChanged(in long index, in long count);
-
+ void rowCountChanged(long index, long count);
+
/**
* Notify the tree that the view is about to perform a batch
* update, that is, add, remove or invalidate several rows at once.
* This must be followed by calling endUpdateBatch(), otherwise the tree
* will get out of sync.
*/
void beginUpdateBatch();
--- a/dom/webidl/TreeColumns.webidl
+++ b/dom/webidl/TreeColumns.webidl
@@ -1,21 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-interface MozTreeBoxObject;
interface MozTreeColumn;
[Func="IsChromeOrXBL"]
interface TreeColumns {
/**
* The tree widget for these columns.
*/
- readonly attribute MozTreeBoxObject? tree;
+ readonly attribute TreeBoxObject? tree;
/**
* The number of columns.
*/
readonly attribute unsigned long count;
/**
* An alias for count (for the benefit of scripts which treat this as an
--- a/dom/webidl/XULDocument.webidl
+++ b/dom/webidl/XULDocument.webidl
@@ -3,17 +3,16 @@
* 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/.
*
* The origin of this IDL file is:
* dom/interfaces/xul/nsIDOMXULDocument.idl
*/
interface XULCommandDispatcher;
-interface MozBoxObject;
interface MozObserver;
[Func="IsChromeOrXBL"]
interface XULDocument : Document {
attribute Node? popupNode;
/**
* These attributes correspond to trustedGetPopupNode().rangeOffset and
@@ -46,13 +45,13 @@ interface XULDocument : Document {
DOMString attr);
void removeBroadcastListenerFor(Element broadcaster, Element observer,
DOMString attr);
[Throws]
void persist([TreatNullAs=EmptyString] DOMString id, DOMString attr);
[Throws]
- MozBoxObject? getBoxObjectFor(Element? element);
+ BoxObject? getBoxObjectFor(Element? element);
[Throws]
void loadOverlay(DOMString url, MozObserver? observer);
};
--- a/dom/webidl/XULElement.webidl
+++ b/dom/webidl/XULElement.webidl
@@ -1,15 +1,14 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-interface MozBoxObject;
interface MozControllers;
interface MozFrameLoader;
interface MozRDFCompositeDataSource;
interface MozRDFResource;
interface MozXULTemplateBuilder;
[Func="IsChromeOrXBL"]
interface XULElement : Element {
@@ -90,17 +89,17 @@ interface XULElement : Element {
readonly attribute MozRDFCompositeDataSource? database;
readonly attribute MozXULTemplateBuilder? builder;
[Throws]
readonly attribute MozRDFResource? resource;
[Throws]
readonly attribute MozControllers controllers;
[Throws]
- readonly attribute MozBoxObject? boxObject;
+ readonly attribute BoxObject? boxObject;
[Throws]
void focus();
[Throws]
void blur();
[Throws]
void click();
void doCommand();
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -48,16 +48,17 @@ WEBIDL_FILES = [
'AudioTrackList.webidl',
'AutocompleteInfo.webidl',
'BarProp.webidl',
'BatteryManager.webidl',
'BeforeAfterKeyboardEvent.webidl',
'BeforeUnloadEvent.webidl',
'BiquadFilterNode.webidl',
'Blob.webidl',
+ 'BoxObject.webidl',
'BrowserElementDictionaries.webidl',
'CallsList.webidl',
'CameraCapabilities.webidl',
'CameraControl.webidl',
'CameraManager.webidl',
'CameraUtil.webidl',
'CanvasRenderingContext2D.webidl',
'CaretPosition.webidl',
@@ -69,16 +70,17 @@ WEBIDL_FILES = [
'ChromeNotifications.webidl',
'ClipboardEvent.webidl',
'CommandEvent.webidl',
'Comment.webidl',
'CompositionEvent.webidl',
'Console.webidl',
'Constraints.webidl',
'Contacts.webidl',
+ 'ContainerBoxObject.webidl',
'ConvolverNode.webidl',
'Coordinates.webidl',
'CSPReport.webidl',
'CSS.webidl',
'CSSPrimitiveValue.webidl',
'CSSRuleList.webidl',
'CSSStyleDeclaration.webidl',
'CSSStyleSheet.webidl',
@@ -245,29 +247,31 @@ WEBIDL_FILES = [
'InterAppConnection.webidl',
'InterAppConnectionRequest.webidl',
'InterAppMessagePort.webidl',
'KeyAlgorithm.webidl',
'KeyboardEvent.webidl',
'KeyEvent.webidl',
'LegacyQueryInterface.webidl',
'LinkStyle.webidl',
+ 'ListBoxObject.webidl',
'LocalMediaStream.webidl',
'Location.webidl',
'MediaElementAudioSourceNode.webidl',
'MediaError.webidl',
'MediaList.webidl',
'MediaQueryList.webidl',
'MediaRecorder.webidl',
'MediaSource.webidl',
'MediaStream.webidl',
'MediaStreamAudioDestinationNode.webidl',
'MediaStreamAudioSourceNode.webidl',
'MediaStreamTrack.webidl',
'MediaTrackConstraintSet.webidl',
+ 'MenuBoxObject.webidl',
'MessageChannel.webidl',
'MessageEvent.webidl',
'MessagePort.webidl',
'MessagePortList.webidl',
'MimeType.webidl',
'MimeTypeArray.webidl',
'MouseEvent.webidl',
'MouseScrollEvent.webidl',
@@ -315,16 +319,17 @@ WEBIDL_FILES = [
'PerformanceResourceTiming.webidl',
'PerformanceTiming.webidl',
'PeriodicWave.webidl',
'PermissionSettings.webidl',
'PhoneNumberService.webidl',
'Plugin.webidl',
'PluginArray.webidl',
'PointerEvent.webidl',
+ 'PopupBoxObject.webidl',
'Position.webidl',
'PositionError.webidl',
'ProcessingInstruction.webidl',
'ProfileTimelineMarker.webidl',
'Promise.webidl',
'PromiseDebugging.webidl',
'PushManager.webidl',
'RadioNodeList.webidl',
@@ -342,16 +347,17 @@ WEBIDL_FILES = [
'RTCPeerConnectionStatic.webidl',
'RTCRtpReceiver.webidl',
'RTCRtpSender.webidl',
'RTCSessionDescription.webidl',
'RTCStatsReport.webidl',
'Screen.webidl',
'ScriptProcessorNode.webidl',
'ScrollAreaEvent.webidl',
+ 'ScrollBoxObject.webidl',
'Selection.webidl',
'ServiceWorker.webidl',
'ServiceWorkerContainer.webidl',
'ServiceWorkerGlobalScope.webidl',
'ServiceWorkerRegistration.webidl',
'SettingChangeNotification.webidl',
'SettingsManager.webidl',
'ShadowRoot.webidl',
@@ -487,16 +493,17 @@ WEBIDL_FILES = [
'TextTrackCueList.webidl',
'TextTrackList.webidl',
'TimeEvent.webidl',
'TimeRanges.webidl',
'Touch.webidl',
'TouchEvent.webidl',
'TouchList.webidl',
'TransitionEvent.webidl',
+ 'TreeBoxObject.webidl',
'TreeColumns.webidl',
'TreeWalker.webidl',
'UDPMessageEvent.webidl',
'UDPSocket.webidl',
'UIEvent.webidl',
'UndoManager.webidl',
'URL.webidl',
'URLSearchParams.webidl',
--- a/dom/xslt/tests/buster/buster-handlers.js
+++ b/dom/xslt/tests/buster/buster-handlers.js
@@ -3,17 +3,17 @@
* 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/. */
var xalan_field;
function onLoad()
{
view.tree = document.getElementById('out');
- view.boxObject = view.tree.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);
+ view.boxObject = view.tree.boxObject;
{
view.mIframe = document.getElementById('hiddenHtml');
view.mIframe.webNavigation.allowPlugins = false;
view.mIframe.webNavigation.allowJavascript = false;
view.mIframe.webNavigation.allowMetaRedirects = false;
view.mIframe.webNavigation.allowImages = false;
}
view.database = view.tree.database;
--- a/editor/composer/test/test_bug434998.xul
+++ b/editor/composer/test/test_bug434998.xul
@@ -93,17 +93,17 @@ https://bugzilla.mozilla.org/show_bug.cg
mEditor: null
};
var progress, progressListener;
function runTest() {
var newEditorElement = document.getElementById("editor");
newEditorElement.makeEditable("html", true);
- var docShell = newEditorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+ var docShell = newEditorElement.boxObject.docShell;
progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
progressListener = new EditorContentListener(newEditorElement);
progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
newEditorElement.setAttribute("src", "data:text/html,");
}
]]>
</script>
</window>
--- a/editor/libeditor/tests/test_bug607584.xul
+++ b/editor/libeditor/tests/test_bug607584.xul
@@ -99,17 +99,17 @@ https://bugzilla.mozilla.org/show_bug.cg
mEditor: null
};
var progress, progressListener;
function runTest() {
var newEditorElement = document.getElementById("editor");
newEditorElement.makeEditable("html", true);
- var docShell = newEditorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+ var docShell = newEditorElement.boxObject.docShell;
progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
progressListener = new EditorContentListener(newEditorElement);
progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
newEditorElement.setAttribute("src", "data:text/html,");
}
]]>
</script>
</window>
--- a/editor/libeditor/tests/test_bug616590.xul
+++ b/editor/libeditor/tests/test_bug616590.xul
@@ -89,17 +89,17 @@ https://bugzilla.mozilla.org/show_bug.cg
mEditor: null
};
var progress, progressListener;
function runTest() {
var editorElement = document.getElementById("editor");
editorElement.makeEditable("htmlmail", true);
- var docShell = editorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+ var docShell = editorElement.boxObject.docShell;
progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
progressListener = new EditorContentListener(editorElement);
progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
editorElement.setAttribute("src", "data:text/html,");
}
]]>
</script>
</window>
--- a/editor/libeditor/tests/test_bug780908.xul
+++ b/editor/libeditor/tests/test_bug780908.xul
@@ -97,17 +97,17 @@ adapted from test_bug607584.xul by Kent
mEditor: null
};
var progress, progressListener;
function runTest() {
var newEditorElement = document.getElementById("editor");
newEditorElement.makeEditable("html", true);
- var docShell = newEditorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+ var docShell = newEditorElement.boxObject.docShell;
progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
progressListener = new EditorContentListener(newEditorElement);
progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
newEditorElement.setAttribute("src", "data:text/html,");
}
]]>
</script>
</window>
--- a/extensions/cookie/test/unit/test_permmanager_defaults.js
+++ b/extensions/cookie/test/unit/test_permmanager_defaults.js
@@ -1,15 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// The origin we use in most of the tests.
const TEST_ORIGIN = "example.org";
const TEST_ORIGIN_2 = "example.com";
const TEST_PERMISSION = "test-permission";
+Components.utils.import("resource://gre/modules/Promise.jsm");
function promiseTimeout(delay) {
let deferred = Promise.defer();
do_timeout(delay, deferred.resolve);
return deferred.promise;
}
function run_test() {
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -79,16 +79,17 @@ static const char *sExtensionNames[] = {
"GL_ARB_copy_buffer",
"GL_ARB_depth_texture",
"GL_ARB_draw_buffers",
"GL_ARB_draw_instanced",
"GL_ARB_framebuffer_object",
"GL_ARB_framebuffer_sRGB",
"GL_ARB_half_float_pixel",
"GL_ARB_instanced_arrays",
+ "GL_ARB_invalidate_subdata",
"GL_ARB_map_buffer_range",
"GL_ARB_occlusion_query2",
"GL_ARB_pixel_buffer_object",
"GL_ARB_robustness",
"GL_ARB_sampler_objects",
"GL_ARB_sync",
"GL_ARB_texture_compression",
"GL_ARB_texture_float",
@@ -1351,16 +1352,31 @@ GLContext::InitWithPrefix(const char *pr
if (!LoadSymbols(&umnSymbols[0], trygl, prefix)) {
NS_ERROR("GL supports uniform matrix with non-square dim without supplying its functions.");
MarkUnsupported(GLFeature::uniform_matrix_nonsquare);
ClearSymbols(umnSymbols);
}
}
+ if (IsSupported(GLFeature::invalidate_framebuffer)) {
+ SymLoadStruct invSymbols[] = {
+ { (PRFuncPtr *) &mSymbols.fInvalidateFramebuffer, { "InvalidateFramebuffer", nullptr } },
+ { (PRFuncPtr *) &mSymbols.fInvalidateSubFramebuffer, { "InvalidateSubFramebuffer", nullptr } },
+ END_SYMBOLS
+ };
+
+ if (!LoadSymbols(&invSymbols[0], trygl, prefix)) {
+ NS_ERROR("GL supports framebuffer invalidation without supplying its functions.");
+
+ MarkUnsupported(GLFeature::invalidate_framebuffer);
+ ClearSymbols(invSymbols);
+ }
+ }
+
if (IsExtensionSupported(KHR_debug)) {
SymLoadStruct extSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fDebugMessageControl, { "DebugMessageControl", "DebugMessageControlKHR", nullptr } },
{ (PRFuncPtr*) &mSymbols.fDebugMessageInsert, { "DebugMessageInsert", "DebugMessageInsertKHR", nullptr } },
{ (PRFuncPtr*) &mSymbols.fDebugMessageCallback, { "DebugMessageCallback", "DebugMessageCallbackKHR", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetDebugMessageLog, { "GetDebugMessageLog", "GetDebugMessageLogKHR", nullptr } },
{ (PRFuncPtr*) &mSymbols.fGetPointerv, { "GetPointerv", "GetPointervKHR", nullptr } },
{ (PRFuncPtr*) &mSymbols.fPushDebugGroup, { "PushDebugGroup", "PushDebugGroupKHR", nullptr } },
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -38,16 +38,17 @@
#include "GLContextTypes.h"
#include "GLTextureImage.h"
#include "SurfaceTypes.h"
#include "GLScreenBuffer.h"
#include "GLContextSymbols.h"
#include "base/platform_thread.h" // for PlatformThreadId
#include "mozilla/GenericRefCounted.h"
#include "gfx2DGlue.h"
+#include "GeckoProfiler.h"
class nsIntRegion;
class nsIRunnable;
class nsIThread;
namespace android {
class GraphicBuffer;
}
@@ -95,16 +96,17 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
framebuffer_multisample,
framebuffer_object,
get_integer_indexed,
get_integer64_indexed,
get_query_object_iv,
gpu_shader4,
instanced_arrays,
instanced_non_arrays,
+ invalidate_framebuffer,
map_buffer_range,
occlusion_query,
occlusion_query_boolean,
occlusion_query2,
packed_depth_stencil,
query_objects,
renderbuffer_color_float,
renderbuffer_color_half_float,
@@ -362,16 +364,17 @@ public:
ARB_copy_buffer,
ARB_depth_texture,
ARB_draw_buffers,
ARB_draw_instanced,
ARB_framebuffer_object,
ARB_framebuffer_sRGB,
ARB_half_float_pixel,
ARB_instanced_arrays,
+ ARB_invalidate_subdata,
ARB_map_buffer_range,
ARB_occlusion_query2,
ARB_pixel_buffer_object,
ARB_robustness,
ARB_sampler_objects,
ARB_sync,
ARB_texture_compression,
ARB_texture_float,
@@ -759,36 +762,49 @@ private:
GLContext *tip = this;
while (tip->mSharedContext)
tip = tip->mSharedContext;
return tip;
}
static void AssertNotPassingStackBufferToTheGL(const void* ptr);
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL \
+ PROFILER_LABEL_FUNC( \
+ js::ProfileEntry::Category::GRAPHICS);\
+ BeforeGLCall(MOZ_FUNCTION_NAME)
+#else
#define BEFORE_GL_CALL \
do { \
BeforeGLCall(MOZ_FUNCTION_NAME); \
} while (0)
+#endif
#define AFTER_GL_CALL \
do { \
AfterGLCall(MOZ_FUNCTION_NAME); \
} while (0)
#define TRACKING_CONTEXT(a) \
do { \
TrackingContext()->a; \
} while (0)
#define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) AssertNotPassingStackBufferToTheGL(ptr)
#else // ifdef DEBUG
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS)
+#else
#define BEFORE_GL_CALL do { } while (0)
+#endif
#define AFTER_GL_CALL do { } while (0)
#define TRACKING_CONTEXT(a) do {} while (0)
#define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) do {} while (0)
#endif // ifdef DEBUG
#define ASSERT_SYMBOL_PRESENT(func) \
do {\
@@ -885,16 +901,30 @@ public:
default:
// Nothing we care about, likely an error.
break;
}
raw_fBindFramebuffer(target, framebuffer);
}
+ void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) {
+ BEFORE_GL_CALL;
+ ASSERT_SYMBOL_PRESENT(fInvalidateFramebuffer);
+ mSymbols.fInvalidateFramebuffer(target, numAttachments, attachments);
+ AFTER_GL_CALL;
+ }
+
+ void fInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) {
+ BEFORE_GL_CALL;
+ ASSERT_SYMBOL_PRESENT(fInvalidateSubFramebuffer);
+ mSymbols.fInvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
+ AFTER_GL_CALL;
+ }
+
void fBindTexture(GLenum target, GLuint texture) {
BEFORE_GL_CALL;
mSymbols.fBindTexture(target, texture);
AFTER_GL_CALL;
}
void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
BEFORE_GL_CALL;
@@ -3532,16 +3562,20 @@ public:
/* Clear to transparent black, with 0 depth and stencil,
* while preserving current ClearColor etc. values.
* Useful for resizing offscreen buffers.
*/
void ClearSafely();
bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
+ bool IsDrawingToDefaultFramebuffer() {
+ return Screen()->IsDrawFramebufferDefault();
+ }
+
protected:
nsRefPtr<TextureGarbageBin> mTexGarbageBin;
public:
TextureGarbageBin* TexGarbageBin() {
MOZ_ASSERT(mTexGarbageBin);
return mTexGarbageBin;
}
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -284,16 +284,25 @@ static const FeatureInfo sFeatureInfoArr
}
/* This is an expanded version of `instanced_arrays` that allows for all
* enabled active attrib arrays to have non-zero divisors.
* ANGLE_instanced_arrays and NV_instanced_arrays forbid this, but GLES3
* has no such restriction.
*/
},
{
+ "invalidate_framebuffer",
+ 430, // OpenGL version
+ 300, // OpenGL ES version
+ GLContext::ARB_invalidate_subdata,
+ {
+ GLContext::Extensions_End
+ }
+ },
+ {
"map_buffer_range",
300, // OpenGL version
300, // OpenGL ES version
GLContext::ARB_map_buffer_range,
{
GLContext::Extensions_End
}
},
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -329,16 +329,21 @@ struct GLContextSymbols
PFNGLISFRAMEBUFFER fIsFramebuffer;
typedef realGLboolean (GLAPIENTRY * PFNGLISRENDERBUFFER) (GLuint renderbuffer);
PFNGLISRENDERBUFFER fIsRenderbuffer;
typedef realGLboolean (GLAPIENTRY * PFNGLISVERTEXARRAY) (GLuint array);
PFNGLISVERTEXARRAY fIsVertexArray;
typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
+ typedef void (GLAPIENTRY * PFNINVALIDATEFRAMEBUFFER) (GLenum target, GLsizei numAttachments, const GLenum* attachments);
+ PFNINVALIDATEFRAMEBUFFER fInvalidateFramebuffer;
+ typedef void (GLAPIENTRY * PFNINVALIDATESUBFRAMEBUFFER) (GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+ PFNINVALIDATESUBFRAMEBUFFER fInvalidateSubFramebuffer;
+
// These functions are only used by Skia/GL in desktop mode.
// Other parts of Gecko should avoid using these
typedef void (GLAPIENTRY * PFNGLCLIENTACTIVETEXTURE) (GLenum texture);
PFNGLCLIENTACTIVETEXTURE fClientActiveTexture;
typedef void (GLAPIENTRY * PFNDISABLECLIENTSTATE) (GLenum capability);
PFNDISABLECLIENTSTATE fDisableClientState;
typedef void (GLAPIENTRY * PFNENABLECLIENTSTATE) (GLenum capability);
PFNENABLECLIENTSTATE fEnableClientState;
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -7,16 +7,17 @@
#if defined(MOZ_X11)
#include "mozilla/X11Util.h"
#endif
#include "GLLibraryLoader.h"
#include "mozilla/ThreadLocal.h"
#include "nsIFile.h"
+#include "GeckoProfiler.h"
#include <bitset>
#if defined(XP_WIN)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
@@ -70,27 +71,38 @@ namespace gl {
# define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__
# elif defined(_MSC_VER)
# define MOZ_FUNCTION_NAME __FUNCTION__
# else
# define MOZ_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name.
# endif
#endif
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL \
+ PROFILER_LABEL_FUNC( \
+ js::ProfileEntry::Category::GRAPHICS);\
+ BeforeGLCall(MOZ_FUNCTION_NAME)
+#else
#define BEFORE_GL_CALL do { \
BeforeGLCall(MOZ_FUNCTION_NAME); \
} while (0)
+#endif
#define AFTER_GL_CALL do { \
AfterGLCall(MOZ_FUNCTION_NAME); \
} while (0)
-// We rely on the fact that GLLibraryEGL.h #defines BEFORE_GL_CALL and
-// AFTER_GL_CALL to nothing if !defined(DEBUG).
+#else
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS)
#else
#define BEFORE_GL_CALL
+#endif
#define AFTER_GL_CALL
#endif
class GLLibraryEGL
{
public:
GLLibraryEGL()
: mInitialized(false),
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -524,16 +524,30 @@ GLScreenBuffer::Readback(SharedSurface*
}
if (needsSwap) {
src->UnlockProd();
SharedSurf()->LockProd();
}
}
+bool
+GLScreenBuffer::IsDrawFramebufferDefault() const
+{
+ if (!mDraw)
+ return IsReadFramebufferDefault();
+ return mDraw->mFB == 0;
+}
+
+bool
+GLScreenBuffer::IsReadFramebufferDefault() const
+{
+ return SharedSurf()->mAttachType == AttachmentType::Screen;
+}
+
////////////////////////////////////////////////////////////////////////
// DrawBuffer
bool
DrawBuffer::Create(GLContext* const gl,
const SurfaceCaps& caps,
const GLFormats& formats,
const gfx::IntSize& size,
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -256,14 +256,17 @@ public:
GLuint GetDrawFB() const;
GLuint GetReadFB() const;
// Here `fb` is the actual framebuffer you want bound. Binding 0 will
// bind the (generally useless) default framebuffer.
void BindFB_Internal(GLuint fb);
void BindDrawFB_Internal(GLuint fb);
void BindReadFB_Internal(GLuint fb);
+
+ bool IsDrawFramebufferDefault() const;
+ bool IsReadFramebufferDefault() const;
};
} // namespace gl
} // namespace mozilla
#endif // SCREEN_BUFFER_H_
--- a/gfx/gl/SharedSurface.cpp
+++ b/gfx/gl/SharedSurface.cpp
@@ -1,17 +1,19 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedSurface.h"
+#include "../2d/2D.h"
#include "GLBlitHelper.h"
#include "GLContext.h"
+#include "GLReadTexImageHelper.h"
#include "nsThreadUtils.h"
#include "ScopedGLHelpers.h"
#include "SharedSurfaceGL.h"
namespace mozilla {
namespace gl {
/*static*/ void
@@ -442,10 +444,111 @@ ScopedReadbackFB::~ScopedReadbackFB()
if (mSurfToUnlock) {
mSurfToUnlock->UnlockProd();
}
if (mSurfToLock) {
mSurfToLock->LockProd();
}
}
+////////////////////////////////////////////////////////////////////////////////
+
+class AutoLockBits
+{
+ gfx::DrawTarget* mDT;
+ uint8_t* mLockedBits;
+
+public:
+ AutoLockBits(gfx::DrawTarget* dt)
+ : mDT(dt)
+ , mLockedBits(nullptr)
+ {
+ MOZ_ASSERT(mDT);
+ }
+
+ bool Lock(uint8_t** data, gfx::IntSize* size, int32_t* stride,
+ gfx::SurfaceFormat* format)
+ {
+ bool success = mDT->LockBits(data, size, stride, format);
+ if (success)
+ mLockedBits = *data;
+ return success;
+ }
+
+ ~AutoLockBits() {
+ if (mLockedBits)
+ mDT->ReleaseBits(mLockedBits);
+ }
+};
+
+bool
+ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst)
+{
+ AutoLockBits lock(dst);
+
+ uint8_t* dstBytes;
+ gfx::IntSize dstSize;
+ int32_t dstStride;
+ gfx::SurfaceFormat dstFormat;
+ if (!dst->LockBits(&dstBytes, &dstSize, &dstStride, &dstFormat))
+ return false;
+
+ const bool isDstRGBA = (dstFormat == gfx::SurfaceFormat::R8G8B8A8 ||
+ dstFormat == gfx::SurfaceFormat::R8G8B8X8);
+ MOZ_ASSERT_IF(!isDstRGBA, dstFormat == gfx::SurfaceFormat::B8G8R8A8 ||
+ dstFormat == gfx::SurfaceFormat::B8G8R8X8);
+
+ size_t width = src->mSize.width;
+ size_t height = src->mSize.height;
+ MOZ_ASSERT(width == (size_t)dstSize.width);
+ MOZ_ASSERT(height == (size_t)dstSize.height);
+
+ GLenum readGLFormat;
+ GLenum readType;
+
+ {
+ ScopedReadbackFB autoReadback(src);
+
+
+ // We have a source FB, now we need a format.
+ GLenum dstGLFormat = isDstRGBA ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
+ GLenum dstType = LOCAL_GL_UNSIGNED_BYTE;
+
+ // We actually don't care if they match, since we can handle
+ // any read{Format,Type} we get.
+ GLContext* gl = src->mGL;
+ GetActualReadFormats(gl, dstGLFormat, dstType, &readGLFormat,
+ &readType);
+
+ MOZ_ASSERT(readGLFormat == LOCAL_GL_RGBA ||
+ readGLFormat == LOCAL_GL_BGRA);
+ MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
+
+ // ReadPixels from the current FB into lockedBits.
+ {
+ size_t alignment = 8;
+ if (dstStride % 4 == 0)
+ alignment = 4;
+ ScopedPackAlignment autoAlign(gl, alignment);
+
+ gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType,
+ dstBytes);
+ }
+ }
+
+ const bool isReadRGBA = readGLFormat == LOCAL_GL_RGBA;
+
+ if (isReadRGBA != isDstRGBA) {
+ for (size_t j = 0; j < height; ++j) {
+ uint8_t* rowItr = dstBytes + j*dstStride;
+ uint8_t* rowEnd = rowItr + 4*width;
+ while (rowItr != rowEnd) {
+ Swap(rowItr[0], rowItr[2]);
+ rowItr += 4;
+ }
+ }
+ }
+
+ return true;
+}
+
} /* namespace gfx */
} /* namespace mozilla */
--- a/gfx/gl/SharedSurface.h
+++ b/gfx/gl/SharedSurface.h
@@ -26,16 +26,19 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "ScopedGLHelpers.h"
#include "SurfaceTypes.h"
class nsIThread;
namespace mozilla {
+namespace gfx {
+class DrawTarget;
+}
namespace gl {
class GLContext;
class SurfaceFactory;
class ShSurfHandle;
class SharedSurface
{
@@ -248,12 +251,14 @@ class ScopedReadbackFB
SharedSurface* mSurfToUnlock;
SharedSurface* mSurfToLock;
public:
ScopedReadbackFB(SharedSurface* src);
~ScopedReadbackFB();
};
+bool ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst);
+
} // namespace gl
} // namespace mozilla
#endif // SHARED_SURFACE_H_
--- a/gfx/gl/SharedSurfaceGL.cpp
+++ b/gfx/gl/SharedSurfaceGL.cpp
@@ -78,85 +78,29 @@ SharedSurface_Basic::SharedSurface_Basic
mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_TEXTURE_2D,
mTex,
0);
DebugOnly<GLenum> status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
-
- int32_t stride = gfx::GetAlignedStride<4>(size.width * BytesPerPixel(format));
- mData = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
- // Leave the extra return for clarity, in case we decide more code should
- // be added after this check, that should run even if mData is null.
- if (NS_WARN_IF(!mData)) {
- return;
- }
}
SharedSurface_Basic::~SharedSurface_Basic()
{
if (!mGL->MakeCurrent())
return;
if (mFB)
mGL->fDeleteFramebuffers(1, &mFB);
mGL->fDeleteTextures(1, &mTex);
}
-void
-SharedSurface_Basic::Fence()
-{
- // The constructor can fail to get us mData, we should deal with it:
- if (NS_WARN_IF(!mData)) {
- return;
- }
-
- mGL->MakeCurrent();
- ScopedBindFramebuffer autoFB(mGL, mFB);
- ReadPixelsIntoDataSurface(mGL, mData);
-}
-
-bool
-SharedSurface_Basic::WaitSync()
-{
- return true;
-}
-
-bool
-SharedSurface_Basic::PollSync()
-{
- return true;
-}
-
-void
-SharedSurface_Basic::Fence_ContentThread_Impl()
-{
-}
-
-bool
-SharedSurface_Basic::WaitSync_ContentThread_Impl()
-{
- mGL->MakeCurrent();
- ScopedBindFramebuffer autoFB(mGL, mFB);
- ReadPixelsIntoDataSurface(mGL, mData);
- return true;
-}
-
-bool
-SharedSurface_Basic::PollSync_ContentThread_Impl()
-{
- mGL->MakeCurrent();
- ScopedBindFramebuffer autoFB(mGL, mFB);
- ReadPixelsIntoDataSurface(mGL, mData);
- return true;
-}
-
////////////////////////////////////////////////////////////////////////
// SharedSurface_GLTexture
/*static*/ UniquePtr<SharedSurface_GLTexture>
SharedSurface_GLTexture::Create(GLContext* prodGL,
GLContext* consGL,
const GLFormats& formats,
const IntSize& size,
--- a/gfx/gl/SharedSurfaceGL.h
+++ b/gfx/gl/SharedSurfaceGL.h
@@ -42,47 +42,36 @@ public:
MOZ_ASSERT(surf->mType == SharedSurfaceType::Basic);
return (SharedSurface_Basic*)surf;
}
protected:
const GLuint mTex;
GLuint mFB;
- RefPtr<gfx::DataSourceSurface> mData;
SharedSurface_Basic(GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha,
gfx::SurfaceFormat format,
GLuint tex);
public:
virtual ~SharedSurface_Basic();
virtual void LockProdImpl() MOZ_OVERRIDE {}
virtual void UnlockProdImpl() MOZ_OVERRIDE {}
-
- virtual void Fence() MOZ_OVERRIDE;
- virtual bool WaitSync() MOZ_OVERRIDE;
- virtual bool PollSync() MOZ_OVERRIDE;
-
- virtual void Fence_ContentThread_Impl() MOZ_OVERRIDE;
- virtual bool WaitSync_ContentThread_Impl() MOZ_OVERRIDE;
- virtual bool PollSync_ContentThread_Impl() MOZ_OVERRIDE;
+ virtual void Fence() MOZ_OVERRIDE {}
+ virtual bool WaitSync() MOZ_OVERRIDE { return true; }
+ virtual bool PollSync() MOZ_OVERRIDE { return true; }
virtual GLuint ProdTexture() MOZ_OVERRIDE {
return mTex;
}
-
- // Implementation-specific functions below:
- gfx::DataSourceSurface* GetData() {
- return mData;
- }
};
class SurfaceFactory_Basic
: public SurfaceFactory
{
public:
SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps)
: SurfaceFactory(gl, SharedSurfaceType::Basic, caps)
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -111,99 +111,70 @@ CanvasLayerD3D10::UpdateSurface()
} else if (mIsD2DTexture) {
return;
}
if (!mTexture) {
return;
}
+ SharedSurface* surf = nullptr;
if (mGLContext) {
auto screen = mGLContext->Screen();
MOZ_ASSERT(screen);
- SharedSurface* surf = screen->Front()->Surf();
+ surf = screen->Front()->Surf();
if (!surf)
return;
surf->WaitSync();
- switch (surf->mType) {
- case SharedSurfaceType::EGLSurfaceANGLE: {
- SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
- HANDLE shareHandle = shareSurf->GetShareHandle();
-
- HRESULT hr = device()->OpenSharedResource(shareHandle,
- __uuidof(ID3D10Texture2D),
- getter_AddRefs(mTexture));
- if (FAILED(hr))
- return;
+ if (surf->mType == SharedSurfaceType::EGLSurfaceANGLE) {
+ SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
+ HANDLE shareHandle = shareSurf->GetShareHandle();
- hr = device()->CreateShaderResourceView(mTexture,
- nullptr,
- getter_AddRefs(mSRView));
- if (FAILED(hr))
- return;
-
+ HRESULT hr = device()->OpenSharedResource(shareHandle,
+ __uuidof(ID3D10Texture2D),
+ getter_AddRefs(mTexture));
+ if (FAILED(hr))
return;
- }
- case SharedSurfaceType::Basic: {
- SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
- // WebGL reads entire surface.
- D3D10_MAPPED_TEXTURE2D map;
- HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
+ hr = device()->CreateShaderResourceView(mTexture,
+ nullptr,
+ getter_AddRefs(mSRView));
+ if (FAILED(hr))
+ return;
- if (FAILED(hr)) {
- NS_WARNING("Failed to map CanvasLayer texture.");
- return;
- }
+ return;
+ }
+ }
+
+ D3D10_MAPPED_TEXTURE2D map;
+ HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
- DataSourceSurface* frameData = shareSurf->GetData();
- // Scope for DrawTarget, so it's destroyed before Unmap.
- {
- IntSize boundsSize(mBounds.width, mBounds.height);
- RefPtr<DrawTarget> mapDt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
- (uint8_t*)map.pData,
- boundsSize,
- map.RowPitch,
- SurfaceFormat::B8G8R8A8);
+ if (FAILED(hr)) {
+ NS_WARNING("Failed to lock CanvasLayer texture.");
+ return;
+ }
- Rect drawRect(0, 0, frameData->GetSize().width, frameData->GetSize().height);
- mapDt->DrawSurface(frameData, drawRect, drawRect,
- DrawSurfaceOptions(), DrawOptions(1.0F, CompositionOp::OP_SOURCE));
- mapDt->Flush();
- }
+ RefPtr<DrawTarget> destTarget =
+ Factory::CreateDrawTargetForD3D10Texture(mTexture,
+ SurfaceFormat::R8G8B8A8);
- mTexture->Unmap(0);
- mSRView = mUploadSRView;
- break;
- }
-
- default:
- MOZ_CRASH("Unhandled SharedSurfaceType.");
+ if (surf) {
+ if (!ReadbackSharedSurface(surf, destTarget)) {
+ NS_WARNING("Failed to readback into texture.");
}
} else if (mSurface) {
- D3D10_MAPPED_TEXTURE2D map;
- HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
-
- if (FAILED(hr)) {
- NS_WARNING("Failed to lock CanvasLayer texture.");
- return;
- }
-
- RefPtr<DrawTarget> destTarget =
- Factory::CreateDrawTargetForD3D10Texture(mTexture,
- SurfaceFormat::R8G8B8A8);
Rect r(Point(0, 0), ToRect(mBounds).Size());
destTarget->DrawSurface(mSurface, r, r, DrawSurfaceOptions(),
DrawOptions(1.0F, CompositionOp::OP_SOURCE));
+ }
- mTexture->Unmap(0);
- mSRView = mUploadSRView;
- }
+ mTexture->Unmap(0);
+ mSRView = mUploadSRView;
}
Layer*
CanvasLayerD3D10::GetLayer()
{
return this;
}
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -71,52 +71,52 @@ CanvasLayerD3D9::UpdateSurface()
CreateTexture();
if (!mTexture) {
NS_WARNING("CanvasLayerD3D9::Updated called but no texture present and creation failed!");
return;
}
}
- RefPtr<SourceSurface> surface;
-
- if (mGLContext) {
- auto screen = mGLContext->Screen();
- MOZ_ASSERT(screen);
-
- SharedSurface* surf = screen->Front()->Surf();
- if (!surf)
- return;
- surf->WaitSync();
-
- SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
- surface = shareSurf->GetData();
- } else {
- surface = mDrawTarget->Snapshot();
- }
-
// WebGL reads entire surface.
LockTextureRectD3D9 textureLock(mTexture);
if (!textureLock.HasLock()) {
NS_WARNING("Failed to lock CanvasLayer texture.");
return;
}
D3DLOCKED_RECT rect = textureLock.GetLockRect();
IntSize boundsSize(mBounds.width, mBounds.height);
RefPtr<DrawTarget> rectDt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
(uint8_t*)rect.pBits,
boundsSize,
rect.Pitch,
SurfaceFormat::B8G8R8A8);
- Rect drawRect(0, 0, surface->GetSize().width, surface->GetSize().height);
- rectDt->DrawSurface(surface, drawRect, drawRect,
- DrawSurfaceOptions(), DrawOptions(1.0F, CompositionOp::OP_SOURCE));
- rectDt->Flush();
+ if (mGLContext) {
+ auto screen = mGLContext->Screen();
+ MOZ_ASSERT(screen);
+
+ SharedSurface* surf = screen->Front()->Surf();
+ if (!surf)
+ return;
+ surf->WaitSync();
+
+ if (!ReadbackSharedSurface(surf, rectDt)) {
+ NS_WARNING("Failed to readback into texture.");
+ }
+ } else {
+ RefPtr<SourceSurface> surface = mDrawTarget->Snapshot();
+
+ Rect drawRect(0, 0, surface->GetSize().width, surface->GetSize().height);
+ rectDt->DrawSurface(surface, drawRect, drawRect,
+ DrawSurfaceOptions(), DrawOptions(1.0F, CompositionOp::OP_SOURCE));
+
+ rectDt->Flush();
+ }
}
Layer*
CanvasLayerD3D9::GetLayer()
{
return this;
}
--- a/gfx/tests/unit/test_nsIScriptableRegion.js
+++ b/gfx/tests/unit/test_nsIScriptableRegion.js
@@ -1,16 +1,10 @@
function run_test()
{
- // XXX Work around for the fact that for non-libxul builds loading gfx
- // components doesn't call up the layout initialisation routine. This should
- // be fixed/improved by bug 515595.
- Components.classes["@mozilla.org/layout/xul-boxobject-tree;1"]
- .createInstance(Components.interfaces.nsIBoxObject);
-
let rgn = Components.classes["@mozilla.org/gfx/region;1"].createInstance(Components.interfaces.nsIScriptableRegion);
do_check_true (rgn.getRects() === null)
rgn.unionRect(0,0,80,60);
do_check_true (rgn.getRects().toString() == "0,0,80,60")
rgn.unionRect(90,70,1,1);
do_check_true (rgn.getRects().toString() == "0,0,80,60,90,70,1,1")
}
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1899,17 +1899,17 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint
// vertical baseline). The adjustment here is somewhat ad hoc; we
// should eventually look for baseline tables[1] in the fonts and use
// those if available.
// [1] http://www.microsoft.com/typography/otspec/base.htm
aRunParams.context->SetMatrix(aRunParams.context->CurrentMatrix().
Translate(p). // translate origin for rotation
Rotate(M_PI / 2.0). // turn 90deg clockwise
Translate(-p). // undo the translation
- Translate(gfxPoint(0, metrics.emAscent - metrics.emDescent) / 2));
+ Translate(gfxPoint(0, (metrics.emAscent - metrics.emDescent) / 2)));
// and offset the (alphabetic) baseline of the
// horizontally-shaped text from the (centered)
// default baseline used for vertical
}
nsAutoPtr<gfxTextContextPaint> contextPaint;
if (fontParams.haveSVGGlyphs && !fontParams.contextPaint) {
// If no pattern is specified for fill, use the current pattern
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -989,16 +989,17 @@ gfxFontEntry::InputsForOpenTypeFeature(i
hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
features, featurelookups);
hb_codepoint_t index = -1;
while (hb_set_next(featurelookups, &index)) {
hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
nullptr, inputGlyphs,
nullptr, nullptr);
}
+ hb_set_destroy(featurelookups);
}
hb_face_destroy(face);
mFeatureInputs->Put(scriptFeature, inputGlyphs);
return inputGlyphs;
}
--- a/ipc/chromium/src/base/process_util_win.cc
+++ b/ipc/chromium/src/base/process_util_win.cc
@@ -12,16 +12,17 @@
#include <winternl.h>
#include <psapi.h>
#include "base/histogram.h"
#include "base/logging.h"
#include "base/win_util.h"
#include <algorithm>
+#include "prenv.h"
namespace {
// System pagesize. This value remains constant on x86/64 architectures.
const int PAGESIZE_KB = 4;
// HeapSetInformation function pointer.
typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
@@ -270,20 +271,19 @@ void FreeThreadAttributeList(LPPROC_THRE
bool LaunchApp(const std::wstring& cmdline,
bool wait, bool start_hidden, ProcessHandle* process_handle) {
// We want to inherit the std handles so dump() statements and assertion
// messages in the child process can be seen - but we *do not* want to
// blindly have all handles inherited. Vista and later has a technique
// where only specified handles are inherited - so we use this technique if
// we can. If that technique isn't available (or it fails), we just don't
- // inherit anything. This means that dump() etc isn't going to be seen on
- // XP release builds, but that's OK (developers who really care can run a
- // debug build on XP, where the processes are marked as "console" apps, so
- // things work without these hoops)
+ // inherit anything. This can cause us a problem for Windows XP testing,
+ // because we sometimes need the handles to get inherited for test logging to
+ // work. So we also inherit when a specific environment variable is set.
DWORD dwCreationFlags = 0;
BOOL bInheritHandles = FALSE;
// We use a STARTUPINFOEX, but if we can't do the thread attribute thing, we
// just pass the size of a STARTUPINFO.
STARTUPINFOEX startup_info_ex;
ZeroMemory(&startup_info_ex, sizeof(startup_info_ex));
STARTUPINFO &startup_info = startup_info_ex.StartupInfo;
startup_info.cb = sizeof(startup_info);
@@ -300,31 +300,40 @@ bool LaunchApp(const std::wstring& cmdli
HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
if (IsInheritableHandle(stdOut))
handlesToInherit[handleCount++] = stdOut;
if (stdErr != stdOut && IsInheritableHandle(stdErr))
handlesToInherit[handleCount++] = stdErr;
- if (handleCount)
+ if (handleCount) {
lpAttributeList = CreateThreadAttributeList(handlesToInherit, handleCount);
- }
-
- if (lpAttributeList) {
- // it's safe to inherit handles, so arrange for that...
- startup_info.cb = sizeof(startup_info_ex);
+ if (lpAttributeList) {
+ // it's safe to inherit handles, so arrange for that...
+ startup_info.cb = sizeof(startup_info_ex);
+ startup_info.dwFlags |= STARTF_USESTDHANDLES;
+ startup_info.hStdOutput = stdOut;
+ startup_info.hStdError = stdErr;
+ startup_info.hStdInput = INVALID_HANDLE_VALUE;
+ startup_info_ex.lpAttributeList = lpAttributeList;
+ dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
+ bInheritHandles = TRUE;
+ }
+ }
+ } else if (PR_GetEnv("MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA")) {
+ // Even if we can't limit what gets inherited, we sometimes want to inherit
+ // stdout/err for testing purposes.
startup_info.dwFlags |= STARTF_USESTDHANDLES;
startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
startup_info.hStdInput = INVALID_HANDLE_VALUE;
- startup_info_ex.lpAttributeList = lpAttributeList;
- dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
bInheritHandles = TRUE;
}
+
PROCESS_INFORMATION process_info;
BOOL createdOK = CreateProcess(NULL,
const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
bInheritHandles, dwCreationFlags, NULL, NULL,
&startup_info, &process_info);
if (lpAttributeList)
FreeThreadAttributeList(lpAttributeList);
if (!createdOK)
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -3,17 +3,16 @@ dnl Local autoconf macros used with mozi
dnl The contents of this file are under the Public Domain.
dnl
builtin(include, ../../build/autoconf/hotfixes.m4)dnl
builtin(include, ../../build/autoconf/acwinpaths.m4)dnl
builtin(include, ../../build/autoconf/hooks.m4)dnl
builtin(include, ../../build/autoconf/config.status.m4)dnl
builtin(include, ../../build/autoconf/toolchain.m4)dnl
-builtin(include, ../../build/autoconf/ccache.m4)dnl
builtin(include, ../../build/autoconf/wrapper.m4)dnl
builtin(include, ../../build/autoconf/pkg.m4)dnl
builtin(include, ../../build/autoconf/nspr.m4)dnl
builtin(include, ../../build/autoconf/nspr-build.m4)dnl
builtin(include, ../../build/autoconf/codeset.m4)dnl
builtin(include, ../../build/autoconf/altoptions.m4)dnl
builtin(include, ../../build/autoconf/mozprog.m4)dnl
builtin(include, ../../build/autoconf/mozheader.m4)dnl
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -2004,17 +2004,20 @@ IsCoercionCall(ModuleCompiler &m, ParseN
return false;
}
static bool
IsFloatLiteral(ModuleCompiler &m, ParseNode *pn)
{
ParseNode *coercedExpr;
AsmJSCoercion coercion;
- if (!IsCoercionCall(m, pn, &coercion, &coercedExpr) || coercion != AsmJS_FRound)
+ if (!IsCoercionCall(m, pn, &coercion, &coercedExpr))
+ return false;
+ // Don't fold into || to avoid clang/memcheck bug (bug 1077031).
+ if (coercion != AsmJS_FRound)
return false;
return IsNumericNonFloatLiteral(coercedExpr);
}
static unsigned
SimdTypeToLength(AsmJSSimdType type)
{
switch (type) {
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3437,18 +3437,16 @@ MOZ_ARG_ENABLE_BOOL(oom-breakpoint,
[ --enable-oom-breakpoint
Enable a breakpoint function for artificial OOMs],
JS_OOM_BREAKPOINT=1,
JS_OOM_BREAKPOINT= )
if test -n "$JS_OOM_BREAKPOINT"; then
AC_DEFINE(JS_OOM_BREAKPOINT)
fi
-MOZ_CHECK_CCACHE
-
dnl ========================================================
dnl = Enable static checking using gcc-dehydra
dnl ========================================================
MOZ_ARG_WITH_STRING(static-checking,
[ --with-static-checking=path/to/gcc_dehydra.so
Enable static checking of code using GCC-dehydra],
DEHYDRA_PATH=$withval,
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -2,18 +2,16 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef gc_GCRuntime_h
#define gc_GCRuntime_h
-#include <setjmp.h>
-
#include "jsgc.h"
#include "gc/Heap.h"
#ifdef JSGC_GENERATIONAL
# include "gc/Nursery.h"
#endif
#include "gc/Statistics.h"
#ifdef JSGC_GENERATIONAL
@@ -60,52 +58,16 @@ class ChunkPool
inline void popFront();
inline void removeAndPopFront();
private:
ChunkPool &pool;
Chunk **chunkp;
};
};
-struct ConservativeGCData
-{
- /*
- * The GC scans conservatively between ThreadData::nativeStackBase and
- * nativeStackTop unless the latter is nullptr.
- */
- uintptr_t *nativeStackTop;
-
- union {
- jmp_buf jmpbuf;
- uintptr_t words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))];
- } registerSnapshot;
-
- ConservativeGCData() {
- mozilla::PodZero(this);
- }
-
- ~ConservativeGCData() {
- /*
- * The conservative GC scanner should be disabled when the thread leaves
- * the last request.
- */
- MOZ_ASSERT(!hasStackToScan());
- }
-
- MOZ_NEVER_INLINE void recordStackTop();
-
- void updateForRequestEnd() {
- nativeStackTop = nullptr;
- }
-
- bool hasStackToScan() const {
- return !!nativeStackTop;
- }
-};
-
/*
* Encapsulates all of the GC tunables. These are effectively constant and
* should only be modified by setParameter.
*/
class GCSchedulingTunables
{
/*
* Soft limit on the number of bytes we are allowed to allocate in the GC
@@ -318,18 +280,16 @@ class GCRuntime
void setDeterministic(bool enable);
#endif
size_t maxMallocBytesAllocated() { return maxMallocBytes; }
public:
// Internal public interface
js::gc::State state() { return incrementalState; }
- void recordNativeStackTop();
- void notifyRequestEnd() { conservativeGC.updateForRequestEnd(); }
bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
void waitBackgroundSweepOrAllocEnd() { helperState.waitBackgroundSweepOrAllocEnd(); }
void startBackgroundAllocationIfIdle() { helperState.startBackgroundAllocationIfIdle(); }
#ifdef DEBUG
bool onBackgroundThread() { return helperState.onBackgroundThread(); }
@@ -865,18 +825,16 @@ class GCRuntime
GCHelperState helperState;
/*
* During incremental sweeping, this field temporarily holds the arenas of
* the current AllocKind being swept in order of increasing free space.
*/
SortedArenaList incrementalSweepList;
- ConservativeGCData conservativeGC;
-
friend class js::GCHelperState;
friend class js::gc::MarkingValidator;
friend class js::gc::AutoTraceSession;
};
#ifdef JS_GC_ZEAL
inline int
GCRuntime::zeal() {
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -129,37 +129,16 @@ MarkExactStackRoots(ThreadSafeContext* c
static void
MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
{
for (ContextIter cx(rt); !cx.done(); cx.next())
MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx.get(), trc);
MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
}
-MOZ_NEVER_INLINE void
-ConservativeGCData::recordStackTop()
-{
- /* Update the native stack pointer if it points to a bigger stack. */
- uintptr_t dummy;
- nativeStackTop = &dummy;
-
- /*
- * To record and update the register snapshot for the conservative scanning
- * with the latest values we use setjmp.
- */
-#if defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4611)
-#endif
- (void) setjmp(registerSnapshot.jmpbuf);
-#if defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-}
-
void
JS::AutoIdArray::trace(JSTracer *trc)
{
MOZ_ASSERT(tag_ == IDARRAY);
gc::MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
}
inline void
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -92,17 +92,17 @@ void
StoreBuffer::MonoTypeBuffer<T>::handleOverflow(StoreBuffer *owner)
{
if (!owner->isAboutToOverflow()) {
/*
* Compact the buffer now, and if that fails to free enough space then
* trigger a minor collection.
*/
compact(owner);
- if (isAboutToOverflow())
+ if (isLowOnSpace())
owner->setAboutToOverflow();
} else {
/*
* A minor GC has already been triggered, so there's no point
* compacting unless the buffer is totally full.
*/
if (storage_->availableInCurrentChunk() < sizeof(T))
maybeCompact(owner);
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -73,17 +73,28 @@ static const size_t LifoAllocBlockSize =
* The StoreBuffer observes all writes that occur in the system and performs
* efficient filtering of them to derive a remembered set for nursery GC.
*/
class StoreBuffer
{
friend class mozilla::ReentrancyGuard;
/* The size at which a block is about to overflow. */
- static const size_t MinAvailableSize = (size_t)(LifoAllocBlockSize * 1.0 / 8.0);
+ static const size_t LowAvailableThreshold = (size_t)(LifoAllocBlockSize * 1.0 / 16.0);
+
+ /*
+ * If the space available in the store buffer hits the
+ * LowAvailableThreshold and gets compacted, but still doesn't have at
+ * least HighAvailableThreshold space available, then we will trigger a
+ * minor GC. HighAvailableThreshold should be set to provide enough space
+ * for the mutator to run for a while in between compactions. (If
+ * HighAvailableThreshold is too low, we will thrash and spend most of the
+ * time compacting. If it is too high, we will tenure things too early.)
+ */
+ static const size_t HighAvailableThreshold = (size_t)(LifoAllocBlockSize * 1.0 / 4.0);
/*
* This buffer holds only a single type of edge. Using this buffer is more
* efficient than the generic buffer when many writes will be to the same
* type of edge: e.g. Value or Cell*.
*/
template<typename T>
struct MonoTypeBuffer
@@ -105,17 +116,21 @@ class StoreBuffer
if (!storage_)
return;
storage_->used() ? storage_->releaseAll() : storage_->freeAll();
usedAtLastCompact_ = 0;
}
bool isAboutToOverflow() const {
- return !storage_->isEmpty() && storage_->availableInCurrentChunk() < MinAvailableSize;
+ return !storage_->isEmpty() && storage_->availableInCurrentChunk() < LowAvailableThreshold;
+ }
+
+ bool isLowOnSpace() const {
+ return !storage_->isEmpty() && storage_->availableInCurrentChunk() < HighAvailableThreshold;
}
void handleOverflow(StoreBuffer *owner);
/* Compaction algorithms. */
void compactRemoveDuplicates(StoreBuffer *owner);
/*
@@ -184,17 +199,17 @@ class StoreBuffer
void clear() {
if (!storage_)
return;
storage_->used() ? storage_->releaseAll() : storage_->freeAll();
}
bool isAboutToOverflow() const {
- return !storage_->isEmpty() && storage_->availableInCurrentChunk() < MinAvailableSize;
+ return !storage_->isEmpty() && storage_->availableInCurrentChunk() < LowAvailableThreshold;
}
/* Mark all generic edges. */
void mark(StoreBuffer *owner, JSTracer *trc);
template <typename T>
void put(StoreBuffer *owner, const T &t) {
MOZ_ASSERT(storage_);
--- a/js/src/jit-test/tests/asm.js/testBasic.js
+++ b/js/src/jit-test/tests/asm.js/testBasic.js
@@ -5,16 +5,17 @@ assertAsmTypeFail(USE_ASM);
assertAsmTypeFail(USE_ASM + 'return');
assertAsmTypeFail(USE_ASM + 'function f() 0');
assertAsmTypeFail(USE_ASM + 'function f(){}');
assertAsmTypeFail(USE_ASM + 'function f(){} return 0');
assertAsmTypeFail(USE_ASM + 'function f() 0; return 0');
assertAsmTypeFail(USE_ASM + 'function f(){} return g');
assertAsmTypeFail(USE_ASM + 'function f(){} function f(){} return f');
assertAsmTypeFail(USE_ASM + 'function f(){}; function g(){}; return {f, g}');
+assertAsmTypeFail(USE_ASM + 'var f = f;');
assertAsmTypeFail(USE_ASM + 'var f=0; function f(){} return f');
assertAsmTypeFail(USE_ASM + 'var f=glob.Math.imul; return {}');
assertAsmTypeFail('glob', USE_ASM + 'var f=glob.Math.imul; function f(){} return f');
assertAsmTypeFail('glob','foreign', USE_ASM + 'var f=foreign.foo; function f(){} return f');
assertAsmTypeFail(USE_ASM + 'function f(){} var f=[f,f]; return f');
assertAsmTypeFail(USE_ASM + 'function f() 0; return f');
assertAsmTypeFail('"use strict";' + USE_ASM + 'function f() {} return f');
assertAsmTypeFail(USE_ASM + '"use strict"; function f() {} return f');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1080991.js
@@ -0,0 +1,5 @@
+(function(){
+ for (var i = 0; i < 8; i++) {
+ var c = i
+ }
+})()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/test-scalar-replacement-float32.js
@@ -0,0 +1,98 @@
+setJitCompilerOption("ion.warmup.trigger", 30);
+var max = 40;
+
+// This test case verify that even if we do some scalar replacement, we keep a
+// correct computation of Float32 maths. In this case, when the object is not
+// escaped, the "store" instruction are preventing any float32 optimization to
+// kick-in. After Scalar Replacement, the store is removed, and the Float32
+// optimizations can avoid Double coercions.
+function escape_object(o) {
+ if (o.e) {
+ print(o);
+ }
+}
+
+var func = null;
+var check_object_argument_func = function (i, res) {
+ with ({}) { /* trun off the jit for this function, do not inline */ };
+ if (i == max - 1)
+ return funname.arguments[1].d;
+ return res;
+};
+
+var test_object_ref_check = eval(uneval(check_object_argument_func).replace("funname", "test_object_ref"));
+function test_object_ref(x, tmp) {
+ tmp = {
+ a: Math.fround(Math.pow(2 * x / max, 0)),
+ b: Math.fround(Math.pow(2 * x / max, 25)),
+ c: Math.fround(Math.pow(2 * x / max, 50)),
+ d: 0
+ };
+
+ tmp.d = tmp.a + tmp.b;
+ assertFloat32(tmp.d, false);
+ escape_object(tmp);
+ return test_object_ref_check(x, Math.fround(tmp.c + Math.fround(tmp.d)));
+}
+
+var test_object_check = eval(uneval(check_object_argument_func).replace("funname", "test_object"));
+function test_object(x, tmp) {
+ tmp = {
+ a: Math.fround(Math.pow(2 * x / max, 0)),
+ b: Math.fround(Math.pow(2 * x / max, 25)),
+ c: Math.fround(Math.pow(2 * x / max, 50)),
+ d: 0
+ };
+
+ tmp.d = tmp.a + tmp.b;
+ assertFloat32(tmp.d, false);
+ return test_object_check(x, Math.fround(tmp.c + Math.fround(tmp.d)));
+}
+
+// Same test with Arrays.
+function escape_array(o) {
+ if (o.length == 0) {
+ print(o);
+ }
+}
+
+var check_array_argument_func = function (i, res) {
+ with ({}) { /* trun off the jit for this function, do not inline */ };
+ if (i == max - 1) {
+ return funname.arguments[1][3];
+ }
+ return res;
+};
+
+var test_array_ref_check = eval(uneval(check_array_argument_func).replace("funname", "test_array_ref"));
+function test_array_ref(x, tmp) {
+ tmp = [
+ Math.fround(Math.pow(2 * x / max, 0)),
+ Math.fround(Math.pow(2 * x / max, 25)),
+ Math.fround(Math.pow(2 * x / max, 50)),
+ 0
+ ];
+ tmp[3] = tmp[0] + tmp[1];
+ assertFloat32(tmp[3], false);
+ escape_array(tmp);
+ return test_array_ref_check(x, Math.fround(tmp[2] + Math.fround(tmp[3])));
+}
+
+var test_array_check = eval(uneval(check_array_argument_func).replace("funname", "test_array"));
+function test_array(x, tmp) {
+ tmp = [
+ Math.fround(Math.pow(2 * x / max, 0)),
+ Math.fround(Math.pow(2 * x / max, 25)),
+ Math.fround(Math.pow(2 * x / max, 50)),
+ 0
+ ];
+ tmp[3] = tmp[0] + tmp[1];
+ assertFloat32(tmp[3], false);
+ return test_array_check(x, Math.fround(tmp[2] + Math.fround(tmp[3])));
+}
+
+
+for (var i = 0; i < max; i++) {
+ assertEq(test_object_ref(i, undefined), test_object(i, undefined));
+ assertEq(test_array_ref(i, undefined), test_array(i, undefined));
+}
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -402,18 +402,17 @@ EliminateTriviallyDeadResumePointOperand
size_t top = rp->stackDepth() - 1;
MOZ_ASSERT(!rp->isObservableOperand(top));
MDefinition *def = rp->getOperand(top);
if (def->isConstant())
return;
- MConstant *constant = MConstant::New(graph.alloc(), MagicValue(JS_OPTIMIZED_OUT));
- rp->block()->insertBefore(*(rp->block()->begin()), constant);
+ MConstant *constant = rp->block()->optimizedOutConstant(graph.alloc());
rp->replaceOperand(top, constant);
}
// Operands to a resume point which are dead at the point of the resume can be
// replaced with a magic value. This analysis supports limited detection of
// dead operands, pruning those which are defined in the resume point's basic
// block and have no uses outside the block or at points later than the resume
// point.
@@ -717,18 +716,20 @@ jit::EliminatePhis(MIRGenerator *mir, MI
}
}
// Sweep dead phis.
for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
MPhiIterator iter = block->phisBegin();
while (iter != block->phisEnd()) {
MPhi *phi = *iter++;
- if (phi->isUnused())
+ if (phi->isUnused()) {
+ phi->optimizeOutAllUses(graph.alloc());
block->discardPhi(phi);
+ }
}
}
return true;
}
namespace {
@@ -1759,19 +1760,17 @@ CheckPredecessorImpliesSuccessor(MBasicB
return true;
}
return false;
}
static bool
CheckOperandImpliesUse(MNode *n, MDefinition *operand)
{
- // TODO: Fix code that leaves discarded things in resume point operands
- // (bug 1055690).
- MOZ_ASSERT_IF(!n->isResumePoint(), !operand->isDiscarded());
+ MOZ_ASSERT(!operand->isDiscarded());
MOZ_ASSERT(operand->block() != nullptr);
for (MUseIterator i = operand->usesBegin(); i != operand->usesEnd(); i++) {
if (i->consumer() == n)
return true;
}
return false;
}
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -59,17 +59,17 @@ JitOptions::JitOptions()
SET_DEFAULT(checkOsiPointRegisters, false);
#endif
// Whether to enable extra code to perform dynamic validation of
// RangeAnalysis results.
SET_DEFAULT(checkRangeAnalysis, false);
// Toggle whether eager scalar replacement is globally disabled.
- SET_DEFAULT(disableScalarReplacement, true); // experimental
+ SET_DEFAULT(disableScalarReplacement, false);
// Toggle whether global value numbering is globally disabled.
SET_DEFAULT(disableGvn, false);
// Toggles whether loop invariant code motion is globally disabled.
SET_DEFAULT(disableLicm, false);
// Toggles whether inlining is globally disabled.
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -538,16 +538,32 @@ MDefinition::justReplaceAllUsesWith(MDef
MOZ_ASSERT(dom != nullptr);
MOZ_ASSERT(dom != this);
for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i)
i->setProducerUnchecked(dom);
dom->uses_.takeElements(uses_);
}
+void
+MDefinition::optimizeOutAllUses(TempAllocator &alloc)
+{
+ for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
+ MUse *use = *i++;
+ MConstant *constant = use->consumer()->block()->optimizedOutConstant(alloc);
+
+ // Update the resume point operand to use the optimized-out constant.
+ use->setProducerUnchecked(constant);
+ constant->addUseUnchecked(use);
+ }
+
+ // Remove dangling pointers.
+ this->uses_.clear();
+}
+
bool
MDefinition::emptyResultTypeSet() const
{
return resultTypeSet() && resultTypeSet()->empty();
}
MConstant *
MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintList *constraints)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -674,21 +674,29 @@ class MDefinition : public MNode
void addUseUnchecked(MUse *use) {
MOZ_ASSERT(use->producer() == this);
uses_.pushFrontUnchecked(use);
}
void replaceUse(MUse *old, MUse *now) {
MOZ_ASSERT(now->producer() == this);
uses_.replace(old, now);
}
+
+ // Replace the current instruction by a dominating instruction |dom| in all
+ // uses of the current instruction.
void replaceAllUsesWith(MDefinition *dom);
// Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands.
void justReplaceAllUsesWith(MDefinition *dom);
+ // Replace the current instruction by an optimized-out constant in all uses
+ // of the current instruction. Note, that optimized-out constant should not
+ // be observed, and thus they should not flow in any computation.
+ void optimizeOutAllUses(TempAllocator &alloc);
+
// Mark this instruction as having replaced all uses of ins, as during GVN,
// returning false if the replacement should not be performed. For use when
// GVN eliminates instructions which are not equivalent to one another.
virtual bool updateForReplacement(MDefinition *ins) {
return true;
}
void setVirtualRegister(uint32_t vreg) {
@@ -2655,17 +2663,19 @@ class MNewDerivedTypedObject
bool writeRecoverData(CompactBufferWriter &writer) const;
bool canRecoverOnBailout() const {
return true;
}
};
// Represent the content of all slots of an object. This instruction is not
// lowered and is not used to generate code.
-class MObjectState : public MVariadicInstruction
+class MObjectState
+ : public MVariadicInstruction,
+ public NoFloatPolicyAfter<1>::Data
{
private:
uint32_t numSlots_;
uint32_t numFixedSlots_;
explicit MObjectState(MDefinition *obj);
bool init(TempAllocator &alloc, MDefinition *obj);
@@ -2717,17 +2727,19 @@ class MObjectState : public MVariadicIns
bool writeRecoverData(CompactBufferWriter &writer) const;
bool canRecoverOnBailout() const {
return true;
}
};
// Represent the contents of all elements of an array. This instruction is not
// lowered and is not used to generate code.
-class MArrayState : public MVariadicInstruction
+class MArrayState
+ : public MVariadicInstruction,
+ public NoFloatPolicyAfter<2>::Data
{
private:
uint32_t numElements_;
explicit MArrayState(MDefinition *arr)
{
// This instruction is only used as a summary for bailout paths.
setResultType(MIRType_Object);
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -747,16 +747,30 @@ MBasicBlock::peek(int32_t depth)
}
void
MBasicBlock::discardLastIns()
{
discard(lastIns());
}
+MConstant *
+MBasicBlock::optimizedOutConstant(TempAllocator &alloc)
+{
+ // If the first instruction is a MConstant(MagicValue(JS_OPTIMIZED_OUT))
+ // then reuse it.
+ MInstruction *ins = *begin();
+ if (ins->type() == MIRType_MagicOptimizedOut)
+ return ins->toConstant();
+
+ MConstant *constant = MConstant::New(alloc, MagicValue(JS_OPTIMIZED_OUT));
+ insertBefore(ins, constant);
+ return constant;
+}
+
void
MBasicBlock::addFromElsewhere(MInstruction *ins)
{
MOZ_ASSERT(ins->block() != this);
// Remove |ins| from its containing block.
ins->block()->instructions_.remove(ins);
--- a/js/src/jit/MIRGraph.h
+++ b/js/src/jit/MIRGraph.h
@@ -362,16 +362,18 @@ class MBasicBlock : public TempObject, p
}
bool hasLastIns() const {
return !instructions_.empty() && instructions_.rbegin()->isControlInstruction();
}
MControlInstruction *lastIns() const {
MOZ_ASSERT(hasLastIns());
return instructions_.rbegin()->toControlInstruction();
}
+ // Find or allocate an optimized out constant.
+ MConstant *optimizedOutConstant(TempAllocator &alloc);
MPhiIterator phisBegin() const {
return phis_.begin();
}
MPhiIterator phisBegin(MPhi *at) const {
return phis_.begin(at);
}
MPhiIterator phisEnd() const {
return phis_.end();
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -451,19 +451,18 @@ ParallelSafetyVisitor::convertToBailout(
// We expect iter to be settled on the unsafe instruction.
MInstruction *ins = *iter;
MBasicBlock *block = ins->block();
MOZ_ASSERT(unsafe()); // `block` must have contained unsafe items
MOZ_ASSERT(block->isMarked()); // `block` must have been reachable to get here
clearUnsafe();
- // Allocate a new bailout instruction and transplant the resume point.
+ // Allocate a new bailout instruction.
MBail *bail = MBail::New(graph_.alloc(), Bailout_ParallelUnsafe);
- TransplantResumePoint(ins, bail);
// Discard the rest of the block and sever its link to its successors in
// the CFG.
for (size_t i = 0; i < block->numSuccessors(); i++)
block->getSuccessor(i)->removePredecessor(block);
block->discardAllInstructionsStartingAt(iter);
// End the block in a bail.
@@ -777,17 +776,16 @@ ParallelSafetyVisitor::visitSpecializedI
// Throw
bool
ParallelSafetyVisitor::visitThrow(MThrow *thr)
{
MBasicBlock *block = thr->block();
MOZ_ASSERT(block->lastIns() == thr);
MBail *bail = MBail::New(alloc(), Bailout_ParallelUnsafe);
- TransplantResumePoint(thr, bail);
block->discardLastIns();
block->add(bail);
block->end(MUnreachable::New(alloc()));
return true;
}
///////////////////////////////////////////////////////////////////////////
// Callee extraction
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -499,16 +499,28 @@ NoFloatPolicy<Op>::staticAdjustInputs(Te
return true;
}
template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
+template <unsigned FirstOp>
+bool
+NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator &alloc, MInstruction *def)
+{
+ for (size_t op = FirstOp, e = def->numOperands(); op < e; op++)
+ EnsureOperandNotFloat32(alloc, def, op);
+ return true;
+}
+
+template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator &alloc, MInstruction *def);
+template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator &alloc, MInstruction *def);
+
template <unsigned Op>
bool
BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
MDefinition *in = ins->getOperand(Op);
if (in->type() == MIRType_Value)
return true;
@@ -951,16 +963,18 @@ FilterTypeSetPolicy::adjustInputs(TempAl
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >) \
_(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >) \
_(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >) \
_(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >) \
_(MixPolicy<StringPolicy<0>, IntPolicy<1> >) \
_(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \
_(NoFloatPolicy<0>) \
+ _(NoFloatPolicyAfter<1>) \
+ _(NoFloatPolicyAfter<2>) \
_(ObjectPolicy<0>) \
_(ObjectPolicy<1>) \
_(ObjectPolicy<3>) \
_(StringPolicy<0>)
namespace js {
namespace jit {
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -228,16 +228,26 @@ class NoFloatPolicy : public TypePolicy
public:
EMPTY_DATA_;
static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
return staticAdjustInputs(alloc, def);
}
};
+// Policy for guarding variadic instructions such as object / array state
+// instructions.
+template <unsigned FirstOp>
+class NoFloatPolicyAfter : public TypePolicy
+{
+ public:
+ EMPTY_DATA_;
+ bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+};
+
// Box objects or strings as an input to a ToDouble instruction.
class ToDoublePolicy : public BoxInputsPolicy
{
public:
EMPTY_DATA_;
static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
return staticAdjustInputs(alloc, def);
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -299,20 +299,16 @@ ValueNumberer::discardDefsRecursively(MD
// becomes unused, so it isn't trivial to do.
bool
ValueNumberer::releaseResumePointOperands(MResumePoint *resume)
{
for (size_t i = 0, e = resume->numOperands(); i < e; ++i) {
if (!resume->hasOperand(i))
continue;
MDefinition *op = resume->getOperand(i);
- // TODO: We shouldn't leave discarded operands sitting around
- // (bug 1055690).
- if (op->isDiscarded())
- continue;
resume->releaseOperand(i);
// We set the UseRemoved flag when removing resume point operands,
// because even though we may think we're certain that a particular
// branch might not be taken, the type information might be incomplete.
if (!handleUseReleased(op, SetUseRemoved))
return false;
}
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -3236,21 +3236,53 @@ Simulator::decodeType6(SimInstruction *i
decodeType6CoprocessorIns(instr);
}
void
Simulator::decodeType7(SimInstruction *instr)
{
if (instr->bit(24) == 1)
softwareInterrupt(instr);
+ else if (instr->bit(4) == 1 && instr->bits(11,9) != 5)
+ decodeType7CoprocessorIns(instr);
else
decodeTypeVFP(instr);
}
void
+Simulator::decodeType7CoprocessorIns(SimInstruction *instr)
+{
+ if (instr->bit(20) == 0) {
+ // MCR, MCR2
+ if (instr->coprocessorValue() == 15) {
+ int opc1 = instr->bits(23,21);
+ int opc2 = instr->bits(7,5);
+ int CRn = instr->bits(19,16);
+ int CRm = instr->bits(3,0);
+ if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 10) {
+ // ARMv6 DSB instruction - do nothing now, see comments above
+ } else if (opc1 == 0 && opc2 == 5 && CRn == 7 && CRm == 10) {
+ // ARMv6 DMB instruction - do nothing now, see comments above
+ }
+ else if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 5) {
+ // ARMv6 ISB instruction - do nothing now, see comments above
+ }
+ else {
+ MOZ_CRASH();
+ }
+ } else {
+ MOZ_CRASH();
+ }
+ } else {
+ // MRC, MRC2
+ MOZ_CRASH();
+ }
+}
+
+void
Simulator::decodeTypeVFP(SimInstruction *instr)
{
MOZ_ASSERT(instr->typeValue() == 7 && instr->bit(24) == 0);
MOZ_ASSERT(instr->bits(11, 9) == 0x5);
// Obtain double precision register codes.
VFPRegPrecision precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
int vm = instr->VFPMRegValue(precision);
@@ -4072,16 +4104,25 @@ Simulator::decodeSpecialCondition(SimIns
break;
case 0xB:
if (instr->bits(22, 20) == 5 && instr->bits(15, 12) == 0xf) {
// pld: ignore instruction.
} else {
MOZ_CRASH();
}
break;
+ case 0x1C:
+ case 0x1D:
+ if (instr->bit(4) == 1 && instr->bits(11,9) != 5) {
+ // MCR, MCR2, MRC, MRC2 with cond == 15
+ decodeType7CoprocessorIns(instr);
+ } else {
+ MOZ_CRASH();
+ }
+ break;
default:
MOZ_CRASH();
}
}
// Executes the current instruction.
void
Simulator::instructionDecode(SimInstruction *instr)
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -259,16 +259,19 @@ class Simulator
void decodeSpecialCondition(SimInstruction *instr);
void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction *instr);
void decodeVCMP(SimInstruction *instr);
void decodeVCVTBetweenDoubleAndSingle(SimInstruction *instr);
void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction *instr);
void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction *instr);
+ // Support for some system functions.
+ void decodeType7CoprocessorIns(SimInstruction *instr);
+
// Executes one instruction.
void instructionDecode(SimInstruction *instr);
public:
static bool ICacheCheckingEnabled;
static void FlushICache(void *start, size_t size);
static int64_t StopSimAt;
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -6,16 +6,17 @@
Program('jsapi-tests')
UNIFIED_SOURCES += [
'selfTest.cpp',
'testAddPropertyPropcache.cpp',
'testArgumentsObject.cpp',
'testArrayBuffer.cpp',
+ 'testArrayBufferView.cpp',
'testBindCallable.cpp',
'testBug604087.cpp',
'testCallNonGenericMethodOnProxy.cpp',
'testChromeBuffer.cpp',
'testClassGetter.cpp',
'testCloneScript.cpp',
'testContexts.cpp',
'testCustomIterator.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testArrayBufferView.cpp
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+
+#include "jsfriendapi.h"
+
+#include "jsapi-tests/tests.h"
+
+BEGIN_TEST(testArrayBufferView_type)
+{
+ CHECK((TestViewType<uint8_t,
+ Create<JS_NewUint8Array, 7>,
+ JS_GetObjectAsUint8Array,
+ js::Scalar::Uint8,
+ 7, 7>(cx)));
+
+ CHECK((TestViewType<int8_t,
+ Create<JS_NewInt8Array, 33>,
+ JS_GetObjectAsInt8Array,
+ js::Scalar::Int8,
+ 33, 33>(cx)));
+
+ CHECK((TestViewType<uint8_t,
+ Create<JS_NewUint8ClampedArray, 7>,
+ JS_GetObjectAsUint8ClampedArray,
+ js::Scalar::Uint8Clamped,
+ 7, 7>(cx)));
+
+ CHECK((TestViewType<uint16_t,
+ Create<JS_NewUint16Array, 3>,
+ JS_GetObjectAsUint16Array,
+ js::Scalar::Uint16,
+ 3, 6>(cx)));
+
+ CHECK((TestViewType<int16_t,
+ Create<JS_NewInt16Array, 17>,
+ JS_GetObjectAsInt16Array,
+ js::Scalar::Int16,
+ 17, 34>(cx)));
+
+ CHECK((TestViewType<uint32_t,
+ Create<JS_NewUint32Array, 15>,
+ JS_GetObjectAsUint32Array,
+ js::Scalar::Uint32,
+ 15, 60>(cx)));
+
+ CHECK((TestViewType<int32_t,
+ Create<JS_NewInt32Array, 8>,
+ JS_GetObjectAsInt32Array,
+ js::Scalar::Int32,
+ 8, 32>(cx)));
+
+ CHECK((TestViewType<float,
+ Create<JS_NewFloat32Array, 7>,
+ JS_GetObjectAsFloat32Array,
+ js::Scalar::Float32,
+ 7, 28>(cx)));
+
+ CHECK((TestViewType<double,
+ Create<JS_NewFloat64Array, 9>,
+ JS_GetObjectAsFloat64Array,
+ js::Scalar::Float64,
+ 9, 72>(cx)));
+
+ CHECK((TestViewType<uint8_t,
+ CreateDataView,
+ JS_GetObjectAsArrayBufferView,
+ js::Scalar::TypeMax,
+ 8, 8>(cx)));
+
+ JS::Rooted<JS::Value> hasTypedObject(cx);
+ EVAL("typeof TypedObject !== 'undefined'", &hasTypedObject);
+ if (hasTypedObject.isTrue()) {
+ JS::Rooted<JS::Value> tval(cx);
+ EVAL("var T = new TypedObject.StructType({ x: TypedObject.uint32 });\n"
+ "new T(new ArrayBuffer(4));",
+ &tval);
+
+ JS::Rooted<JSObject*> tobj(cx, &tval.toObject());
+ CHECK(!JS_IsArrayBufferViewObject(tobj));
+ }
+
+ return true;
+}
+
+static JSObject *
+CreateDataView(JSContext *cx)
+{
+ JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
+ if (!global)
+ return nullptr;
+
+ static const char code[] = "new DataView(new ArrayBuffer(8))";
+
+ JS::Rooted<JS::Value> val(cx);
+ if (!JS_EvaluateScript(cx, global, code, strlen(code), __FILE__, __LINE__, &val))
+ return nullptr;
+
+ JS::Rooted<JSObject*> dv(cx, &val.toObject());
+ if (!JS_IsDataViewObject(dv))
+ return nullptr;
+
+ return dv;
+}
+
+template<JSObject * CreateTypedArray(JSContext *cx, uint32_t length),
+ size_t Length>
+static JSObject *
+Create(JSContext *cx)
+{
+ return CreateTypedArray(cx, Length);
+}
+
+template<typename T,
+ JSObject * CreateViewType(JSContext *cx),
+ JSObject * GetObjectAs(JSObject *obj, uint32_t *length, T **data),
+ js::Scalar::Type ExpectedType,
+ uint32_t ExpectedLength,
+ uint32_t ExpectedByteLength>
+bool TestViewType(JSContext *cx)
+{
+ JS::Rooted<JSObject*> obj(cx, CreateViewType(cx));
+ CHECK(obj);
+
+ CHECK(JS_IsArrayBufferViewObject(obj));
+
+ CHECK(JS_GetArrayBufferViewType(obj) == ExpectedType);
+
+ CHECK(JS_GetArrayBufferViewByteLength(obj) == ExpectedByteLength);
+
+ {
+ JS::AutoCheckCannotGC nogc;
+ T *data1 = static_cast<T*>(JS_GetArrayBufferViewData(obj, nogc));
+
+ T *data2;
+ uint32_t len;
+ CHECK(obj == GetObjectAs(obj, &len, &data2));
+ CHECK(data1 == data2);
+ CHECK(len == ExpectedLength);
+ }
+
+ return true;
+}
+
+END_TEST(testArrayBufferView_type)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -692,17 +692,16 @@ StopRequest(JSContext *cx)
{
JSRuntime *rt = cx->runtime();
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
MOZ_ASSERT(rt->requestDepth != 0);
if (rt->requestDepth != 1) {
rt->requestDepth--;
} else {
- rt->gc.notifyRequestEnd();
rt->requestDepth = 0;
rt->triggerActivityCallback(false);
}
}
JS_PUBLIC_API(void)
JS_BeginRequest(JSContext *cx)
{
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -157,17 +157,17 @@ assertSameCompartment(ThreadSafeContext
START_ASSERT_SAME_COMPARTMENT();
c.check(t1);
#endif
}
template <class T1> inline void
assertSameCompartmentDebugOnly(ThreadSafeContext *cx, const T1 &t1)
{
-#ifdef DEBUG
+#if defined(DEBUG) && defined(JS_CRASH_DIAGNOSTICS)
START_ASSERT_SAME_COMPARTMENT();
c.check(t1);
#endif
}
template <class T1, class T2> inline void
assertSameCompartment(ThreadSafeContext *cx, const T1 &t1, const T2 &t2)
{
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1343,25 +1343,16 @@ GCRuntime::init(uint32_t maxbytes, uint3
if (!marker.init(mode))
return false;
return true;
}
void
-GCRuntime::recordNativeStackTop()
-{
- /* Record the stack top here only if we are called from a request. */
- if (!rt->requestDepth)
- return;
- conservativeGC.recordStackTop();
-}
-
-void
GCRuntime::finish()
{
/*
* Wait until the background finalization stops and the helper thread
* shuts down before we forcefully release any remaining GC memory.
*/
helperState.finish();
@@ -5806,18 +5797,16 @@ GCRuntime::collect(bool incremental, int
return;
#endif
MOZ_ASSERT_IF(!incremental || budget != SliceBudget::Unlimited, JSGC_INCREMENTAL);
AutoStopVerifyingBarriers av(rt, reason == JS::gcreason::SHUTDOWN_CC ||
reason == JS::gcreason::DESTROY_RUNTIME);
- recordNativeStackTop();
-
gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), reason);
cleanUpEverything = ShouldCleanUpEverything(reason, gckind);
bool repeat = false;
do {
/*
* Let the API user decide to defer a GC if it wants to (unless this
@@ -6058,17 +6047,16 @@ AutoFinishGC::AutoFinishGC(JSRuntime *rt
rt->gc.waitBackgroundSweepEnd();
}
AutoPrepareForTracing::AutoPrepareForTracing(JSRuntime *rt, ZoneSelector selector)
: finish(rt),
session(rt),
copy(rt, selector)
{
- rt->gc.recordNativeStackTop();
}
JSCompartment *
js::NewCompartment(JSContext *cx, Zone *zone, JSPrincipals *principals,
const JS::CompartmentOptions &options)
{
JSRuntime *rt = cx->runtime();
JS_AbortIfWrongThread(rt);
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -356,16 +356,19 @@ void
ShapeGetterSetterRef::mark(JSTracer *trc)
{
// Update the current shape's entry in the parent KidsHash table if needed.
// This is necessary as the computed hash includes the getter/setter
// pointers.
JSObject *obj = *objp;
JSObject *prior = obj;
+ if (!prior)
+ return;
+
trc->setTracingLocation(&*prior);
gc::Mark(trc, &obj, "AccessorShape getter or setter");
if (obj == *objp)
return;
Shape *parent = shape->parent;
if (shape->inDictionary() || !parent->kids.isHash()) {
*objp = obj;
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -288,17 +288,17 @@ Poison(void *ptr, int value, size_t num)
if (poison)
return memset(ptr, value, num);
return nullptr;
}
/* Crash diagnostics */
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(MOZ_ASAN)
# define JS_CRASH_DIAGNOSTICS 1
#endif
#if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL)
# define JS_POISON(p, val, size) Poison(p, val, size)
#else
# define JS_POISON(p, val, size) ((void) 0)
#endif
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5935,17 +5935,17 @@ main(int argc, char **argv, char **envp)
"shell's global")
|| !op.addIntOption('\0', "thread-count", "COUNT", "Use COUNT auxiliary threads "
"(default: # of cores - 1)", -1)
|| !op.addBoolOption('\0', "ion", "Enable IonMonkey (default)")
|| !op.addBoolOption('\0', "no-ion", "Disable IonMonkey")
|| !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|| !op.addStringOption('\0', "ion-scalar-replacement", "on/off",
- "Scalar Replacement (default: off, on to enable)")
+ "Scalar Replacement (default: on, off to disable)")
|| !op.addStringOption('\0', "ion-gvn", "[mode]",
"Specify Ion global value numbering:\n"
" off: disable GVN\n"
" on: enable GVN (default)\n")
|| !op.addStringOption('\0', "ion-licm", "on/off",
"Loop invariant code motion (default: on, off to disable)")
|| !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
"Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Object/clear-dictionary-accessor-getset.js
@@ -0,0 +1,55 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = "clear-dictionary-accessor-getset.js";
+var BUGNUMBER = 1082662;
+var summary =
+ "Properly handle GC of a dictionary accessor property whose [[Get]] or " +
+ "[[Set]] has been changed to |undefined|";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+function test(field)
+{
+ var prop = "[[" + field[0].toUpperCase() + field.substring(1) + "]]";
+ print("Testing for GC crashes after setting " + prop + " to undefined...");
+
+ function inner()
+ {
+ // Create an object with an accessor property.
+ var obj = { x: 42, get y() {}, set y(v) {} };
+
+ // 1) convert it to dictionary mode, in the process 2) creating a new
+ // version of that accessor property whose [[Get]] and [[Set]] are objects
+ // that trigger post barriers.
+ delete obj.x;
+
+ var desc = {};
+ desc[field] = undefined;
+
+ // Overwrite [[field]] with undefined. Note #1 above is necessary so this
+ // is an actual *overwrite*, and not (possibly) a shape-tree fork that
+ // doesn't overwrite.
+ Object.defineProperty(obj, "y", desc);
+
+ }
+
+ inner();
+ gc(); // In unfixed code, this crashes trying to mark a null [[field]].
+}
+
+test("get");
+test("set");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -776,33 +776,34 @@ ArrayBufferObject::objectMoved(JSObject
if (src.hasInlineData())
dst.setSlot(DATA_SLOT, PrivateValue(dst.inlineDataPointer()));
}
ArrayBufferViewObject *
ArrayBufferObject::firstView()
{
return getSlot(FIRST_VIEW_SLOT).isObject()
- ? &getSlot(FIRST_VIEW_SLOT).toObject().as<ArrayBufferViewObject>()
- : nullptr;
+ ? static_cast<ArrayBufferViewObject*>(&getSlot(FIRST_VIEW_SLOT).toObject())
+ : nullptr;
}
void
ArrayBufferObject::setFirstView(ArrayBufferViewObject *view)
{
setSlot(FIRST_VIEW_SLOT, ObjectOrNullValue(view));
}
bool
ArrayBufferObject::addView(JSContext *cx, JSObject *viewArg)
{
// Note: we don't pass in an ArrayBufferViewObject as the argument due to
// tricky inheritance in the various view classes. View classes do not
// inherit from ArrayBufferViewObject so won't be upcast automatically.
- ArrayBufferViewObject *view = &viewArg->as<ArrayBufferViewObject>();
+ MOZ_ASSERT(viewArg->is<ArrayBufferViewObject>() || viewArg->is<TypedObject>());
+ ArrayBufferViewObject *view = static_cast<ArrayBufferViewObject*>(viewArg);
if (!firstView()) {
setFirstView(view);
return true;
}
return cx->compartment()->innerViews.addView(cx, this, view);
}
@@ -980,17 +981,17 @@ ArrayBufferViewObject::trace(JSTracer *t
obj->initPrivate(buf.dataPointer() + offset);
}
}
template <>
bool
JSObject::is<js::ArrayBufferViewObject>() const
{
- return is<DataViewObject>() || is<TypedArrayObject>() || is<TypedObject>();
+ return is<DataViewObject>() || is<TypedArrayObject>();
}
void
ArrayBufferViewObject::neuter(void *newData)
{
MOZ_ASSERT(newData != nullptr);
if (is<DataViewObject>())
as<DataViewObject>().neuter(newData);
@@ -1206,17 +1207,19 @@ JS_GetArrayBufferViewData(JSObject *obj,
}
JS_FRIEND_API(JSObject *)
JS_GetArrayBufferViewBuffer(JSContext *cx, HandleObject objArg)
{
JSObject *obj = CheckedUnwrap(objArg);
if (!obj)
return nullptr;
- Rooted<ArrayBufferViewObject *> viewObject(cx, &obj->as<ArrayBufferViewObject>());
+ MOZ_ASSERT(obj->is<ArrayBufferViewObject>());
+
+ Rooted<ArrayBufferViewObject *> viewObject(cx, static_cast<ArrayBufferViewObject*>(obj));
return ArrayBufferViewObject::bufferObject(cx, viewObject);
}
JS_FRIEND_API(uint32_t)
JS_GetArrayBufferViewByteLength(JSObject *obj)
{
obj = CheckedUnwrap(obj);
if (!obj)
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1236,17 +1236,18 @@ OptionsBase::ParseString(const char *nam
if (!value.isString()) {
JS_ReportError(mCx, "Expected a string value for property %s", name);
return false;
}
char *tmp = JS_EncodeString(mCx, value.toString());
NS_ENSURE_TRUE(tmp, false);
- prop.Adopt(tmp, strlen(tmp));
+ prop.Assign(tmp, strlen(tmp));
+ js_free(tmp);
return true;
}
/*
* Helper that tries to get a string property from the options object.
*/
bool
OptionsBase::ParseString(const char *name, nsString &prop)
--- a/js/xpconnect/src/XPCDebug.cpp
+++ b/js/xpconnect/src/XPCDebug.cpp
@@ -1,16 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "xpcprivate.h"
#include "jsprf.h"
+#include "nsThreadUtils.h"
+#include "nsContentUtils.h"
#ifdef XP_WIN
#include <windows.h>
#endif
static void DebugDump(const char* fmt, ...)
{
char buffer[2048];
@@ -27,19 +29,22 @@ static void DebugDump(const char* fmt, .
if (IsDebuggerPresent()) {
OutputDebugStringA(buffer);
}
#endif
printf("%s", buffer);
}
bool
-xpc_DumpJSStack(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps)
+xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps)
{
- if (char* buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) {
+ JSContext* cx = nsContentUtils::GetCurrentJSContextForThread();
+ if (!cx) {
+ printf("there is no JSContext on the stack!\n");
+ } else if (char* buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) {
DebugDump("%s\n", buf);
JS_smprintf_free(buf);
}
return true;
}
char*
xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -26,24 +26,16 @@ members = [
# - nsIDOMJSWindow.{prompt,setTimeout,setInterval,open,openDialog}
#
# (And nsIDOMModalContentWindow.returnValue is an attribute of type
# nsIVariant, which qsgen.py can't handle.)
# dom/interfaces/xpath
'nsIDOMXPathNSResolver.lookupNamespaceURI',
- # layout/xul/base/public
- 'nsIBoxObject.x',
- 'nsIBoxObject.y',
- 'nsIBoxObject.screenX',
- 'nsIBoxObject.screenY',
- 'nsIBoxObject.width',
- 'nsIBoxObject.height',
-
]
# Most interfaces can be found by searching the includePath; to find
# nsIDOMEvent, for example, just look for nsIDOMEvent.idl. But IDL filenames
# for very long interface names are slightly abbreviated, and many interfaces
# don't have their own files, just for extra wackiness. So qsgen.py needs
# a little help.
#
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -963,21 +963,17 @@ nsXPConnect::DebugDumpObject(nsISupports
}
/* void debugDumpJSStack (in bool showArgs, in bool showLocals, in bool showThisProps); */
NS_IMETHODIMP
nsXPConnect::DebugDumpJSStack(bool showArgs,
bool showLocals,
bool showThisProps)
{
- JSContext* cx = GetCurrentJSContext();
- if (!cx)
- printf("there is no JSContext on the nsIThreadJSContextStack!\n");
- else
- xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps);
+ xpc_DumpJSStack(showArgs, showLocals, showThisProps);
return NS_OK;
}
char*
nsXPConnect::DebugPrintJSStack(bool showArgs,
bool showLocals,
bool showThisProps)
@@ -1384,22 +1380,17 @@ nsXPConnect::ReadFunction(nsIObjectInput
{
return ReadScriptOrFunction(stream, cx, nullptr, functionObjp);
}
/* These are here to be callable from a debugger */
extern "C" {
JS_EXPORT_API(void) DumpJSStack()
{
- nsresult rv;
- nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
- if (NS_SUCCEEDED(rv) && xpc)
- xpc->DebugDumpJSStack(true, true, false);
- else
- printf("failed to get XPConnect service!\n");
+ xpc_DumpJSStack(true, true, false);
}
JS_EXPORT_API(char*) PrintJSStack()
{
nsresult rv;
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
return (NS_SUCCEEDED(rv) && xpc) ?
xpc->DebugPrintJSStack(true, true, false) :
--- a/js/xpconnect/src/qsgen.py
+++ b/js/xpconnect/src/qsgen.py
@@ -1093,20 +1093,17 @@ def writeSpecs(f, elementType, varname,
f.write("};\n\n")
def writeDefiner(f, conf, stringtable, interfaces):
f.write("// === Definer\n\n")
# Write out the properties and functions
propspecs_indices = {}
funcspecs_indices = {}
- prop_array_name = "all_properties"
func_array_name = "all_functions"
- writeSpecs(f, "xpc_qsPropertySpec", prop_array_name,
- "propspecs", propspecs_indices, interfaces)
writeSpecs(f, "xpc_qsFunctionSpec", func_array_name,
"funcspecs", funcspecs_indices, interfaces)
# generate the static hash table
loadFactor = 0.6
size = int(len(interfaces) / loadFactor)
buckets = [[] for i in range(size)]
for iface in interfaces:
@@ -1142,16 +1139,17 @@ def writeDefiner(f, conf, stringtable, i
% (m3[0:2], m3[2:4], m4[0:2], m4[2:4],
m4[4:6], m4[6:8], m4[8:10], m4[10:12]))
iid = ('{0x%s, 0x%s, 0x%s, %s}' % (m0, m1, m2, m3arr))
# properties fields
prop_index = 0
prop_n_entries = 0
if iface.propspecs:
+ assert False
prop_index = propspecs_indices[iface.name]
prop_n_entries = len(iface.propspecs)
# member fields
func_index = 0
func_n_entries = 0
if iface.funcspecs:
func_index = funcspecs_indices[iface.name]
@@ -1188,31 +1186,31 @@ def writeDefiner(f, conf, stringtable, i
f.write("\n };\n\n")
f.write("// Make sure our table indices aren't overflowed\n"
"PR_STATIC_ASSERT((sizeof(tableData) / sizeof(tableData[0])) < (1 << (8 * sizeof(tableData[0].parentInterface))));\n"
"PR_STATIC_ASSERT((sizeof(tableData) / sizeof(tableData[0])) < (1 << (8 * sizeof(tableData[0].chain))));\n\n")
# The string table for property and method names.
table_name = "stringtab"
stringtable.writeDefinition(f, table_name)
- structNames = [prop_array_name, func_array_name]
+ structNames = [func_array_name]
for name in structNames:
f.write("PR_STATIC_ASSERT(sizeof(%s) < (1 << (8 * sizeof(%s[0].name_index))));\n"
% (table_name, name))
f.write("\n")
# the definer function (entry point to this quick stubs file)
f.write("namespace xpc {\n")
f.write("bool %s_DefineQuickStubs(" % conf.name)
f.write("JSContext *cx, JSObject *proto, unsigned flags, uint32_t count, "
"const nsID **iids)\n"
"{\n")
f.write(" return !!xpc_qsDefineQuickStubs("
"cx, proto, flags, count, iids, %d, tableData, %s, %s, %s);\n" % (
- size, prop_array_name, func_array_name, table_name))
+ size, "nullptr", func_array_name, table_name))
f.write("}\n")
f.write("} // namespace xpc\n\n\n")
stubTopTemplate = '''\
/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */
#include "jsapi.h"
#include "qsWinUndefs.h"
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2963,18 +2963,17 @@ xpc_JSObjectToID(JSContext *cx, JSObject
extern bool
xpc_JSObjectIsID(JSContext *cx, JSObject* obj);
/***************************************************************************/
// in XPCDebug.cpp
extern bool
-xpc_DumpJSStack(JSContext* cx, bool showArgs, bool showLocals,
- bool showThisProps);
+xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps);
// Return a newly-allocated string containing a representation of the
// current JS stack. It is the *caller's* responsibility to free this
// string with JS_smprintf_free().
extern char*
xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
bool showThisProps);
--- a/js/xpconnect/tests/chrome/test_bug760109.xul
+++ b/js/xpconnect/tests/chrome/test_bug760109.xul
@@ -34,41 +34,16 @@ https://bugzilla.mozilla.org/show_bug.cg
// Check |constructor|.
// Note that the 'constructor' property of the underlying chrome object
// will be resolved on SomeConstructor.prototype, which has an empty
// __exposedProps__. This means that we shouldn't remap the property, even
// though we'd also be able to find it on Object.prototype. Some recent
// refactoring has made it possible to do the right thing here.
is(typeof chromeObject.constructor, "undefined", "Object constructor does what we expect");
ok(chromeArray.constructor === Array, "Array constructor remapped properly");
-
- // We should be able to .forEach on the Array.
- var concat = '';
- chromeArray.forEach(function(val) { concat += val; });
- is(concat, 'abz', "Should be able to .forEach COW-ed Array");
-
- // Try other Array operations.
- is(chromeArray.indexOf('b'), 1, "indexOf works correctly");
- is(chromeArray.join(''), concat, "join works correctly");
- is(chromeArray.slice(1).join(''), 'bz', "slice works correctly");
- is(chromeArray.length, 3, "Able to check array length");
-
- // Try some operations that modify the array.
- is(chromeArray.pop(), 'z', "Able to call pop");
- is(chromeArray.push('z'), 3, "Able to call push");
- chromeArray.reverse();
- is(chromeArray.join(''), 'zba', "Able to call reverse");
- chromeArray.sort();
- is(chromeArray.join(''), 'abz', "Able to call sort");
-
- // We should be able to .hasOwnProperty on the Object, and have
- // it filter the objects we can see.
- ok(chromeObject.hasOwnProperty('foo'), "Should see r property");
- ok(!chromeObject.hasOwnProperty('bar'), "Shouldn't see non-exposed property");
- ok(chromeObject.hasOwnProperty('baz'), "Should see rw property");
}
// We use a constructor to create the test object so that there's an
// intermediate object on the prototype chain between the instance and the
// standard prototype.
function SomeConstructor() {
this.foo = 2;
this.bar = 3;
--- a/js/xpconnect/tests/chrome/test_cows.xul
+++ b/js/xpconnect/tests/chrome/test_cows.xul
@@ -263,49 +263,16 @@ function COWTests() {
// Readables and functions
try {
var COWFunc = getCOW((function() { return 5; }));
is(COWFunc(), 5, "COWed functions should be callable");
} catch (e) {
todo(false, "COWed functions should not raise " + e);
}
- try {
- var objWithFunc = {__exposedProps__: {foo: 'r'},
- foo: function foo() { return 5; }};
- is(getCOW((objWithFunc)).foo(), 5,
- "Readable function exposed props should be callable");
- } catch (e) {
- ok(false, "Readable function exposed props should be callable" + e);
- }
-
- // Readables with getters
- var obj = {
- get prop() { return { __exposedProps__: {}, test: "FAIL" } },
- __exposedProps__: {prop: 'r'}
- };
- is(getCOW(obj).prop.test, undefined, "getting prop.test shouldn't return anything");
- ok(!("test" in getCOW(obj).prop), "getting prop.test shouldn't return anything");
-
- // Alien objects
- try {
- is(alienObject.funProp(1), 2,
- "COWs wrapping objects from different principals should work");
- } catch (e) {
- ok(false, "COWs wrapping objs from different principals " +
- "shouldn't throw " + e);
- }
-
- try {
- is(alienObject.funProp(1), 2,
- "COWs wrapping objs from different principals should work twice");
- } catch (e) {
- ok(false, "COWs wrapping objs from different principals " +
- "shouldn't throw on second access but not first: " + e);
- }
}
// Decompile the COW test suite, re-evaluate it in the sandbox and execute it.
Cu.evalInSandbox('(' + uneval(COWTests) + ')()', sandbox);
// Test that COWed objects passing from content to chrome get unwrapped.
function returnCOW() {
return getCOW({__exposedProps__: {},
--- a/js/xpconnect/tests/chrome/test_exposeInDerived.xul
+++ b/js/xpconnect/tests/chrome/test_exposeInDerived.xul
@@ -22,31 +22,25 @@ https://bugzilla.mozilla.org/show_bug.cg
// Set up the sandbox.
var sb = new Cu.Sandbox('http://www.example.com');
sb.ok = ok;
sb.is = is;
// Make a chrome object that exposes objects off its prototype.
sb.proto = { read: 42, readWrite: 32, __exposedProps__: {} };
- sb.proto.__defineSetter__('setterProp', function(val) { this._setterProp = val; });
- sb.obj = { __exposedProps__: { read: 'r', readWrite: 'rw', setterProp: 'w' } };
+ sb.obj = { __exposedProps__: { read: 'r', readWrite: 'rw' } };
sb.obj.__proto__ = sb.proto;
// Make sure we can't access any of the properties on the prototype directly.
Cu.evalInSandbox('is(proto.read, undefined, "proto.read inaccessible");', sb);
Cu.evalInSandbox('var wrote = false; ' +
'try { proto.readWrite = 12; wrote = true; } catch(e) {} ' +
' ok(!wrote, "Should not write proto property");', sb);
- Cu.evalInSandbox('var wrote = false; ' +
- 'try { proto.setterProp = 12; wrote = true; } catch(e) {} ' +
- ' ok(!wrote, "Should not write proto setter");', sb);
// Make sure we can access the exposed properties via the derived object.
Cu.evalInSandbox('is(obj.read, 42, "obj.read accessible");', sb);
Cu.evalInSandbox('is(obj.readWrite, 32, "obj.readWrite is readable");', sb);
Cu.evalInSandbox('obj.readWrite = 8; is(obj.readWrite, 8, "obj.readWrite is writable");', sb);
- Cu.evalInSandbox('obj.setterProp = 3;', sb);
- is(sb.obj._setterProp, 3, "obj.setterProp works");
]]>
</script>
</window>
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -108,23 +108,16 @@ https://bugzilla.mozilla.org/show_bug.cg
ok(Object.getOwnPropertyNames(iwin.Array).indexOf('prototype') >= 0, "Should list prototype for standard constructor");
// Test proxies.
var targetObject = new iwin.Object();
targetObject.foo = 9;
var forwardingProxy = new iwin.Proxy(targetObject, new iwin.Object());
is(global(forwardingProxy), iwin, "proxy global correct");
is(Cu.waiveXrays(forwardingProxy).foo, 9, "forwards correctly");
- // NB: COW-implemented proxy handlers are super dangerous, and we should not
- // encourage them.
- var handler = {get: function(target, name) { return name * 2; }, __exposedProps__: {get: 'r'}};
- var doublingProxy = new iwin.Proxy(targetObject, handler);
- is(global(doublingProxy), iwin, "doubling proxy global correct");
- is(Cu.waiveXrays(doublingProxy)[3], 6, "Doubles correctly");
- is(Cu.waiveXrays(doublingProxy)[20], 40, "Doubles correctly");
// Test eval.
var toEval = "({a: 2, b: {foo: 'bar'}, f: function() { return window; }})";
is(global(iwin.eval(toEval)), iwin, "eval creates objects in the correct global");
is(iwin.eval(toEval).b.foo, 'bar', "eval-ed object looks right");
is(Cu.waiveXrays(iwin.eval(toEval)).f(), Cu.waiveXrays(iwin), "evaled function works right");
testDate();
--- a/js/xpconnect/tests/mochitest/test_bug393269.html
+++ b/js/xpconnect/tests/mochitest/test_bug393269.html
@@ -9,18 +9,16 @@ https://bugzilla.mozilla.org/show_bug.cg
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=393269">Mozilla Bug 393269</a>
<iframe id="ifr"></iframe>
<pre id="test">
<script class="testbody" type="text/javascript">
-SimpleTest.expectAssertions(1, 2);
-
(function () {
/** Test for Bug 393269 **/
var doc = $("ifr").contentDocument;
is("UTF-8", doc.characterSet, "control, getting a property");
doc.open();
try {
is("UTF-8", doc.characterSet,
"can get a property after 1 document.open")
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_bug1082450.js
@@ -0,0 +1,40 @@
+const Cu = Components.utils;
+function run_test() {
+
+ var sb = new Cu.Sandbox('http://www.example.com');
+ function checkThrows(str, rgxp) {
+ try {
+ sb.eval(str);
+ do_check_true(false);
+ } catch (e) {
+ do_check_true(rgxp.test(e));
+ }
+ }
+
+ sb.exposed = {
+ get getterProp() { return 42; },
+ set setterProp(x) { },
+ get getterSetterProp() { return 42; },
+ set getterSetterProp(x) { },
+ simpleValueProp: 42,
+ objectValueProp: { val: 42, __exposedProps__: { val: 'r' } },
+ contentCallableValueProp: new sb.Function('return 42'),
+ chromeCallableValueProp: function() {},
+ __exposedProps__: { getterProp : 'r',
+ setterProp : 'w',
+ getterSetterProp: 'rw',
+ simpleValueProp: 'r',
+ objectValueProp: 'r',
+ contentCallableValueProp: 'r',
+ chromeCallableValueProp: 'r' }
+ };
+
+ do_check_eq(sb.eval('exposed.simpleValueProp'), 42);
+ do_check_eq(sb.eval('exposed.objectValueProp.val'), 42);
+ checkThrows('exposed.getterProp;', /privileged accessor/i);
+ checkThrows('exposed.setterProp = 42;', /privileged accessor/i);
+ checkThrows('exposed.getterSetterProp;', /privileged accessor/i);
+ checkThrows('exposed.getterSetterProp = 42;', /privileged accessor/i);
+ do_check_eq(sb.eval('exposed.contentCallableValueProp()'), 42);
+ checkThrows('exposed.chromeCallableValueProp();', /privileged or cross-origin callable/i);
+}
--- a/js/xpconnect/tests/unit/test_bug780370.js
+++ b/js/xpconnect/tests/unit/test_bug780370.js
@@ -1,23 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=780370 */
const Cu = Components.utils;
-// Use a COW to expose a function from a standard prototype, and make sure it's
-// still remapped.
+// Use a COW to expose a function from a standard prototype, and make we deny
+// access to it.
function run_test()
{
var sb = Cu.Sandbox("http://www.example.com");
sb.obj = { foo: 42, __exposedProps__: { hasOwnProperty: 'r' } };
do_check_eq(Cu.evalInSandbox('typeof obj.foo', sb), 'undefined', "COW works as expected");
- do_check_true(Cu.evalInSandbox('obj.hasOwnProperty === Object.prototype.hasOwnProperty', sb),
- "Remapping happens even when the property is explicitly exposed");
- // NB: We used to test for the following, but such behavior became very
- // difficult to implement in a recent refactor. We're moving away from this
- // API anyway, so we decided to explicitly drop support for this.
- // do_check_eq(Cu.evalInSandbox('Object.prototype.bar = 10; obj.bar', sb), 10);
+ try {
+ Cu.evalInSandbox('obj.hasOwnProperty', sb);
+ do_check_true(false);
+ } catch (e) {
+ do_check_true(/privileged or cross-origin callable/i.test(e));
+ }
}
deleted file mode 100644
--- a/js/xpconnect/tests/unit/test_bug805807.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const Cu = Components.utils;
-function run_test() {
- var sb = new Cu.Sandbox('http://www.example.com');
-
- sb.obj = { priv: 42, __exposedProps__ : {} };
- Object.defineProperty(sb.obj, 'readable', { get: function() { return this.priv; }, set: function(x) { this.priv = x; }} );
- sb.obj.__exposedProps__.readable = 'r';
- do_check_eq(Cu.evalInSandbox('Object.getOwnPropertyDescriptor(obj, "readable").get.call(obj)', sb), 42);
- sb.obj.readable = 32;
- do_check_eq(Cu.evalInSandbox('Object.getOwnPropertyDescriptor(obj, "readable").get.call(obj);', sb), 32);
- do_check_eq(Cu.evalInSandbox('Object.__lookupGetter__.call(obj, "readable").call(obj);', sb), 32);
- Object.getOwnPropertyDescriptor(sb.obj, "readable").set.call(sb.obj, 22);
- do_check_eq(sb.obj.readable, 22);
- Object.__lookupSetter__.call(sb.obj, "readable").call(sb.obj, 21);
- do_check_eq(sb.obj.readable, 21);
- checkThrows(sb, 'obj.readable = 11;');
- do_check_eq(Cu.evalInSandbox('Object.getOwnPropertyDescriptor(obj, "readable").set', sb), null);
- do_check_eq(Cu.evalInSandbox('Object.__lookupSetter__.call(obj, "readable")', sb), null);
- do_check_eq(sb.obj.readable, 21);
-}
-
-function checkThrows(sb, expression) {
- var result = Cu.evalInSandbox('(function() { try { ' + expression + ' return "success"; } catch (e) { return e.toString(); } })();', sb);
- dump("Result: " + result);
- do_check_true(!!/denied/.exec(result));
-}
--- a/js/xpconnect/tests/unit/test_bug853709.js
+++ b/js/xpconnect/tests/unit/test_bug853709.js
@@ -1,16 +1,12 @@
const Cu = Components.utils;
function setupChromeSandbox() {
this.chromeObj = {a: 2, __exposedProps__: {a: "rw", b: "rw"} };
- this._b = 3;
- Object.defineProperty(chromeObj, 'b', { configurable: true,
- get: function() { return _b; },
- set: function(val) { _b = val; } });
this.chromeArr = [4, 2, 1];
this.chromeArr["__exposedProps__"] = { "1": "rw" };
}
function checkDefineThrows(sb, obj, prop, desc) {
var result = Cu.evalInSandbox('(function() { try { Object.defineProperty(' + obj + ', "' + prop + '", ' + desc.toSource() + '); return "nothrow"; } catch (e) { return e.toString(); }})();', sb);
do_check_neq(result, 'nothrow');
do_check_true(!!/denied/.exec(result));
@@ -20,17 +16,15 @@ function checkDefineThrows(sb, obj, prop
function run_test() {
var chromeSB = new Cu.Sandbox(this);
var contentSB = new Cu.Sandbox('http://www.example.org');
Cu.evalInSandbox('(' + setupChromeSandbox.toSource() + ')()', chromeSB);
contentSB.chromeObj = chromeSB.chromeObj;
contentSB.chromeArr = chromeSB.chromeArr;
do_check_eq(Cu.evalInSandbox('chromeObj.a', contentSB), 2);
- do_check_eq(Cu.evalInSandbox('chromeObj.b', contentSB), 3);
- do_check_eq(Cu.evalInSandbox('chromeObj.b = 4; chromeObj.b', contentSB), 4);
do_check_eq(Cu.evalInSandbox('chromeArr[1]', contentSB), 2);
checkDefineThrows(contentSB, 'chromeObj', 'a', {get: function() { return 2; }});
checkDefineThrows(contentSB, 'chromeObj', 'a', {configurable: true, get: function() { return 2; }});
checkDefineThrows(contentSB, 'chromeObj', 'b', {configurable: true, get: function() { return 2; }, set: function() {}});
checkDefineThrows(contentSB, 'chromeArr', '1', {configurable: true, get: function() { return 2; }});
}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -23,17 +23,16 @@ support-files =
[test_bug451678.js]
[test_bug604362.js]
[test_bug641378.js]
[test_bug677864.js]
[test_bug711404.js]
[test_bug742444.js]
[test_bug778409.js]
[test_bug780370.js]
-[test_bug805807.js]
[test_bug809652.js]
[test_bug809674.js]
[test_bug813901.js]
[test_bug845201.js]
[test_bug845862.js]
[test_bug849730.js]
[test_bug851895.js]
[test_bug853709.js]
@@ -47,16 +46,17 @@ support-files =
[test_bug961054.js]
[test_bug976151.js]
[test_bug1001094.js]
[test_bug1021312.js]
[test_bug1033253.js]
[test_bug1033920.js]
[test_bug1033927.js]
[test_bug1034262.js]
+[test_bug1082450.js]
[test_bug_442086.js]
[test_file.js]
[test_blob.js]
[test_blob2.js]
[test_file2.js]
[test_import.js]
[test_import_fail.js]
[test_interposition.js]
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -338,16 +338,35 @@ ExposedPropertiesOnly::check(JSContext *
return false;
}
if ((act == Wrapper::SET && !(access & WRITE)) ||
(act != Wrapper::SET && !(access & READ))) {
return false;
}
+ // Inspect the property on the underlying object to check for red flags.
+ if (!JS_GetPropertyDescriptorById(cx, wrappedObject, id, &desc))
+ return false;
+
+ // Reject accessor properties.
+ if (desc.hasGetterOrSetter()) {
+ EnterAndThrow(cx, wrapper, "Exposing privileged accessor properties is prohibited");
+ return false;
+ }
+
+ // Reject privileged or cross-origin callables.
+ if (desc.value().isObject()) {
+ RootedObject maybeCallable(cx, js::UncheckedUnwrap(&desc.value().toObject()));
+ if (JS::IsCallable(maybeCallable) && !AccessCheck::subsumes(wrapper, maybeCallable)) {
+ EnterAndThrow(cx, wrapper, "Exposing privileged or cross-origin callable is prohibited");
+ return false;
+ }
+ }
+
return true;
}
bool
ExposedPropertiesOnly::deny(js::Wrapper::Action act, HandleId id)
{
// Fail silently for GET, ENUMERATE, and GET_PROPERTY_DESCRIPTOR.
if (act == js::Wrapper::GET || act == js::Wrapper::ENUMERATE ||
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -281,18 +281,18 @@ ChromeObjectWrapper::objectClassIs(Handl
bool
ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper,
HandleId id, js::Wrapper::Action act, bool *bp) const
{
if (AllowedByBase(cx, wrapper, id, act))
return true;
// COWs fail silently for GETs, and that also happens to be the only case
// where we might want to redirect the lookup to the home prototype chain.
- *bp = act == Wrapper::GET || act == Wrapper::ENUMERATE ||
- act == Wrapper::GET_PROPERTY_DESCRIPTOR;
+ *bp = (act == Wrapper::GET || act == Wrapper::ENUMERATE ||
+ act == Wrapper::GET_PROPERTY_DESCRIPTOR) && !JS_IsExceptionPending(cx);
if (!*bp || id == JSID_VOID)
return false;
// Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor
// before we've fully entered the policy. Waive our policy.
js::AutoWaivePolicy policy(cx, wrapper, id, act);
return PropIsFromStandardPrototype(cx, wrapper, id);
}
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug1080361_inner.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1080361
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1080361</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ #target, #mediator, #listener { background: yellow; margin: 10px; }
+ </style>
+ <script type="application/javascript">
+ var target = undefined;
+ var mediator = undefined;
+ var listener = undefined;
+ var test_target_down = false;
+ var test_target_up = false;
+ var test_first_exc = false;
+ var test_second_exc = false;
+ var test_third_exc = false;
+ var test_fourth_exc = false;
+ var test_listener = false;
+
+ function TargetDownHandler(event) {
+ logger("Target receive event: " + event.type);
+ test_target_down = true;
+ try {
+ logger("target.setPointerCapture()");
+ target.setPointerCapture(31415);
+ } catch(exc) {
+ test_first_exc = true;
+ parent.is(exc.name, "InvalidPointerId", "Exception InvalidPointerId should be fired");
+ }
+ try {
+ logger("mediator.setPointerCapture()");
+ mediator.parentNode.removeChild(mediator);
+ mediator.setPointerCapture(event.pointerId);
+ } catch(exc) {
+ test_second_exc = true;
+ parent.is(exc.name, "InvalidStateError", "Exception InvalidStateError should be fired");
+ }
+ try {
+ logger("listener.setPointerCapture()");
+ listener.setPointerCapture(event.pointerId);
+ } catch(exc) {
+ test_third_exc = true;
+ }
+ }
+ function TargetUpHandler(event) {
+ logger("Target receive event: " + event.type);
+ test_target_up = true;
+ try {
+ logger("target.setPointerCapture()");
+ target.setPointerCapture(event.pointerId);
+ } catch(exc) {
+ test_fourth_exc = true;
+ }
+ }
+ function ListenerHandler(event) {
+ logger("Listener receive event: " + event.type);
+ test_listener = true;
+ listener.releasePointerCapture(event.pointerId);
+ }
+ function logger(message) {
+ console.log(message);
+ var log = document.getElementById('log');
+ log.innerHTML = message + "<br>" + log.innerHTML;
+ }
+
+ function prepareTest() {
+ parent.turnOnPointerEvents(executeTest);
+ }
+ function executeTest()
+ {
+ logger("executeTest");
+ target = document.getElementById("target");
+ mediator = document.getElementById("mediator");
+ listener = document.getElementById("listener");
+ target.addEventListener("pointerdown", TargetDownHandler, false);
+ target.addEventListener("pointerup", TargetUpHandler, false);
+ listener.addEventListener("gotpointercapture", ListenerHandler, false);
+ var rect = target.getBoundingClientRect();
+ synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerdown"});
+ synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
+ synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerup"});
+ finishTest();
+ }
+ function finishTest() {
+ setTimeout(function() {
+ parent.is(test_target_down, true, "pointerdown event should be received by target");
+ parent.is(test_target_up, true, "pointerup event should be received by target");
+ parent.is(test_first_exc, true, "first exception should be thrown");
+ parent.is(test_second_exc, true, "second exception should be thrown");
+ parent.is(test_third_exc, false, "third exception should not be thrown");
+ parent.is(test_fourth_exc, false, "fourth exception should not be thrown");
+ parent.is(test_listener, true, "listener should receive gotpointercapture event");
+ logger("finishTest");
+ parent.finishTest();
+ }, 1000);
+ }
+ </script>
+</head>
+<body onload="prepareTest()">
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080361">Mozilla Bug 1080361</a>
+ <div id="target">div id=target</div>
+ <div id="mediator">div id=mediator</div>
+ <div id="listener">div id=listener</div>
+ <pre id="log"></pre>
+</body>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -486,8 +486,10 @@ skip-if = (buildapp == 'b2g' && toolkit
[test_bug687297.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 948948
support-files =
bug687297_a.html
bug687297_b.html
bug687297_c.html
[test_bug990340.html]
[test_bug1070851.html]
+[test_bug1080361.html]
+support-files = bug1080361_inner.html
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug1080361.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1080361
+-->
+ <head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1080361</title>
+ <meta name="author" content="Maksim Lebedev" />
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript">
+ var iframe = undefined;
+ function prepareTest() {
+ SimpleTest.waitForExplicitFinish();
+ iframe = document.getElementById("testFrame");
+ turnOnPointerEvents(startTest);
+ }
+ function turnOnPointerEvents(callback) {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.w3c_pointer_events.enabled", true]
+ ]
+ }, callback);
+ }
+ function startTest() {
+ iframe.src = "bug1080361_inner.html";
+ }
+ function finishTest() {
+ SimpleTest.finish();
+ }
+ </script>
+ </head>
+ <body onload="prepareTest()">
+ <iframe id="testFrame" height="700" width="700"></iframe>
+ </body>
+</html>
--- a/layout/reftests/invalidation/540247-1-ref.xul
+++ b/layout/reftests/invalidation/540247-1-ref.xul
@@ -4,18 +4,17 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script><![CDATA[
document.addEventListener("MozReftestInvalidate", runtest, false);
function runtest() {
document.getElementById('b').height = '100';
- var sbo = document.getElementById('s').boxObject.
- QueryInterface(Components.interfaces.nsIScrollBoxObject);
+ var sbo = document.getElementById('s').boxObject;
sbo.scrollTo(0, 1000);
document.documentElement.className = "";
}
]]>
</script>
<scrollbox id="s" height="200" style="overflow: scroll;">
--- a/layout/reftests/invalidation/540247-1.xul
+++ b/layout/reftests/invalidation/540247-1.xul
@@ -5,18 +5,17 @@
<script><![CDATA[
document.addEventListener("MozReftestInvalidate", runtest, false);
function runtest() {
// Make sure that the effects of the scroll are painted to the screen before
// shrinking the size of the scrolled frame.
window.addEventListener("MozAfterPaint", finish, false);
- var sbo = document.getElementById('s').boxObject.
- QueryInterface(Components.interfaces.nsIScrollBoxObject);
+ var sbo = document.getElementById('s').boxObject;
sbo.scrollTo(0, 1000);
}
function finish() {
document.getElementById('b').height = '100';
document.documentElement.className = "";
}
]]>
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -960,16 +960,17 @@ protected:
}
bool IsParsingCompoundProperty(void) const {
return mParsingCompoundProperty;
}
/* Functions for basic shapes */
bool ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens);
bool ParsePolygonFunction(nsCSSValue& aValue);
+ bool ParseCircleOrEllipseFunction(nsCSSKeyword, nsCSSValue& aValue);
/* Functions for transform Parsing */
bool ParseSingleTransform(bool aIsPrefixed, nsCSSValue& aValue);
bool ParseFunction(nsCSSKeyword aFunction, const int32_t aAllowedTypes[],
int32_t aVariantMaskAll, uint16_t aMinElems,
uint16_t aMaxElems, nsCSSValue &aValue);
bool ParseFunctionInternals(const int32_t aVariantMask[],
int32_t aVariantMaskAll,
@@ -13839,16 +13840,73 @@ CSSParserImpl::ParsePolygonFunction(nsCS
if (numArgs > 1) {
functionArray->Item(1) = fillRuleValue;
}
return true;
}
bool
+CSSParserImpl::ParseCircleOrEllipseFunction(nsCSSKeyword aKeyword,
+ nsCSSValue& aValue)
+{
+ nsCSSValue radiusX, radiusY, position;
+ bool hasRadius = false, hasPosition = false;
+
+ int32_t mask = VARIANT_LPCALC | VARIANT_NONNEGATIVE_DIMENSION |
+ VARIANT_KEYWORD;
+ if (ParseVariant(radiusX, mask, nsCSSProps::kShapeRadiusKTable)) {
+ if (aKeyword == eCSSKeyword_ellipse) {
+ if (!ParseVariant(radiusY, mask, nsCSSProps::kShapeRadiusKTable)) {
+ REPORT_UNEXPECTED_TOKEN(PEExpectedRadius);
+ SkipUntil(')');
+ return false;
+ }
+ }
+ hasRadius = true;
+ }
+
+ if (!ExpectSymbol(')', true)) {
+ if (!GetToken(true)) {
+ REPORT_UNEXPECTED_EOF(PEPositionEOF);
+ return false;
+ }
+
+ if (mToken.mType != eCSSToken_Ident ||
+ !mToken.mIdent.LowerCaseEqualsLiteral("at") ||
+ !ParsePositionValue(position)) {
+ REPORT_UNEXPECTED_TOKEN(PEExpectedPosition);
+ SkipUntil(')');
+ return false;
+ }
+ if (!ExpectSymbol(')', true)) {
+ REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen);
+ SkipUntil(')');
+ return false;
+ }
+ hasPosition = true;
+ }
+
+ size_t count = aKeyword == eCSSKeyword_circle ? 2 : 3;
+ nsRefPtr<nsCSSValue::Array> functionArray =
+ aValue.InitFunction(aKeyword, count);
+ if (hasRadius) {
+ functionArray->Item(1) = radiusX;
+ if (aKeyword == eCSSKeyword_ellipse) {
+ functionArray->Item(2) = radiusY;
+ }
+ }
+ if (hasPosition) {
+ functionArray->Item(count) = position;
+ }
+
+ return true;
+}
+
+bool
CSSParserImpl::ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens)
{
if (!GetToken(true)) {
return false;
}
if (mToken.mType != eCSSToken_Function) {
UngetToken();
@@ -13856,16 +13914,19 @@ CSSParserImpl::ParseBasicShape(nsCSSValu
}
// Specific shape function parsing always consumes tokens.
*aConsumedTokens = true;
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
switch (keyword) {
case eCSSKeyword_polygon:
return ParsePolygonFunction(aValue);
+ case eCSSKeyword_circle:
+ case eCSSKeyword_ellipse:
+ return ParseCircleOrEllipseFunction(keyword, aValue);
default:
return false;
}
}
/* Parse a clip-path url to a <clipPath> element or a basic shape. */
bool CSSParserImpl::ParseClipPath()
{
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1886,16 +1886,22 @@ const KTableValue nsCSSProps::kClipShape
eCSSKeyword_border_box, NS_STYLE_CLIP_SHAPE_SIZING_BORDER,
eCSSKeyword_margin_box, NS_STYLE_CLIP_SHAPE_SIZING_MARGIN,
eCSSKeyword_fill_box, NS_STYLE_CLIP_SHAPE_SIZING_FILL,
eCSSKeyword_stroke_box, NS_STYLE_CLIP_SHAPE_SIZING_STROKE,
eCSSKeyword_view_box, NS_STYLE_CLIP_SHAPE_SIZING_VIEW,
eCSSKeyword_UNKNOWN,-1
};
+const KTableValue nsCSSProps::kShapeRadiusKTable[] = {
+ eCSSKeyword_closest_side, NS_RADIUS_CLOSEST_SIDE,
+ eCSSKeyword_farthest_side, NS_RADIUS_FARTHEST_SIDE,
+ eCSSKeyword_UNKNOWN, -1
+};
+
const KTableValue nsCSSProps::kFilterFunctionKTable[] = {
eCSSKeyword_blur, NS_STYLE_FILTER_BLUR,
eCSSKeyword_brightness, NS_STYLE_FILTER_BRIGHTNESS,
eCSSKeyword_contrast, NS_STYLE_FILTER_CONTRAST,
eCSSKeyword_grayscale, NS_STYLE_FILTER_GRAYSCALE,
eCSSKeyword_invert, NS_STYLE_FILTER_INVERT,
eCSSKeyword_opacity, NS_STYLE_FILTER_OPACITY,
eCSSKeyword_saturate, NS_STYLE_FILTER_SATURATE,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -532,16 +532,17 @@ public:
static const KTableValue kBorderWidthKTable[];
static const KTableValue kBoxAlignKTable[];
static const KTableValue kBoxDecorationBreakKTable[];
static const KTableValue kBoxDirectionKTable[];
static const KTableValue kBoxOrientKTable[];
static const KTableValue kBoxPackKTable[];
static const KTableValue kClipShapeSizingKTable[];
static const KTableValue kDominantBaselineKTable[];
+ static const KTableValue kShapeRadiusKTable[];
static const KTableValue kFillRuleKTable[];
static const KTableValue kFilterFunctionKTable[];
static const KTableValue kImageRenderingKTable[];
static const KTableValue kShapeRenderingKTable[];
static const KTableValue kStrokeLinecapKTable[];
static const KTableValue kStrokeLinejoinKTable[];
static const KTableValue kStrokeContextValueKTable[];
static const KTableValue kVectorEffectKTable[];
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -847,16 +847,66 @@ nsCSSValue::AppendPolygonToString(nsCSSP
nsCSSProps::kFillRuleKTable),
aResult);
aResult.AppendLiteral(", ");
++index;
}
array->Item(index).AppendToString(aProperty, aResult, aSerialization);
}
+inline void
+nsCSSValue::AppendPositionCoordinateToString(
+ const nsCSSValue& aValue, nsCSSProperty aProperty,
+ nsAString& aResult, Serialization aSerialization) const
+{
+ if (aValue.GetUnit() == eCSSUnit_Enumerated) {
+ int32_t intValue = aValue.GetIntValue();
+ AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(intValue,
+ nsCSSProps::kShapeRadiusKTable), aResult);
+ } else {
+ aValue.AppendToString(aProperty, aResult, aSerialization);
+ }
+}
+
+void
+nsCSSValue::AppendCircleOrEllipseToString(nsCSSKeyword aFunctionId,
+ nsCSSProperty aProperty,
+ nsAString& aResult,
+ Serialization aSerialization) const
+{
+ const nsCSSValue::Array* array = GetArrayValue();
+ size_t count = aFunctionId == eCSSKeyword_circle ? 2 : 3;
+ NS_ABORT_IF_FALSE(array->Count() == count + 1, "wrong number of arguments");
+
+ bool hasRadii = array->Item(1).GetUnit() != eCSSUnit_Null;
+
+ AppendPositionCoordinateToString(array->Item(1), aProperty,
+ aResult, aSerialization);
+
+ if (hasRadii && aFunctionId == eCSSKeyword_ellipse) {
+ aResult.Append(' ');
+ AppendPositionCoordinateToString(array->Item(2), aProperty,
+ aResult, aSerialization);
+ }
+
+ // Any position specified?
+ if (array->Item(count).GetUnit() != eCSSUnit_Array) {
+ NS_ABORT_IF_FALSE(array->Item(count).GetUnit() == eCSSUnit_Null,
+ "unexpected value");
+ return;
+ }
+
+ if (hasRadii) {
+ aResult.Append(' ');
+ }
+ aResult.AppendLiteral("at ");
+ array->Item(count).AppendToString(eCSSProperty_background_position,
+ aResult, aSerialization);
+}
+
void
nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
Serialization aSerialization) const
{
// eCSSProperty_UNKNOWN gets used for some recursive calls below.
NS_ABORT_IF_FALSE((0 <= aProperty &&
aProperty <= eCSSProperty_COUNT_no_shorthands) ||
aProperty == eCSSProperty_UNKNOWN,
@@ -986,16 +1036,22 @@ nsCSSValue::AppendToString(nsCSSProperty
nsStyleUtil::AppendEscapedCSSIdent(ident, aResult);
aResult.Append('(');
switch (functionId) {
case eCSSKeyword_polygon:
AppendPolygonToString(aProperty, aResult, aSerialization);
break;
+ case eCSSKeyword_circle:
+ case eCSSKeyword_ellipse:
+ AppendCircleOrEllipseToString(functionId, aProperty, aResult,
+ aSerialization);
+ break;
+
default: {
// Now, step through the function contents, writing each of
// them as we go.
for (size_t index = 1; index < array->Count(); ++index) {
array->Item(index).AppendToString(aProperty, aResult,
aSerialization);
/* If we're not at the final element, append a comma. */
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -716,17 +716,24 @@ public:
private:
static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
return static_cast<char16_t*>(aBuffer->Data());
}
void AppendPolygonToString(nsCSSProperty aProperty, nsAString& aResult,
Serialization aValueSerialization) const;
-
+ void AppendPositionCoordinateToString(const nsCSSValue& aValue,
+ nsCSSProperty aProperty,
+ nsAString& aResult,
+ Serialization aSerialization) const;
+ void AppendCircleOrEllipseToString(
+ nsCSSKeyword aFunctionId,
+ nsCSSProperty aProperty, nsAString& aResult,
+ Serialization aValueSerialization) const;
protected:
nsCSSUnit mUnit;
union {
int32_t mInt;
float mFloat;
// Note: the capacity of the buffer may exceed the length of the string.
// If we're of a string type, mString is not null.
nsStringBuffer* mString;
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5170,51 +5170,103 @@ nsComputedDOMStyle::DoGetLightingColor()
CSSValue*
nsComputedDOMStyle::DoGetStopColor()
{
nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
SetToRGBAColor(val, StyleSVGReset()->mStopColor);
return val;
}
+inline void AppendBasicShapeTypeToString(nsStyleBasicShape::Type aType,
+ nsAutoString& aString)
+{
+ nsCSSKeyword functionName;
+ switch (aType) {
+ case nsStyleBasicShape::Type::ePolygon:
+ functionName = eCSSKeyword_polygon;
+ break;
+ case nsStyleBasicShape::Type::eCircle:
+ functionName = eCSSKeyword_circle;
+ break;
+ case nsStyleBasicShape::Type::eEllipse:
+ functionName = eCSSKeyword_ellipse;
+ break;
+ default:
+ NS_NOTREACHED("unexpected type");
+ }
+ AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(functionName),
+ aString);
+}
+
CSSValue*
nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
{
nsDOMCSSValueList* valueList = GetROCSSValueList(false);
-
- if (aStyleBasicShape &&
- aStyleBasicShape->GetShapeType() == nsStyleBasicShape::Type::ePolygon) {
+ if (aStyleBasicShape) {
+ nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
// Shape function name and opening parenthesis.
nsAutoString shapeFunctionString;
- AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(eCSSKeyword_polygon),
- shapeFunctionString);
+ AppendBasicShapeTypeToString(type, shapeFunctionString);
shapeFunctionString.Append('(');
- bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
- NS_STYLE_FILL_RULE_EVENODD;
- if (hasEvenOdd) {
- shapeFunctionString.AppendLiteral("evenodd");
- }
- for (size_t i = 0; i < aStyleBasicShape->Coordinates().Length(); i += 2) {
- nsAutoString coordString;
- if (i > 0 || hasEvenOdd) {
- shapeFunctionString.AppendLiteral(", ");
+ switch (type) {
+ case nsStyleBasicShape::Type::ePolygon: {
+ bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
+ NS_STYLE_FILL_RULE_EVENODD;
+ if (hasEvenOdd) {
+ shapeFunctionString.AppendLiteral("evenodd");
+ }
+ for (size_t i = 0;
+ i < aStyleBasicShape->Coordinates().Length(); i += 2) {
+ nsAutoString coordString;
+ if (i > 0 || hasEvenOdd) {
+ shapeFunctionString.AppendLiteral(", ");
+ }
+ SetCssTextToCoord(coordString,
+ aStyleBasicShape->Coordinates()[i]);
+ shapeFunctionString.Append(coordString);
+ shapeFunctionString.Append(' ');
+ SetCssTextToCoord(coordString,
+ aStyleBasicShape->Coordinates()[i + 1]);