Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-08-28 16:21:43 -04:00
commit 62f7c5af6c
78 changed files with 1691 additions and 808 deletions

View File

@ -251,6 +251,14 @@ a11y::MakeXPCEvent(AccEvent* aEvent)
return xpEvent.forget(); return xpEvent.forget();
} }
if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) {
AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent);
xpEvent = new xpcAccObjectAttributeChangedEvent(type, acc, doc, domNode,
fromUser,
oac->GetAttribute());
return xpEvent.forget();
}
xpEvent = new xpcAccEvent(type, acc, doc, domNode, fromUser); xpEvent = new xpcAccEvent(type, acc, doc, domNode, fromUser);
return xpEvent.forget(); return xpEvent.forget();
} }

View File

@ -105,7 +105,8 @@ public:
eTextSelChangeEvent, eTextSelChangeEvent,
eSelectionChangeEvent, eSelectionChangeEvent,
eTableChangeEvent, eTableChangeEvent,
eVirtualCursorChangeEvent eVirtualCursorChangeEvent,
eObjectAttrChangedEvent
}; };
static const EventGroup kEventGroup = eGenericEvent; static const EventGroup kEventGroup = eGenericEvent;
@ -494,6 +495,32 @@ private:
int16_t mReason; int16_t mReason;
}; };
/**
* Accessible object attribute changed event.
*/
class AccObjectAttrChangedEvent: public AccEvent
{
public:
AccObjectAttrChangedEvent(Accessible* aAccessible, nsIAtom* aAttribute) :
AccEvent(::nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED, aAccessible),
mAttribute(aAttribute) { }
// AccEvent
static const EventGroup kEventGroup = eObjectAttrChangedEvent;
virtual unsigned int GetEventGroups() const
{
return AccEvent::GetEventGroups() | (1U << eObjectAttrChangedEvent);
}
// AccObjectAttrChangedEvent
nsIAtom* GetAttribute() const { return mAttribute; }
private:
nsCOMPtr<nsIAtom> mAttribute;
virtual ~AccObjectAttrChangedEvent() { }
};
/** /**
* Downcast the generic accessible event object to derived type. * Downcast the generic accessible event object to derived type.
*/ */

View File

@ -1094,9 +1094,11 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
// For aria attributes like drag and drop changes we fire a generic attribute // For aria attributes like drag and drop changes we fire a generic attribute
// change event; at least until native API comes up with a more meaningful event. // change event; at least until native API comes up with a more meaningful event.
uint8_t attrFlags = aria::AttrCharacteristicsFor(aAttribute); uint8_t attrFlags = aria::AttrCharacteristicsFor(aAttribute);
if (!(attrFlags & ATTR_BYPASSOBJ)) if (!(attrFlags & ATTR_BYPASSOBJ)) {
FireDelayedEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED, nsRefPtr<AccEvent> event =
aAccessible); new AccObjectAttrChangedEvent(aAccessible, aAttribute);
FireDelayedEvent(event);
}
nsIContent* elm = aAccessible->GetContent(); nsIContent* elm = aAccessible->GetContent();

View File

@ -18,6 +18,7 @@ XPIDL_SOURCES += [
'nsIAccessibleHyperLink.idl', 'nsIAccessibleHyperLink.idl',
'nsIAccessibleHyperText.idl', 'nsIAccessibleHyperText.idl',
'nsIAccessibleImage.idl', 'nsIAccessibleImage.idl',
'nsIAccessibleObjectAttributeChangedEvent.idl',
'nsIAccessiblePivot.idl', 'nsIAccessiblePivot.idl',
'nsIAccessibleRelation.idl', 'nsIAccessibleRelation.idl',
'nsIAccessibleRetrieval.idl', 'nsIAccessibleRetrieval.idl',

View File

@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIAccessibleEvent.idl"
interface nsIAtom;
/**
* Fired when an attribute of an accessible changes.
*/
[scriptable, builtinclass, uuid(4CA96609-23C8-4771-86E7-77C8B651CA24)]
interface nsIAccessibleObjectAttributeChangedEvent : nsIAccessibleEvent
{
/**
* Return the accessible attribute that changed.
*/
readonly attribute nsIAtom changedAttribute;
};

View File

@ -235,6 +235,10 @@ this.AccessFu = { // jshint ignore:line
}, },
_output: function _output(aPresentationData, aBrowser) { _output: function _output(aPresentationData, aBrowser) {
if (!Utils.isAliveAndVisible(
Utils.AccRetrieval.getAccessibleFor(aBrowser))) {
return;
}
for (let presenter of aPresentationData) { for (let presenter of aPresentationData) {
if (!presenter) { if (!presenter) {
continue; continue;

View File

@ -225,43 +225,30 @@ this.EventManager.prototype = {
this.editState = editState; this.editState = editState;
break; break;
} }
case Events.OBJECT_ATTRIBUTE_CHANGED:
{
let evt = aEvent.QueryInterface(
Ci.nsIAccessibleObjectAttributeChangedEvent);
if (evt.changedAttribute.toString() !== 'aria-hidden') {
// Only handle aria-hidden attribute change.
break;
}
if (Utils.isHidden(aEvent.accessible)) {
this._handleHide(evt);
} else {
this._handleShow(aEvent);
}
break;
}
case Events.SHOW: case Events.SHOW:
{ {
let {liveRegion, isPolite} = this._handleLiveRegion(aEvent, this._handleShow(aEvent);
['additions', 'all']);
// Only handle show if it is a relevant live region.
if (!liveRegion) {
break;
}
// Show for text is handled by the EVENT_TEXT_INSERTED handler.
if (aEvent.accessible.role === Roles.TEXT_LEAF) {
break;
}
this._dequeueLiveEvent(Events.HIDE, liveRegion);
this.present(Presentation.liveRegion(liveRegion, isPolite, false));
break; break;
} }
case Events.HIDE: case Events.HIDE:
{ {
let evt = aEvent.QueryInterface(Ci.nsIAccessibleHideEvent); let evt = aEvent.QueryInterface(Ci.nsIAccessibleHideEvent);
let {liveRegion, isPolite} = this._handleLiveRegion( this._handleHide(evt);
evt, ['removals', 'all']);
if (liveRegion) {
// Hide for text is handled by the EVENT_TEXT_REMOVED handler.
if (aEvent.accessible.role === Roles.TEXT_LEAF) {
break;
}
this._queueLiveEvent(Events.HIDE, liveRegion, isPolite);
} else {
let vc = Utils.getVirtualCursor(this.contentScope.content.document);
if (vc.position &&
(Utils.getState(vc.position).contains(States.DEFUNCT) ||
Utils.isInSubtree(vc.position, aEvent.accessible))) {
this.contentControl.autoMove(
evt.targetPrevSibling || evt.targetParent,
{ moveToFocused: true, delay: 500 });
}
}
break; break;
} }
case Events.TEXT_INSERTED: case Events.TEXT_INSERTED:
@ -306,6 +293,51 @@ this.EventManager.prototype = {
} }
}, },
_handleShow: function _handleShow(aEvent) {
let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
['additions', 'all']);
// Only handle show if it is a relevant live region.
if (!liveRegion) {
return;
}
// Show for text is handled by the EVENT_TEXT_INSERTED handler.
if (aEvent.accessible.role === Roles.TEXT_LEAF) {
return;
}
this._dequeueLiveEvent(Events.HIDE, liveRegion);
this.present(Presentation.liveRegion(liveRegion, isPolite, false));
},
_handleHide: function _handleHide(aEvent) {
let {liveRegion, isPolite} = this._handleLiveRegion(
aEvent, ['removals', 'all']);
let acc = aEvent.accessible;
if (liveRegion) {
// Hide for text is handled by the EVENT_TEXT_REMOVED handler.
if (acc.role === Roles.TEXT_LEAF) {
return;
}
this._queueLiveEvent(Events.HIDE, liveRegion, isPolite);
} else {
let vc = Utils.getVirtualCursor(this.contentScope.content.document);
if (vc.position &&
(Utils.getState(vc.position).contains(States.DEFUNCT) ||
Utils.isInSubtree(vc.position, acc))) {
let position = aEvent.targetPrevSibling || aEvent.targetParent;
if (!position) {
try {
position = acc.previousSibling;
} catch (x) {
// Accessible is unattached from the accessible tree.
position = acc.parent;
}
}
this.contentControl.autoMove(position,
{ moveToFocused: true, delay: 500 });
}
}
},
_handleText: function _handleText(aEvent, aLiveRegion, aIsPolite) { _handleText: function _handleText(aEvent, aLiveRegion, aIsPolite) {
let event = aEvent.QueryInterface(Ci.nsIAccessibleTextChangeEvent); let event = aEvent.QueryInterface(Ci.nsIAccessibleTextChangeEvent);
let isInserted = event.isInserted; let isInserted = event.isInserted;

View File

@ -353,10 +353,16 @@ this.Utils = { // jshint ignore:line
return false; return false;
}, },
isHidden: function isHidden(aAccessible) {
// Need to account for aria-hidden, so can't just check for INVISIBLE
// state.
let hidden = Utils.getAttributes(aAccessible).hidden;
return hidden && hidden === 'true';
},
inHiddenSubtree: function inHiddenSubtree(aAccessible) { inHiddenSubtree: function inHiddenSubtree(aAccessible) {
for (let acc=aAccessible; acc; acc=acc.parent) { for (let acc=aAccessible; acc; acc=acc.parent) {
let hidden = Utils.getAttributes(acc).hidden; if (this.isHidden(acc)) {
if (hidden && JSON.parse(hidden)) {
return true; return true;
} }
} }
@ -789,9 +795,7 @@ PivotContext.prototype = {
if (this._includeInvisible) { if (this._includeInvisible) {
include = true; include = true;
} else { } else {
// Need to account for aria-hidden, so can't just check for INVISIBLE include = !Utils.isHidden(child);
// state.
include = Utils.getAttributes(child).hidden !== 'true';
} }
if (include) { if (include) {
if (aPreorder) { if (aPreorder) {

View File

@ -12,6 +12,8 @@ const nsIAccessibleTextChangeEvent =
Components.interfaces.nsIAccessibleTextChangeEvent; Components.interfaces.nsIAccessibleTextChangeEvent;
const nsIAccessibleVirtualCursorChangeEvent = const nsIAccessibleVirtualCursorChangeEvent =
Components.interfaces.nsIAccessibleVirtualCursorChangeEvent; Components.interfaces.nsIAccessibleVirtualCursorChangeEvent;
const nsIAccessibleObjectAttributeChangedEvent =
Components.interfaces.nsIAccessibleObjectAttributeChangedEvent;
const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates; const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates;
const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole; const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;

View File

@ -1773,6 +1773,43 @@ function textSelectionChecker(aID, aStartOffset, aEndOffset)
} }
} }
/**
* Object attribute changed checker
*/
function objAttrChangedChecker(aID, aAttr)
{
this.__proto__ = new invokerChecker(EVENT_OBJECT_ATTRIBUTE_CHANGED, aID);
this.check = function objAttrChangedChecker_check(aEvent)
{
var event = null;
try {
var event = aEvent.QueryInterface(
nsIAccessibleObjectAttributeChangedEvent);
} catch (e) {
ok(false, "Object attribute changed event was expected");
}
if (!event) {
return;
}
is(event.changedAttribute.toString(), aAttr,
"Wrong attribute name of the object attribute changed event.");
};
this.match = function objAttrChangedChecker_match(aEvent)
{
if (aEvent instanceof nsIAccessibleObjectAttributeChangedEvent) {
var scEvent = aEvent.QueryInterface(
nsIAccessibleObjectAttributeChangedEvent);
return (aEvent.accessible == getAccessible(this.target)) &&
(scEvent.changedAttribute.toString() == aAttr);
}
return false;
};
}
/** /**
* State change checker. * State change checker.
*/ */

View File

@ -20,25 +20,24 @@
* Do tests. * Do tests.
*/ */
var gQueue = null; var gQueue = null;
function updateAttribute(aID, aAttr, aValue) function updateAttribute(aID, aAttr, aValue)
{ {
this.node = getNode(aID); this.node = getNode(aID);
this.accessible = getAccessible(this.node); this.accessible = getAccessible(this.node);
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_OBJECT_ATTRIBUTE_CHANGED, this.accessible), new objAttrChangedChecker(aID, aAttr),
]; ];
this.invoke = function updateAttribute_invoke() this.invoke = function updateAttribute_invoke()
{ {
this.node.setAttribute(aAttr, aValue); this.node.setAttribute(aAttr, aValue);
} };
this.getID = function updateAttribute_getID() this.getID = function updateAttribute_getID()
{ {
return aAttr + " for " + aID + " " + aValue; return aAttr + " for " + aID + " " + aValue;
} };
} }
// Debug stuff. // Debug stuff.

View File

@ -24,6 +24,22 @@
document.getElementById('alert').hidden = true; document.getElementById('alert').hidden = true;
} }
function ariaShowBack() {
document.getElementById('back').setAttribute('aria-hidden', false);
}
function ariaHideBack() {
document.getElementById('back').setAttribute('aria-hidden', true);
}
function ariaShowIframe() {
document.getElementById('iframe').setAttribute('aria-hidden', false);
}
function ariaHideIframe() {
document.getElementById('iframe').setAttribute('aria-hidden', true);
}
</script> </script>
<style> <style>
#windows { #windows {
@ -58,6 +74,7 @@
<body> <body>
<div>Phone status bar</div> <div>Phone status bar</div>
<div id="windows"> <div id="windows">
<button id="back">Back</button>
<div id="appframe"></div> <div id="appframe"></div>
<div role="dialog" id="alert" hidden> <div role="dialog" id="alert" hidden>
<h1>This is an alert!</h1> <h1>This is an alert!</h1>

View File

@ -24,6 +24,7 @@
function doTest() { function doTest() {
var doc = currentTabDocument(); var doc = currentTabDocument();
var iframe = doc.createElement('iframe'); var iframe = doc.createElement('iframe');
iframe.id = 'iframe';
iframe.mozbrowser = true; iframe.mozbrowser = true;
iframe.addEventListener('mozbrowserloadend', function () { iframe.addEventListener('mozbrowserloadend', function () {
var contentTest = new AccessFuContentTest( var contentTest = new AccessFuContentTest(
@ -33,6 +34,9 @@
speak: ['Phone status bar', 'Traversal Rule test document'], speak: ['Phone status bar', 'Traversal Rule test document'],
focused: 'body' focused: 'body'
}], }],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'], speak: ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'],
focused: 'iframe' focused: 'iframe'
@ -79,10 +83,16 @@
[ContentMessages.simpleMovePrevious, { [ContentMessages.simpleMovePrevious, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]}] speak: ['wow', {'string': 'headingLevel', 'args': [1]}]
}], }],
[ContentMessages.simpleMovePrevious, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMovePrevious, { [ContentMessages.simpleMovePrevious, {
speak: ['Phone status bar'] speak: ['Phone status bar']
}], }],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
// Moving to the absolute last item from an embedded document // Moving to the absolute last item from an embedded document
// fails. Bug 972035. // fails. Bug 972035.
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
@ -101,6 +111,9 @@
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document'] speak: ['Phone status bar', 'Traversal Rule test document']
}], }],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'] speak: ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app']
}], }],
@ -134,6 +147,9 @@
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document'] speak: ['Phone status bar', 'Traversal Rule test document']
}], }],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'] speak: ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app']
}], }],
@ -149,6 +165,54 @@
// XXX: Set focus on element in iframe when cursor is outside of it. // XXX: Set focus on element in iframe when cursor is outside of it.
// XXX: Set focus on element in iframe when cursor is in iframe. // XXX: Set focus on element in iframe when cursor is in iframe.
// aria-hidden element that the virtual cursor is positioned on
[ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document']
}],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
[doc.defaultView.ariaHideBack, {
speak: ["wow", {"string": "headingLevel","args": [1]}, "such app"],
}],
// Changing aria-hidden attribute twice and making sure that the event
// is fired only once when the actual change happens.
[doc.defaultView.ariaHideBack],
[doc.defaultView.ariaShowBack],
[ContentMessages.simpleMovePrevious, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
// aria-hidden on the iframe that has the vc.
[ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document']
}],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMoveNext, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app']
}],
[doc.defaultView.ariaHideIframe, {
speak: ['Home', {'string': 'pushbutton'}]
}],
[doc.defaultView.ariaShowIframe],
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
// aria-hidden element and auto Move
[ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document']
}],
[doc.defaultView.ariaHideBack],
[ContentMessages.focusSelector('button#back', false), {
// Must not speak Back button as it is aria-hidden
speak: ["wow", {"string": "headingLevel","args": [1]}, "such app"],
}],
[doc.defaultView.ariaShowBack],
[ContentMessages.focusSelector('button#back', true), null],
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
// Open dialog in outer doc, while cursor is also in outer doc // Open dialog in outer doc, while cursor is also in outer doc
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document'] speak: ['Phone status bar', 'Traversal Rule test document']
@ -169,6 +233,9 @@
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document'] speak: ['Phone status bar', 'Traversal Rule test document']
}], }],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMoveNext, { [ContentMessages.simpleMoveNext, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'] speak: ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app']
}], }],

View File

@ -33,6 +33,16 @@
element.style.display = "block"; element.style.display = "block";
} }
function ariaHide(id) {
var element = document.getElementById(id);
element.setAttribute('aria-hidden', true);
}
function ariaShow(id) {
var element = document.getElementById(id);
element.setAttribute('aria-hidden', false);
}
function udpate(id, text, property) { function udpate(id, text, property) {
var element = document.getElementById(id); var element = document.getElementById(id);
element[property] = text; element[property] = text;
@ -60,7 +70,7 @@
}, { }, {
expected: { expected: {
"eventType": "liveregion-change", "eventType": "liveregion-change",
"data": [{"string": "hidden"},"I will be hidden"], "data": [{"string": "hidden"}, "I will be hidden"],
"options": { "options": {
"enqueue": true "enqueue": true
} }
@ -92,6 +102,54 @@
[show(id) for (id of ["to_show_descendant1", "to_show_descendant2", [show(id) for (id of ["to_show_descendant1", "to_show_descendant2",
"to_show_descendant3", "to_show_descendant4"])]; "to_show_descendant3", "to_show_descendant4"])];
} }
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": true
}
},
action: function action() {
[ariaHide(id) for (id of ["to_hide5", "to_hide6", "to_hide7",
"to_hide8", "to_hide9"])];
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": true
}
},
action: function action() {
[ariaHide(id) for (id of ["to_hide_descendant5", "to_hide_descendant6",
"to_hide_descendant7", "to_hide_descendant8"])];
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": true
}
},
action: function action() {
[ariaShow(id) for (id of ["to_show5", "to_show6", "to_show7",
"to_show8", "to_show9"])];
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": true
}
},
action: function action() {
[ariaShow(id) for (id of ["to_show_descendant5", "to_show_descendant6",
"to_show_descendant7", "to_show_descendant8"])];
}
}, { }, {
expected: { expected: {
"eventType": "liveregion-change", "eventType": "liveregion-change",
@ -103,6 +161,17 @@
action: function action() { action: function action() {
hide("to_hide_live_assertive"); hide("to_hide_live_assertive");
} }
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": false
}
},
action: function action() {
ariaHide("to_hide_live_assertive2");
}
}, { }, {
expected: { expected: {
"eventType": "liveregion-change", "eventType": "liveregion-change",
@ -114,6 +183,18 @@
action: function action() { action: function action() {
[show(id) for (id of ["to_show_live_off", "to_show_live_assertive"])]; [show(id) for (id of ["to_show_live_off", "to_show_live_assertive"])];
} }
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": false
}
},
action: function action() {
[ariaShow(id) for (id of ["to_show_live_off2",
"to_show_live_assertive2"])];
}
}, { }, {
expected: { expected: {
"eventType": "liveregion-change", "eventType": "liveregion-change",
@ -284,6 +365,12 @@
<p id="to_hide3" aria-live="assertive" aria-relevant="text">I should not be announced 3</p> <p id="to_hide3" aria-live="assertive" aria-relevant="text">I should not be announced 3</p>
<p id="to_hide4" aria-live="polite" aria-relevant="all">I will be hidden</p> <p id="to_hide4" aria-live="polite" aria-relevant="all">I will be hidden</p>
<p id="to_hide5" aria-hidden="true">I should not be announced 5</p>
<p id="to_hide6">I should not be announced 6</p>
<p id="to_hide7" aria-live="polite">I should not be announced 7</p>
<p id="to_hide8" aria-live="assertive" aria-relevant="text">I should not be announced 8</p>
<p id="to_hide9" aria-live="polite" aria-relevant="all">I will be hidden</p>
<div> <div>
<p id="to_hide_descendant1">I should not be announced 1</p> <p id="to_hide_descendant1">I should not be announced 1</p>
</div> </div>
@ -297,11 +384,30 @@
<p id="to_hide_descendant4">I will be hidden</p> <p id="to_hide_descendant4">I will be hidden</p>
</div> </div>
<div>
<p id="to_hide_descendant5">I should not be announced 4</p>
</div>
<div aria-live="polite">
<p id="to_hide_descendant6">I should not be announced 5</p>
</div>
<div aria-live="assertive" aria-relevant="text">
<p id="to_hide_descendant7">I should not be announced 6</p>
</div>
<div aria-live="polite" aria-relevant="all">
<p id="to_hide_descendant8">I will be hidden</p>
</div>
<p id="to_show1" style="display: none">I should not be announced 1</p> <p id="to_show1" style="display: none">I should not be announced 1</p>
<p id="to_show2" aria-live="assertive" aria-relevant="text" style="display: none">I should not be announced 2</p> <p id="to_show2" aria-live="assertive" aria-relevant="text" style="display: none">I should not be announced 2</p>
<p id="to_show3" aria-live="polite" aria-relevant="removals" style="display: none">I should not be announced 3</p> <p id="to_show3" aria-live="polite" aria-relevant="removals" style="display: none">I should not be announced 3</p>
<p id="to_show4" aria-live="polite" aria-relevant="all" style="display: none">I will be shown</p> <p id="to_show4" aria-live="polite" aria-relevant="all" style="display: none">I will be shown</p>
<p id="to_show5" aria-hidden="false">I should not be announced 5</p>
<p id="to_show6" aria-hidden="true">I should not be announced 6</p>
<p id="to_show7" aria-hidden="true" aria-live="assertive" aria-relevant="text">I should not be announced 7</p>
<p id="to_show8" aria-hidden="true" aria-live="polite" aria-relevant="removals">I should not be announced 8</p>
<p id="to_show9" aria-hidden="true" aria-live="polite" aria-relevant="all">I will be shown</p>
<div> <div>
<p id="to_show_descendant1" style="display: none">I should not be announced 1</p> <p id="to_show_descendant1" style="display: none">I should not be announced 1</p>
</div> </div>
@ -315,13 +421,34 @@
<p id="to_show_descendant4" style="display: none">I will be shown</p> <p id="to_show_descendant4" style="display: none">I will be shown</p>
</div> </div>
<div>
<p id="to_show_descendant5" aria-hidden="true">I should not be announced 5</p>
</div>
<div aria-live="polite" aria-relevant="removals">
<p id="to_show_descendant6" aria-hidden="true">I should not be announced 6</p>
</div>
<div aria-live="assertive" aria-relevant="text">
<p id="to_show_descendant7" aria-hidden="true">I should not be announced 7</p>
</div>
<div aria-live="polite" aria-relevant="all">
<p id="to_show_descendant8" aria-hidden="true">I will be shown</p>
</div>
<div aria-live="assertive" aria-relevant="all"> <div aria-live="assertive" aria-relevant="all">
<p id="to_hide_live_assertive">I will be hidden</p> <p id="to_hide_live_assertive">I will be hidden</p>
</div> </div>
<div aria-live="assertive" aria-relevant="all">
<p id="to_hide_live_assertive2">I will be hidden</p>
</div>
<p id="to_show_live_assertive" aria-live="assertive" style="display: none">I will be shown</p> <p id="to_show_live_assertive" aria-live="assertive" style="display: none">I will be shown</p>
<p id="to_show_live_off" aria-live="off" style="display: none">I will not be shown</p> <p id="to_show_live_off" aria-live="off" style="display: none">I will not be shown</p>
<p id="to_show_live_assertive2" aria-live="assertive" aria-hidden="true">I will be shown</p>
<p id="to_show_live_off2" aria-live="off" aria-hidden="true">I will not be shown</p>
<div id="to_replace_region" aria-live="polite" aria-relevant="all"> <div id="to_replace_region" aria-live="polite" aria-relevant="all">
<p id="to_replace">I am replaced</p> <p id="to_replace">I am replaced</p>
</div> </div>

View File

@ -12,6 +12,7 @@ simple_events = [
'TextChangeEvent', 'TextChangeEvent',
'HideEvent', 'HideEvent',
'CaretMoveEvent', 'CaretMoveEvent',
'ObjectAttributeChangedEvent',
'TableChangeEvent', 'TableChangeEvent',
'VirtualCursorChangeEvent' 'VirtualCursorChangeEvent'
] ]

View File

@ -103,8 +103,21 @@ function onSubmitStatus(subj, topic, data) {
if (data != "success" && data != "failed") if (data != "success" && data != "failed")
return; return;
let extra = getPropertyBagValue(subj.QueryInterface(Ci.nsIPropertyBag), let propBag = subj.QueryInterface(Ci.nsIPropertyBag);
"extra"); if (data == "success") {
let remoteID = getPropertyBagValue(propBag, "serverCrashID");
ok(!!remoteID, "serverCrashID should be set");
// Remove the submitted report file.
let file = Services.dirsvc.get("UAppData", Ci.nsILocalFile);
file.append("Crash Reports");
file.append("submitted");
file.append(remoteID + ".txt");
ok(file.exists(), "Submitted report file should exist");
file.remove(false);
}
let extra = getPropertyBagValue(propBag, "extra");
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag"); ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
let val = getPropertyBagValue(extra, "PluginUserComment"); let val = getPropertyBagValue(extra, "PluginUserComment");

View File

@ -8756,6 +8756,7 @@ AC_SUBST(VPX_X86_ASM)
AC_SUBST(VPX_ARM_ASM) AC_SUBST(VPX_ARM_ASM)
AC_SUBST(VPX_NEED_OBJ_INT_EXTRACT) AC_SUBST(VPX_NEED_OBJ_INT_EXTRACT)
AC_SUBST(MOZ_INSTRUMENT_EVENT_LOOP) AC_SUBST(MOZ_INSTRUMENT_EVENT_LOOP)
AC_SUBST(MOZ_CODE_COVERAGE)
AC_SUBST(LIBJPEG_TURBO_AS) AC_SUBST(LIBJPEG_TURBO_AS)
AC_SUBST(LIBJPEG_TURBO_ASFLAGS) AC_SUBST(LIBJPEG_TURBO_ASFLAGS)
AC_SUBST(LIBJPEG_TURBO_X86_ASM) AC_SUBST(LIBJPEG_TURBO_X86_ASM)

View File

@ -1500,20 +1500,22 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
// Unset this since that's what the old code effectively did. // Unset this since that's what the old code effectively did.
UnsetFlags(NODE_FORCE_XBL_BINDINGS); UnsetFlags(NODE_FORCE_XBL_BINDINGS);
bool clearBindingParent = true;
#ifdef MOZ_XUL #ifdef MOZ_XUL
nsXULElement* xulElem = nsXULElement::FromContent(this); nsXULElement* xulElem = nsXULElement::FromContent(this);
if (xulElem) { if (xulElem) {
xulElem->SetXULBindingParent(nullptr); xulElem->SetXULBindingParent(nullptr);
clearBindingParent = false;
} }
else
#endif #endif
{
nsDOMSlots *slots = GetExistingDOMSlots(); nsDOMSlots* slots = GetExistingDOMSlots();
if (slots) { if (slots) {
if (clearBindingParent) {
slots->mBindingParent = nullptr; slots->mBindingParent = nullptr;
slots->mContainingShadow = nullptr;
} }
slots->mContainingShadow = nullptr;
} }
// This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree, // This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,

View File

@ -34,6 +34,9 @@ function checkAllowed () {
ok(color === green, "Eval should be allowed"); ok(color === green, "Eval should be allowed");
color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-inline-style-allowed')).color; color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-inline-style-allowed')).color;
ok(color === green, "Inline style should be allowed"); ok(color === green, "Inline style should be allowed");
document.getElementById('cspframe2').src = 'file_CSP_bug885433_blocks.html';
document.getElementById('cspframe2').addEventListener('load', checkBlocked, false);
} }
function checkBlocked () { function checkBlocked () {
@ -52,8 +55,6 @@ function checkBlocked () {
document.getElementById('cspframe').src = 'file_CSP_bug885433_allows.html'; document.getElementById('cspframe').src = 'file_CSP_bug885433_allows.html';
document.getElementById('cspframe').addEventListener('load', checkAllowed, false); document.getElementById('cspframe').addEventListener('load', checkAllowed, false);
document.getElementById('cspframe2').src = 'file_CSP_bug885433_blocks.html';
document.getElementById('cspframe2').addEventListener('load', checkBlocked, false);
</script> </script>
</pre> </pre>
</body> </body>

4
content/html/content/public/HTMLMediaElement.h Normal file → Executable file
View File

@ -1151,6 +1151,10 @@ protected:
// to raise the 'waiting' event as per 4.7.1.8 in HTML 5 specification. // to raise the 'waiting' event as per 4.7.1.8 in HTML 5 specification.
bool mPlayingBeforeSeek; bool mPlayingBeforeSeek;
// if TRUE then the seek started while content was in active playing state
// if FALSE then the seek started while the content was not playing.
bool mPlayingThroughTheAudioChannelBeforeSeek;
// True iff this element is paused because the document is inactive or has // True iff this element is paused because the document is inactive or has
// been suspended by the audio channel service. // been suspended by the audio channel service.
bool mPausedForInactiveDocumentOrChannel; bool mPausedForInactiveDocumentOrChannel;

9
content/html/content/src/HTMLMediaElement.cpp Normal file → Executable file
View File

@ -2034,6 +2034,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mIsCasting(false), mIsCasting(false),
mAudioCaptured(false), mAudioCaptured(false),
mPlayingBeforeSeek(false), mPlayingBeforeSeek(false),
mPlayingThroughTheAudioChannelBeforeSeek(false),
mPausedForInactiveDocumentOrChannel(false), mPausedForInactiveDocumentOrChannel(false),
mEventDeliveryPaused(false), mEventDeliveryPaused(false),
mWaitingFired(false), mWaitingFired(false),
@ -3056,6 +3057,10 @@ void HTMLMediaElement::PlaybackEnded()
void HTMLMediaElement::SeekStarted() void HTMLMediaElement::SeekStarted()
{ {
DispatchAsyncEvent(NS_LITERAL_STRING("seeking")); DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
// Set the Variable if the Seekstarted while active playing
if(mPlayingThroughTheAudioChannel) {
mPlayingThroughTheAudioChannelBeforeSeek = true;
}
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA); ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
FireTimeUpdate(false); FireTimeUpdate(false);
} }
@ -3073,6 +3078,8 @@ void HTMLMediaElement::SeekCompleted()
if (mCurrentPlayRangeStart == -1.0) { if (mCurrentPlayRangeStart == -1.0) {
mCurrentPlayRangeStart = CurrentTime(); mCurrentPlayRangeStart = CurrentTime();
} }
// Unset the variable on seekend
mPlayingThroughTheAudioChannelBeforeSeek = false;
} }
void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended) void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
@ -3913,7 +3920,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
(HasAttr(kNameSpaceID_None, nsGkAtoms::loop) || (HasAttr(kNameSpaceID_None, nsGkAtoms::loop) ||
(mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && (mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
!IsPlaybackEnded()) || !IsPlaybackEnded()) ||
mPlayingBeforeSeek)); mPlayingThroughTheAudioChannelBeforeSeek));
if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) { if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel; mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;

View File

@ -1521,8 +1521,10 @@ nsTextEditorState::UnbindFromFrame(nsTextControlFrame* aFrame)
// If the editor is modified but nsIEditorObserver::EditAction() hasn't been // If the editor is modified but nsIEditorObserver::EditAction() hasn't been
// called yet, we need to notify it here because editor may be destroyed // called yet, we need to notify it here because editor may be destroyed
// before EditAction() is called if selection listener causes flushing layout. // before EditAction() is called if selection listener causes flushing layout.
bool isInEditAction = false;
if (mTextListener && mEditor && mEditorInitialized && if (mTextListener && mEditor && mEditorInitialized &&
mEditor->GetIsInEditAction()) { NS_SUCCEEDED(mEditor->GetIsInEditAction(&isInEditAction)) &&
isInEditAction) {
mTextListener->EditAction(); mTextListener->EditAction();
} }

View File

@ -88,7 +88,9 @@ void GraphDriver::UpdateStateComputedTime(GraphTime aStateComputedTime)
// The next state computed time can be the same as the previous, here: it // The next state computed time can be the same as the previous, here: it
// means the driver would be have been blocking indefinitly, but the graph has // means the driver would be have been blocking indefinitly, but the graph has
// been woken up right after having been to sleep. // been woken up right after having been to sleep.
MOZ_ASSERT(aStateComputedTime >= mStateComputedTime, "State time can't go backward."); if (aStateComputedTime < mStateComputedTime) {
printf("State time can't go backward %ld < %ld.\n", static_cast<long>(aStateComputedTime), static_cast<long>(mStateComputedTime));
}
mStateComputedTime = aStateComputedTime; mStateComputedTime = aStateComputedTime;
} }

View File

@ -1310,12 +1310,14 @@ MediaStreamGraphImpl::Process(GraphTime aFrom, GraphTime aTo)
// Only playback audio and video in real-time mode // Only playback audio and video in real-time mode
if (mRealtime) { if (mRealtime) {
CreateOrDestroyAudioStreams(aFrom, stream); CreateOrDestroyAudioStreams(aFrom, stream);
TrackTicks ticksPlayedForThisStream = PlayAudio(stream, aFrom, aTo); if (CurrentDriver()->AsAudioCallbackDriver()) {
if (!ticksPlayed) { TrackTicks ticksPlayedForThisStream = PlayAudio(stream, aFrom, aTo);
ticksPlayed = ticksPlayedForThisStream; if (!ticksPlayed) {
} else { ticksPlayed = ticksPlayedForThisStream;
MOZ_ASSERT(!ticksPlayedForThisStream || ticksPlayedForThisStream == ticksPlayed, } else {
"Each stream should have the same number of frame."); MOZ_ASSERT(!ticksPlayedForThisStream || ticksPlayedForThisStream == ticksPlayed,
"Each stream should have the same number of frame.");
}
} }
PlayVideo(stream); PlayVideo(stream);
} }

View File

@ -77,4 +77,4 @@ load oscillator-ended-2.html
include ../../mediasource/test/crashtests/crashtests.list include ../../mediasource/test/crashtests/crashtests.list
# This needs to run at the end to avoid leaking busted state into other tests. # This needs to run at the end to avoid leaking busted state into other tests.
load 691096-1.html skip-if(winWidget) load 691096-1.html

View File

@ -240,6 +240,7 @@ AutoJSAPI::AutoJSAPI()
void void
AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread) AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
{ {
MOZ_ASSERT(aCx);
mCx = aCx; mCx = aCx;
if (aIsMainThread) { if (aIsMainThread) {
// This Rooted<> is necessary only as long as AutoCxPusher::AutoCxPusher // This Rooted<> is necessary only as long as AutoCxPusher::AutoCxPusher

View File

@ -991,7 +991,9 @@ IMEContentObserver::FlushMergeableNotifications()
} }
// If we're in handling an edit action, this method will be called later. // If we're in handling an edit action, this method will be called later.
if (mEditor && mEditor->GetIsInEditAction()) { bool isInEditAction = false;
if (mEditor && NS_SUCCEEDED(mEditor->GetIsInEditAction(&isInEditAction)) &&
isInEditAction) {
return; return;
} }

View File

@ -1539,6 +1539,10 @@ PeerConnectionWrapper.prototype = {
* The location the stream is coming from ('local' or 'remote') * The location the stream is coming from ('local' or 'remote')
*/ */
attachMedia : function PCW_attachMedia(stream, type, side) { attachMedia : function PCW_attachMedia(stream, type, side) {
function isSenderOfTrack(sender) {
return sender.track == this;
}
info("Got media stream: " + type + " (" + side + ")"); info("Got media stream: " + type + " (" + side + ")");
this.streams.push(stream); this.streams.push(stream);
@ -1547,9 +1551,13 @@ PeerConnectionWrapper.prototype = {
// way and audio + audiovideo the other. // way and audio + audiovideo the other.
if (type == "video") { if (type == "video") {
this._pc.addStream(stream); this._pc.addStream(stream);
ok(this._pc.getSenders().find(isSenderOfTrack,
stream.getVideoTracks()[0]),
"addStream adds sender");
} else { } else {
stream.getTracks().forEach(function(track) { stream.getTracks().forEach(function(track) {
this._pc.addTrack(track, stream); var sender = this._pc.addTrack(track, stream);
is(sender.track, track, "addTrack returns sender");
}.bind(this)); }.bind(this));
} }
} }

View File

@ -39,19 +39,29 @@ ServiceWorkerContainer::ServiceWorkerContainer(nsPIDOMWindow* aWindow)
ServiceWorkerContainer::~ServiceWorkerContainer() ServiceWorkerContainer::~ServiceWorkerContainer()
{ {
RemoveReadyPromise();
} }
void void
ServiceWorkerContainer::DisconnectFromOwner() ServiceWorkerContainer::DisconnectFromOwner()
{ {
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager(); RemoveReadyPromise();
MOZ_ASSERT(swm);
swm->RemoveReadyPromise(GetOwner());
DOMEventTargetHelper::DisconnectFromOwner(); DOMEventTargetHelper::DisconnectFromOwner();
} }
void
ServiceWorkerContainer::RemoveReadyPromise()
{
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
if (window) {
nsCOMPtr<nsIServiceWorkerManager> swm =
mozilla::services::GetServiceWorkerManager();
MOZ_ASSERT(swm);
swm->RemoveReadyPromise(window);
}
}
JSObject* JSObject*
ServiceWorkerContainer::WrapObject(JSContext* aCx) ServiceWorkerContainer::WrapObject(JSContext* aCx)
{ {

View File

@ -75,6 +75,8 @@ public:
private: private:
~ServiceWorkerContainer(); ~ServiceWorkerContainer();
void RemoveReadyPromise();
// This only changes when a worker hijacks everything in its scope by calling // This only changes when a worker hijacks everything in its scope by calling
// replace(). // replace().
// FIXME(nsm): Bug 982711. Provide API to let SWM invalidate this. // FIXME(nsm): Bug 982711. Provide API to let SWM invalidate this.

View File

@ -1851,6 +1851,7 @@ NS_IMETHODIMP
ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener) ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
{ {
MOZ_ASSERT(aDocumentURI); MOZ_ASSERT(aDocumentURI);
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI); nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
if (!domainInfo) { if (!domainInfo) {
nsCString domain; nsCString domain;
@ -1875,6 +1876,7 @@ ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOME
NS_IMETHODIMP NS_IMETHODIMP
ServiceWorkerManager::RemoveRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener) ServiceWorkerManager::RemoveRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
{ {
AssertIsOnMainThread();
MOZ_ASSERT(aDocumentURI); MOZ_ASSERT(aDocumentURI);
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI); nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
if (!domainInfo) { if (!domainInfo) {

View File

@ -38,6 +38,7 @@ ServiceWorkerRegistration::ServiceWorkerRegistration(nsPIDOMWindow* aWindow,
const nsAString& aScope) const nsAString& aScope)
: DOMEventTargetHelper(aWindow) : DOMEventTargetHelper(aWindow)
, mScope(aScope) , mScope(aScope)
, mListeningForEvents(false)
{ {
MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow()); MOZ_ASSERT(aWindow->IsInnerWindow());
@ -47,6 +48,7 @@ ServiceWorkerRegistration::ServiceWorkerRegistration(nsPIDOMWindow* aWindow,
ServiceWorkerRegistration::~ServiceWorkerRegistration() ServiceWorkerRegistration::~ServiceWorkerRegistration()
{ {
StopListeningForEvents();
} }
void void
@ -176,15 +178,21 @@ ServiceWorkerRegistration::StartListeningForEvents()
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
if (swm) { if (swm) {
swm->AddRegistrationEventListener(GetDocumentURI(), this); swm->AddRegistrationEventListener(GetDocumentURI(), this);
mListeningForEvents = true;
} }
} }
void void
ServiceWorkerRegistration::StopListeningForEvents() ServiceWorkerRegistration::StopListeningForEvents()
{ {
if (!mListeningForEvents) {
return;
}
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
if (swm) { if (swm) {
swm->RemoveRegistrationEventListener(GetDocumentURI(), this); swm->RemoveRegistrationEventListener(GetDocumentURI(), this);
mListeningForEvents = false;
} }
} }

View File

@ -86,6 +86,7 @@ private:
nsRefPtr<workers::ServiceWorker> mActiveWorker; nsRefPtr<workers::ServiceWorker> mActiveWorker;
const nsString mScope; const nsString mScope;
bool mListeningForEvents;
}; };
} // namespace dom } // namespace dom

View File

@ -21,7 +21,7 @@ interface nsIEditActionListener;
interface nsIInlineSpellChecker; interface nsIInlineSpellChecker;
interface nsITransferable; interface nsITransferable;
[builtinclass, scriptable, uuid(c3b61bc9-ccdd-4bcd-acd8-1b8dcbe6a247)] [scriptable, uuid(04714a01-e02f-4ef5-a388-612451d0db16)]
interface nsIEditor : nsISupports interface nsIEditor : nsISupports
{ {
@ -555,5 +555,5 @@ interface nsIEditor : nsISupports
* nsIEditorObserver::BeforeEditAction() and nsIEditorObserver::EditAction() * nsIEditorObserver::BeforeEditAction() and nsIEditorObserver::EditAction()
* or nsIEditorObserver::CancelEditAction(). Otherwise, false. * or nsIEditorObserver::CancelEditAction(). Otherwise, false.
*/ */
[infallible, noscript] readonly attribute boolean isInEditAction; [noscript] readonly attribute boolean isInEditAction;
}; };

View File

@ -22,7 +22,7 @@ class Element;
[ptr] native Element (mozilla::dom::Element); [ptr] native Element (mozilla::dom::Element);
[builtinclass, scriptable, uuid(9470bee7-cad3-4382-8fb4-6bdda9f0273a)] [scriptable, uuid(393a364f-e8e2-48a1-a271-a0067b6bac9b)]
interface nsIHTMLEditor : nsISupports interface nsIHTMLEditor : nsISupports
{ {

View File

@ -5,7 +5,7 @@
#include "nsISupports.idl" #include "nsISupports.idl"
[builtinclass, scriptable, uuid(da8f244b-6ffc-4be1-8b1a-667abfe1d304)] [scriptable, uuid(b74fb158-1265-4102-91eb-edd0136b49f8)]
interface nsIPlaintextEditor : nsISupports interface nsIPlaintextEditor : nsISupports
{ {

View File

@ -103,7 +103,7 @@ FPSCounter::IteratedFullInterval(TimeStamp aTimestamp, double aDuration) {
TimeStamp currentStamp = mFrameTimestamps[mIteratorIndex]; TimeStamp currentStamp = mFrameTimestamps[mIteratorIndex];
TimeDuration duration = aTimestamp - currentStamp; TimeDuration duration = aTimestamp - currentStamp;
return duration.ToSecondsSigDigits() >= aDuration; return duration.ToSeconds() >= aDuration;
} }
void void
@ -187,7 +187,7 @@ FPSCounter::BuildHistogram(std::map<int, int>& aFpsData)
currentTimeStamp = GetNextTimeStamp(); currentTimeStamp = GetNextTimeStamp();
TimeDuration interval = currentIntervalStart - currentTimeStamp; TimeDuration interval = currentIntervalStart - currentTimeStamp;
if (interval.ToSecondsSigDigits() >= 1.0 ) { if (interval.ToSeconds() >= 1.0 ) {
currentIntervalStart = currentTimeStamp; currentIntervalStart = currentTimeStamp;
aFpsData[frameCount]++; aFpsData[frameCount]++;
frameCount = 0; frameCount = 0;

View File

@ -132,7 +132,6 @@ EXIFParser::ParseIFD0(Orientation& aOrientationOut)
return false; return false;
// We should have an orientation value here; go ahead and parse it. // We should have an orientation value here; go ahead and parse it.
Orientation orientation;
if (!ParseOrientation(type, count, aOrientationOut)) if (!ParseOrientation(type, count, aOrientationOut))
return false; return false;

View File

@ -26,11 +26,18 @@
# though this may change if we find a need for additional properties. # though this may change if we find a need for additional properties.
# #
# The Unicode data files listed above should be together in one directory. # The Unicode data files listed above should be together in one directory.
#
# We also require the file # We also require the file
# http://www.unicode.org/Public/security/latest/xidmodifications.txt # http://www.unicode.org/Public/security/latest/xidmodifications.txt
# This file should be in a sub-directory "security" immediately below the # This file should be in a sub-directory "security" immediately below the
# directory containing the other Unicode data files. # directory containing the other Unicode data files.
# #
# We also require the latest data file for UTR50, currently revision-12:
# http://www.unicode.org/Public/vertical/revision-12/VerticalOrientation-12.txt
# This file should be in a sub-directory "vertical" immediately below the
# directory containing the other Unicode data files.
#
#
# (2) Run this tool using a command line of the form # (2) Run this tool using a command line of the form
# #
# perl genUnicodePropertyData.pl \ # perl genUnicodePropertyData.pl \
@ -301,6 +308,13 @@ my %bidicategoryCode = (
"BN" => "18" # Boundary Neutral "BN" => "18" # Boundary Neutral
); );
my %verticalOrientationCode = (
'U' => 0, # U - Upright, the same orientation as in the code charts
'R' => 1, # R - Rotated 90 degrees clockwise compared to the code charts
'Tu' => 2, # Tu - Transformed typographically, with fallback to Upright
'Tr' => 3 # Tr - Transformed typographically, with fallback to Rotated
);
# initialize default properties # initialize default properties
my @script; my @script;
my @category; my @category;
@ -314,6 +328,7 @@ my @numericvalue;
my @hanVariant; my @hanVariant;
my @bidicategory; my @bidicategory;
my @fullWidth; my @fullWidth;
my @verticalOrientation;
for (my $i = 0; $i < 0x110000; ++$i) { for (my $i = 0; $i < 0x110000; ++$i) {
$script[$i] = $scriptCode{"UNKNOWN"}; $script[$i] = $scriptCode{"UNKNOWN"};
$category[$i] = $catCode{"UNASSIGNED"}; $category[$i] = $catCode{"UNASSIGNED"};
@ -324,6 +339,7 @@ for (my $i = 0; $i < 0x110000; ++$i) {
$hanVariant[$i] = 0; $hanVariant[$i] = 0;
$bidicategory[$i] = $bidicategoryCode{"L"}; $bidicategory[$i] = $bidicategoryCode{"L"};
$fullWidth[$i] = 0; $fullWidth[$i] = 0;
$verticalOrientation[$i] = 1; # default for unlisted codepoints is 'R'
} }
# blocks where the default for bidi category is not L # blocks where the default for bidi category is not L
@ -628,6 +644,31 @@ while (<FH>) {
} }
close FH; close FH;
# read VerticalOrientation-12.txt
open FH, "< $ARGV[1]/vertical/VerticalOrientation-12.txt" or die "can't open UTR50 data file VerticalOrientation-12.txt\n";
push @versionInfo, "";
while (<FH>) {
chomp;
push @versionInfo, $_;
last if /Date:/;
}
while (<FH>) {
chomp;
s/#.*//;
if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
my $vo = $3;
warn "unknown Vertical_Orientation code $vo"
unless exists $verticalOrientationCode{$vo};
$vo = $verticalOrientationCode{$vo};
my $start = hex "0x$1";
my $end = (defined $2) ? hex "0x$2" : $start;
for (my $i = $start; $i <= $end; ++$i) {
$verticalOrientation[$i] = $vo;
}
}
}
close FH;
my $timestamp = gmtime(); my $timestamp = gmtime();
open DATA_TABLES, "> nsUnicodePropertyData.cpp" or die "unable to open nsUnicodePropertyData.cpp for output"; open DATA_TABLES, "> nsUnicodePropertyData.cpp" or die "unable to open nsUnicodePropertyData.cpp for output";
@ -706,18 +747,35 @@ sub sprintCharProps1
my $usv = shift; my $usv = shift;
return sprintf("{%d,%d,%d}, ", $mirror[$usv], $hangul[$usv], $combining[$usv]); return sprintf("{%d,%d,%d}, ", $mirror[$usv], $hangul[$usv], $combining[$usv]);
} }
&genTables("CharProp1", "struct nsCharProps1 {\n unsigned char mMirrorOffsetIndex:5;\n unsigned char mHangulType:3;\n unsigned char mCombiningClass:8;\n};", my $type = q/
"nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1); struct nsCharProps1 {
unsigned char mMirrorOffsetIndex:5;
unsigned char mHangulType:3;
unsigned char mCombiningClass:8;
};
/;
&genTables("CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1);
sub sprintCharProps2 sub sprintCharProps2
{ {
my $usv = shift; my $usv = shift;
return sprintf("{%d,%d,%d,%d,%d,%d},", return sprintf("{%d,%d,%d,%d,%d,%d,%d},",
$script[$usv], $eaw[$usv], $category[$usv], $script[$usv], $eaw[$usv], $category[$usv],
$bidicategory[$usv], $xidmod[$usv], $numericvalue[$usv]); $bidicategory[$usv], $xidmod[$usv], $numericvalue[$usv],
$verticalOrientation[$usv]);
} }
&genTables("CharProp2", "struct nsCharProps2 {\n unsigned char mScriptCode:8;\n unsigned char mEAW:3;\n unsigned char mCategory:5;\n unsigned char mBidiCategory:5;\n unsigned char mXidmod:4;\n signed char mNumericValue:5;\n unsigned char mHanVariant:2;\n};", $type = q/
"nsCharProps2", 11, 5, \&sprintCharProps2, 16, 4, 1); struct nsCharProps2 {
unsigned char mScriptCode:8;
unsigned char mEAW:3;
unsigned char mCategory:5;
unsigned char mBidiCategory:5;
unsigned char mXidmod:4;
signed char mNumericValue:5;
unsigned char mVertOrient:2;
};
/;
&genTables("CharProp2", $type, "nsCharProps2", 11, 5, \&sprintCharProps2, 16, 4, 1);
print HEADER "#pragma pack()\n\n"; print HEADER "#pragma pack()\n\n";

View File

@ -49,6 +49,18 @@ inline nsCharType GetBidiCat(uint32_t aCh) {
return nsCharType(GetCharProps2(aCh).mBidiCategory); return nsCharType(GetCharProps2(aCh).mBidiCategory);
} }
/* This MUST match the values assigned by genUnicodePropertyData.pl! */
enum VerticalOrientation {
VERTICAL_ORIENTATION_U = 0,
VERTICAL_ORIENTATION_R = 1,
VERTICAL_ORIENTATION_Tu = 2,
VERTICAL_ORIENTATION_Tr = 3
};
inline VerticalOrientation GetVerticalOrientation(uint32_t aCh) {
return VerticalOrientation(GetCharProps2(aCh).mVertOrient);
}
enum XidmodType { enum XidmodType {
XIDMOD_INCLUSION, XIDMOD_INCLUSION,
XIDMOD_RECOMMENDED, XIDMOD_RECOMMENDED,

File diff suppressed because one or more lines are too long

View File

@ -11,7 +11,7 @@
*/ */
/* /*
* Created on Fri Aug 22 16:49:19 2014 from UCD data files with version info: * Created on Tue Aug 26 10:16:12 2014 from UCD data files with version info:
* *
# Date: 2014-06-12, 20:18:00 GMT [KW] # Date: 2014-06-12, 20:18:00 GMT [KW]
@ -52,6 +52,9 @@ Standard.
# Unihan_Variants.txt # Unihan_Variants.txt
# Date: 2014-05-09 18:17:02 GMT [JHJ] # Date: 2014-05-09 18:17:02 GMT [JHJ]
# VerticalOrientation-12.txt
# Date: 2014-07-07, 21:00:00 GMT [EM, KI, LI]
* *
* * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
*/ */
@ -61,22 +64,26 @@ Standard.
#pragma pack(1) #pragma pack(1)
struct nsCharProps1 { struct nsCharProps1 {
unsigned char mMirrorOffsetIndex:5; unsigned char mMirrorOffsetIndex:5;
unsigned char mHangulType:3; unsigned char mHangulType:3;
unsigned char mCombiningClass:8; unsigned char mCombiningClass:8;
}; };
struct nsCharProps2 { struct nsCharProps2 {
unsigned char mScriptCode:8; unsigned char mScriptCode:8;
unsigned char mEAW:3; unsigned char mEAW:3;
unsigned char mCategory:5; unsigned char mCategory:5;
unsigned char mBidiCategory:5; unsigned char mBidiCategory:5;
unsigned char mXidmod:4; unsigned char mXidmod:4;
signed char mNumericValue:5; signed char mNumericValue:5;
unsigned char mHanVariant:2; unsigned char mVertOrient:2;
}; };
#pragma pack() #pragma pack()
enum { enum {

View File

@ -138,7 +138,7 @@ class SplayTree
template <class Op> template <class Op>
void forEach(Op op) void forEach(Op op)
{ {
forEachInner(op, root); forEachInner<Op>(op, root);
} }
private: private:
@ -245,9 +245,9 @@ class SplayTree
if (!node) if (!node)
return; return;
forEachInner(op, node->left); forEachInner<Op>(op, node->left);
op(node->item); op(node->item);
forEachInner(op, node->right); forEachInner<Op>(op, node->right);
} }
Node *checkCoherency(Node *node, Node *minimum) Node *checkCoherency(Node *node, Node *minimum)

View File

@ -1,3 +1,6 @@
if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
quit();
Random = { Random = {
weighted: function(wa) { weighted: function(wa) {
var a = []; var a = [];
@ -128,4 +131,4 @@ testMathyFunction(mathy2, [-0])
mathy5 = (function(y) { mathy5 = (function(y) {
((function() {})(mathy2(y)())) ((function() {})(mathy2(y)()))
}) })
testMathyFunction(mathy5, [Math.PI]) testMathyFunction(mathy5, [Math.PI])

View File

@ -18,6 +18,13 @@ assertEq(fScripts.indexOf(fw.script) != -1, true);
assertEq(fScripts.indexOf(ggw.script), -1); assertEq(fScripts.indexOf(ggw.script), -1);
assertEq(fScripts.indexOf(hw.script), -1); assertEq(fScripts.indexOf(hw.script), -1);
fScripts = dbg.findScripts({ displayURL: "f.js",
line: 1 });
assertEq(fScripts.indexOf(fw.script) != -1, true);
assertEq(fScripts.indexOf(ggw.script), -1);
assertEq(fScripts.indexOf(hw.script), -1);
var gScripts = dbg.findScripts({ displayURL: "g.js" }); var gScripts = dbg.findScripts({ displayURL: "g.js" });
assertEq(gScripts.indexOf(ggw.script) != -1, true); assertEq(gScripts.indexOf(ggw.script) != -1, true);
assertEq(gScripts.indexOf(fw.script), -1); assertEq(gScripts.indexOf(fw.script), -1);

View File

@ -0,0 +1,20 @@
var g = newGlobal();
var dbg = new Debugger();
var gw = dbg.addDebuggee(g);
g.eval('function f(){}');
var o = gw.makeDebuggeeValue(g.f);
var allScripts = dbg.findScripts();
var scripts = dbg.findScripts({
source: o.script.source
});
assertEq(scripts.length < allScripts.length, true);
assertEq(scripts.indexOf(o.script) !== -1, true);
scripts = dbg.findScripts({
source: o.script.source,
line: 1
});
assertEq(scripts.indexOf(o.script) !== -1, true);

View File

@ -371,8 +371,8 @@ MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY, 3, JSEXN_TYPEERR, "{0} is {1}{2}a global
MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 0, JSEXN_TYPEERR, "value is not a function or undefined") MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 0, JSEXN_TYPEERR, "value is not a function or undefined")
MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true") MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true")
MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so") MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so")
MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'innermost' property without both 'url' and 'line' properties") MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object with 'innermost' property must have 'line' and either 'displayURL', 'url', or 'source'")
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'url' property") MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'displayURL', 'url', or 'source' property")
// Intl // Intl
MSG_DEF(JSMSG_DATE_NOT_FINITE, 0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()") MSG_DEF(JSMSG_DATE_NOT_FINITE, 0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()")

View File

@ -2514,16 +2514,19 @@ Debugger::removeDebuggeeGlobalUnderGC(FreeOp *fop, GlobalObject *global,
global->compartment()->removeDebuggeeUnderGC(fop, global, invalidate, compartmentEnum); global->compartment()->removeDebuggeeUnderGC(fop, global, invalidate, compartmentEnum);
} }
static inline ScriptSourceObject *GetSourceReferent(JSObject *obj);
/* /*
* A class for parsing 'findScripts' query arguments and searching for * A class for parsing 'findScripts' query arguments and searching for
* scripts that match the criteria they represent. * scripts that match the criteria they represent.
*/ */
class Debugger::ScriptQuery { class MOZ_STACK_CLASS Debugger::ScriptQuery
{
public: public:
/* Construct a ScriptQuery to use matching scripts for |dbg|. */ /* Construct a ScriptQuery to use matching scripts for |dbg|. */
ScriptQuery(JSContext *cx, Debugger *dbg): ScriptQuery(JSContext *cx, Debugger *dbg):
cx(cx), debugger(dbg), compartments(cx->runtime()), url(cx), displayURLString(cx), cx(cx), debugger(dbg), compartments(cx->runtime()), url(cx), displayURLString(cx),
innermostForCompartment(cx->runtime()) source(cx), innermostForCompartment(cx->runtime())
{} {}
/* /*
@ -2579,6 +2582,39 @@ class Debugger::ScriptQuery {
return false; return false;
} }
/* Check for a 'source' property */
RootedValue debuggerSource(cx);
if (!JSObject::getProperty(cx, query, query, cx->names().source, &debuggerSource))
return false;
if (!debuggerSource.isUndefined()) {
if (!debuggerSource.isObject() ||
debuggerSource.toObject().getClass() != &DebuggerSource_class) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
"query object's 'source' property",
"not undefined nor a Debugger.Source object");
return false;
}
source = GetSourceReferent(&debuggerSource.toObject());
}
/* Check for a 'displayURL' property. */
RootedValue displayURL(cx);
if (!JSObject::getProperty(cx, query, query, cx->names().displayURL, &displayURL))
return false;
if (!displayURL.isUndefined() && !displayURL.isString()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
"query object's 'displayURL' property",
"neither undefined nor a string");
return false;
}
if (displayURL.isString()) {
displayURLString = displayURL.toString()->ensureLinear(cx);
if (!displayURLString)
return false;
}
/* Check for a 'line' property. */ /* Check for a 'line' property. */
RootedValue lineProperty(cx); RootedValue lineProperty(cx);
if (!JSObject::getProperty(cx, query, query, cx->names().line, &lineProperty)) if (!JSObject::getProperty(cx, query, query, cx->names().line, &lineProperty))
@ -2586,7 +2622,7 @@ class Debugger::ScriptQuery {
if (lineProperty.isUndefined()) { if (lineProperty.isUndefined()) {
hasLine = false; hasLine = false;
} else if (lineProperty.isNumber()) { } else if (lineProperty.isNumber()) {
if (url.isUndefined()) { if (displayURL.isUndefined() && url.isUndefined() && !source) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_QUERY_LINE_WITHOUT_URL); JSMSG_QUERY_LINE_WITHOUT_URL);
return false; return false;
@ -2613,30 +2649,13 @@ class Debugger::ScriptQuery {
innermost = ToBoolean(innermostProperty); innermost = ToBoolean(innermostProperty);
if (innermost) { if (innermost) {
/* Technically, we need only check hasLine, but this is clearer. */ /* Technically, we need only check hasLine, but this is clearer. */
if (url.isUndefined() || !hasLine) { if ((displayURL.isUndefined() && url.isUndefined() && !source) || !hasLine) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL); JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL);
return false; return false;
} }
} }
/* Check for a 'displayURL' property. */
RootedValue displayURL(cx);
if (!JSObject::getProperty(cx, query, query, cx->names().displayURL, &displayURL))
return false;
if (!displayURL.isUndefined() && !displayURL.isString()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
"query object's 'displayURL' property",
"neither undefined nor a string");
return false;
}
if (displayURL.isString()) {
displayURLString = displayURL.toString()->ensureLinear(cx);
if (!displayURLString)
return false;
}
return true; return true;
} }
@ -2719,6 +2738,12 @@ class Debugger::ScriptQuery {
* it. */ * it. */
RootedLinearString displayURLString; RootedLinearString displayURLString;
/*
* If this is a source object, matching scripts will have sources
* equal to this instance.
*/
RootedScriptSource source;
/* True if the query contained a 'line' property. */ /* True if the query contained a 'line' property. */
bool hasLine; bool hasLine;
@ -2841,6 +2866,8 @@ class Debugger::ScriptQuery {
if (CompareChars(s, js_strlen(s), displayURLString) != 0) if (CompareChars(s, js_strlen(s), displayURLString) != 0)
return; return;
} }
if (source && source != script->sourceObject())
return;
if (innermost) { if (innermost) {
/* /*

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<body>
<div style="display: -moz-grid-line;">
<div style="position: relative; direction: rtl;">
<div style="position: absolute;">
</div>
</div>
</div>
</body>
</html>

View File

@ -546,4 +546,5 @@ load outline-on-frameset.xhtml
pref(font.size.inflation.minTwips,200) load 1032450.html pref(font.size.inflation.minTwips,200) load 1032450.html
load 1037903.html load 1037903.html
load 1039454-1.html load 1039454-1.html
load 1058954-1.html
load 1042489.html load 1042489.html

View File

@ -608,7 +608,8 @@ FloatMarginWidth(const nsHTMLReflowState& aCBReflowState,
aCBReflowState.ComputedSize(fosWM), aCBReflowState.ComputedSize(fosWM),
aFloatAvailableWidth, aFloatAvailableWidth,
aFloatOffsetState.ComputedLogicalMargin().Size(fosWM), aFloatOffsetState.ComputedLogicalMargin().Size(fosWM),
aFloatOffsetState.ComputedLogicalBorderPadding().Size(fosWM), aFloatOffsetState.ComputedLogicalBorderPadding().Size(fosWM) -
aFloatOffsetState.ComputedLogicalPadding().Size(fosWM),
aFloatOffsetState.ComputedLogicalPadding().Size(fosWM), aFloatOffsetState.ComputedLogicalPadding().Size(fosWM),
true).Width(fosWM) + true).Width(fosWM) +
aFloatOffsetState.ComputedPhysicalMargin().LeftRight() + aFloatOffsetState.ComputedPhysicalMargin().LeftRight() +

View File

@ -8146,7 +8146,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
const WritingMode outerWM = aState.OuterReflowState() ? const WritingMode outerWM = aState.OuterReflowState() ?
aState.OuterReflowState()->GetWritingMode() : ourWM; aState.OuterReflowState()->GetWritingMode() : ourWM;
nsHTMLReflowMetrics desiredSize(outerWM); nsHTMLReflowMetrics desiredSize(outerWM);
LogicalSize ourSize = GetLogicalSize().ConvertTo(outerWM, ourWM); LogicalSize ourSize = GetLogicalSize(outerWM);
if (rendContext) { if (rendContext) {
@ -8186,7 +8186,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
} }
// Should we do this if IsCollapsed() is true? // Should we do this if IsCollapsed() is true?
LogicalSize size(GetLogicalSize().ConvertTo(outerWM, ourWM)); LogicalSize size(GetLogicalSize(outerWM));
desiredSize.ISize(outerWM) = size.ISize(outerWM); desiredSize.ISize(outerWM) = size.ISize(outerWM);
desiredSize.BSize(outerWM) = size.BSize(outerWM); desiredSize.BSize(outerWM) = size.BSize(outerWM);
desiredSize.UnionOverflowAreasWithDesiredBounds(); desiredSize.UnionOverflowAreasWithDesiredBounds();
@ -8195,7 +8195,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
// Set up a |reflowState| to pass into ReflowAbsoluteFrames // Set up a |reflowState| to pass into ReflowAbsoluteFrames
nsHTMLReflowState reflowState(aState.PresContext(), this, nsHTMLReflowState reflowState(aState.PresContext(), this,
aState.GetRenderingContext(), aState.GetRenderingContext(),
LogicalSize(ourWM, size.ISize(ourWM), LogicalSize(ourWM, ISize(),
NS_UNCONSTRAINEDSIZE), NS_UNCONSTRAINEDSIZE),
nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE); nsHTMLReflowState::DUMMY_PARENT_REFLOW_STATE);

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>bug 1059167</title>
<style type="text/css">
body {
width: 200px;
height: 200px;
border: 1px solid black;
}
.item {
width: 100px;
margin-left: 80px;
padding: 1rem;
background: red;
box-sizing: border-box;
}
p {
background: blue;
}
</style>
</head>
<body>
<div class="item"><p>Content</p></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>bug 1059167</title>
<style type="text/css">
body {
width: 200px;
height: 200px;
border: 1px solid black;
}
.item {
width: 100px;
margin-right: 20px;
padding: 1rem;
background: red;
box-sizing: border-box;
float:right;
}
p {
background: blue;
}
</style>
</head>
<body>
<div class="item"><p>Content</p></div>
</body>
</html>

View File

@ -1824,3 +1824,4 @@ pref(browser.display.use_document_fonts,0) == 1022481-1.html 1022481-1-ref.html
== 1050788-1.html about:blank == 1050788-1.html about:blank
== 1053035-1-flex.html 1053035-1-ref.html == 1053035-1-flex.html 1053035-1-ref.html
test-pref(layout.css.grid.enabled,true) == 1053035-1-grid.html 1053035-1-ref.html test-pref(layout.css.grid.enabled,true) == 1053035-1-grid.html 1053035-1-ref.html
== 1059167-1.html 1059167-1-ref.html

View File

@ -706,18 +706,17 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
return CUBEB_ERROR; return CUBEB_ERROR;
} }
int64_t compensated_position = samplerate * (msec - mixer_latency) / 1000;
pthread_mutex_lock(&stm->mutex); pthread_mutex_lock(&stm->mutex);
int64_t maximum_position = stm->written * (int64_t)stm->inputrate / stm->outputrate; int64_t maximum_position = stm->written * (int64_t)stm->inputrate / stm->outputrate;
pthread_mutex_unlock(&stm->mutex); pthread_mutex_unlock(&stm->mutex);
assert(maximum_position >= 0); assert(maximum_position >= 0);
if (compensated_position < 0) { if (msec > mixer_latency) {
*position = 0; int64_t unadjusted_position = samplerate * (msec - mixer_latency) / 1000;
} else if(compensated_position > maximum_position) { *position = unadjusted_position < maximum_position ?
*position = maximum_position; unadjusted_position : maximum_position;
} else { } else {
*position = compensated_position; *position = 0;
} }
return CUBEB_OK; return CUBEB_OK;
} }

View File

@ -0,0 +1,43 @@
# 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/.
from __future__ import print_function
import argparse
import sys
from mozpack.files import FileFinder
from mozpack.copier import Jarrer
def package_gcno_tree(root, output_file):
# XXX JarWriter doesn't support unicode strings, see bug 1056859
if isinstance(root, unicode):
root = root.encode('utf-8')
finder = FileFinder(root)
jarrer = Jarrer(optimize=False)
for p, f in finder.find("**/*.gcno"):
jarrer.add(p, f)
jarrer.copy(output_file)
def cli(args=sys.argv[1:]):
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output-file',
dest='output_file',
help='Path to save packaged data to.')
parser.add_argument('--root',
dest='root',
default=None,
help='Root directory to search from.')
args = parser.parse_args(args)
if not args.root:
from buildconfig import topobjdir
args.root = topobjdir
return package_gcno_tree(args.root, args.output_file)
if __name__ == '__main__':
sys.exit(cli())

View File

@ -300,12 +300,7 @@ let TPS = {
Logger.logInfo("tab for " + taburi + " finished loading"); Logger.logInfo("tab for " + taburi + " finished loading");
if (that._tabsFinished == that._tabsAdded) { if (that._tabsFinished == that._tabsAdded) {
Logger.logInfo("all tabs loaded, continuing..."); Logger.logInfo("all tabs loaded, continuing...");
that.FinishAsyncOperation();
// Wait a second before continuing to be sure tabs can be synced,
// otherwise we can get 'error locating tab'
Utils.namedTimer(function () {
that.FinishAsyncOperation();
}, 1000, this, "postTabsOpening");
} }
}); });
break; break;
@ -895,7 +890,13 @@ let TPS = {
this._triggeredSync = true; this._triggeredSync = true;
this.StartAsyncOperation(); this.StartAsyncOperation();
Weave.Service.sync();
// Bug 682446
// We wait a little before we trigger the Sync call to be sure elements are
// ready to be synced
Utils.namedTimer(function () {
Weave.Service.sync();
}, 2500, this, "beforeSyncDelay");
}, },
WipeServer: function TPS__WipeServer() { WipeServer: function TPS__WipeServer() {

View File

@ -93,9 +93,6 @@ class GeckoInstance(object):
'logfile': self.gecko_log}) 'logfile': self.gecko_log})
self.runner.start() self.runner.start()
def check_for_crashes(self):
return self.runner.check_for_crashes()
def close(self): def close(self):
if self.runner: if self.runner:
self.runner.stop() self.runner.stop()

View File

@ -725,12 +725,13 @@ class Marionette(object):
name = None name = None
crashed = False crashed = False
if self.runner: if self.runner:
if self.runner.check_for_crashes(): if self.runner.check_for_crashes(test_name=self.test_name):
returncode = self.emulator.proc.returncode returncode = self.emulator.proc.returncode
name = 'emulator' name = 'emulator'
crashed = True crashed = True
elif self.instance: elif self.instance:
if self.instance.check_for_crashes(): if self.instance.runner.check_for_crashes(
test_name=self.test_name):
crashed = True crashed = True
if returncode is not None: if returncode is not None:
print ('PROCESS-CRASH | %s | abnormal termination with exit code %d' % print ('PROCESS-CRASH | %s | abnormal termination with exit code %d' %

View File

@ -282,7 +282,6 @@ class BaseMarionetteOptions(OptionParser):
self.add_option('--type', self.add_option('--type',
dest='type', dest='type',
action='store', action='store',
default='browser+b2g',
help="the type of test to run, can be a combination of values defined in the manifest file; " help="the type of test to run, can be a combination of values defined in the manifest file; "
"individual values are combined with '+' or '-' characters. for example: 'browser+b2g' " "individual values are combined with '+' or '-' characters. for example: 'browser+b2g' "
"means the set of tests which are compatible with both browser and b2g; 'b2g-qemu' means " "means the set of tests which are compatible with both browser and b2g; 'b2g-qemu' means "
@ -957,4 +956,9 @@ class BaseMarionetteTestRunner(object):
_extract_xml_from_skipped_manifest_test(test) _extract_xml_from_skipped_manifest_test(test)
doc.appendChild(testsuite) doc.appendChild(testsuite)
# change default encoding to avoid encoding problem for page source
reload(sys)
sys.setdefaultencoding('utf-8')
return doc.toprettyxml(encoding='utf-8') return doc.toprettyxml(encoding='utf-8')

View File

@ -158,7 +158,7 @@ def setup_logging(suite, args, defaults=None):
formatters[formatter] = [] formatters[formatter] = []
for value in values: for value in values:
found = True found = True
if isinstance(value, str): if isinstance(value, basestring):
value = log_file(value) value = log_file(value)
if value == sys.stdout: if value == sys.stdout:
found_stdout_logger = True found_stdout_logger = True

View File

@ -1,10 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import argparse import argparse
import json
import optparse import optparse
import os import os
import unittest
import StringIO import StringIO
import json import sys
import unittest
import mozfile import mozfile
from mozlog.structured import ( from mozlog.structured import (
@ -501,6 +503,15 @@ class TestCommandline(unittest.TestCase):
self.assertEqual(len(logger.handlers), 1) self.assertEqual(len(logger.handlers), 1)
self.assertIsInstance(logger.handlers[0], handlers.StreamHandler) self.assertIsInstance(logger.handlers[0], handlers.StreamHandler)
def test_setup_logging_optparse_unicode(self):
parser = optparse.OptionParser()
commandline.add_logging_group(parser)
args, _ = parser.parse_args([u"--log-raw=-"])
logger = commandline.setup_logging("test_optparse_unicode", args, {})
self.assertEqual(len(logger.handlers), 1)
self.assertEqual(logger.handlers[0].stream, sys.stdout)
self.assertIsInstance(logger.handlers[0], handlers.StreamHandler)
def test_logging_defaultlevel(self): def test_logging_defaultlevel(self):
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
commandline.add_logging_group(parser) commandline.add_logging_group(parser)

View File

@ -125,10 +125,11 @@ class DeviceRunner(BaseRunner):
def on_finish(self): def on_finish(self):
self.check_for_crashes() self.check_for_crashes()
def check_for_crashes(self): def check_for_crashes(self, test_name=None):
test_name = test_name or self.last_test
dump_dir = self.device.pull_minidumps() dump_dir = self.device.pull_minidumps()
crashed = BaseRunner.check_for_crashes(self, dump_directory=dump_dir, crashed = BaseRunner.check_for_crashes(
test_name=self.last_test) self, dump_directory=dump_dir, test_name=test_name)
mozfile.remove(dump_dir) mozfile.remove(dump_dir)
return crashed return crashed

View File

@ -1073,7 +1073,7 @@ function do_get_profile() {
prop == "ProfLDS" || prop == "TmpD") { prop == "ProfLDS" || prop == "TmpD") {
return file.clone(); return file.clone();
} }
throw Components.results.NS_ERROR_FAILURE; return null;
}, },
QueryInterface: function(iid) { QueryInterface: function(iid) {
if (iid.equals(Components.interfaces.nsIDirectoryServiceProvider) || if (iid.equals(Components.interfaces.nsIDirectoryServiceProvider) ||

View File

@ -367,6 +367,21 @@ this.CrashManager.prototype = Object.freeze({
}.bind(this)); }.bind(this));
}, },
/**
* Record the remote ID for a crash.
*
* @param crashID (string) Crash ID. Likely a UUID.
* @param remoteID (Date) Server/Breakpad ID.
*
* @return boolean True if the remote ID was recorded.
*/
setRemoteCrashID: Task.async(function* (crashID, remoteID) {
let store = yield this._getStore();
if (store.setRemoteCrashID(crashID, remoteID)) {
yield store.save();
}
}),
/** /**
* Record the occurrence of a submission attempt for a crash. * Record the occurrence of a submission attempt for a crash.
* *
@ -1005,6 +1020,7 @@ CrashStore.prototype = Object.freeze({
if (!this._data.crashes.has(id)) { if (!this._data.crashes.has(id)) {
this._data.crashes.set(id, { this._data.crashes.set(id, {
id: id, id: id,
remoteID: null,
type: type, type: type,
crashDate: date, crashDate: date,
submissions: new Map(), submissions: new Map(),
@ -1032,6 +1048,19 @@ CrashStore.prototype = Object.freeze({
return !!this._ensureCrashRecord(processType, crashType, id, date); return !!this._ensureCrashRecord(processType, crashType, id, date);
}, },
/**
* @return boolean True if the remote ID was recorded and false if not.
*/
setRemoteCrashID: function (crashID, remoteID) {
let crash = this._data.crashes.get(crashID);
if (!crash || !remoteID) {
return false;
}
crash.remoteID = remoteID;
return true;
},
getCrashesOfType: function (processType, crashType) { getCrashesOfType: function (processType, crashType) {
let crashes = []; let crashes = [];
for (let crash of this.crashes) { for (let crash of this.crashes) {
@ -1126,6 +1155,10 @@ CrashRecord.prototype = Object.freeze({
return this._o.id; return this._o.id;
}, },
get remoteID() {
return this._o.remoteID;
},
get crashDate() { get crashDate() {
return this._o.crashDate; return this._o.crashDate;
}, },

View File

@ -353,3 +353,12 @@ add_task(function* test_addSubmissionAttemptAndResult() {
Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime()); Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime());
Assert.equal(submission.result, m.SUBMISSION_RESULT_OK); Assert.equal(submission.result, m.SUBMISSION_RESULT_OK);
}); });
add_task(function* test_setRemoteCrashID() {
let m = yield getManager();
yield m.addCrash(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_CRASH,
"main-crash", DUMMY_DATE);
yield m.setRemoteCrashID("main-crash", "bp-1");
Assert.equal((yield m.getCrashes())[0].remoteID, "bp-1");
});

View File

@ -90,6 +90,7 @@ add_task(function test_save_load() {
Assert.ok(s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id2", d2)); Assert.ok(s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id2", d2));
Assert.ok(s.addSubmissionAttempt("id1", "sub1", d1)); Assert.ok(s.addSubmissionAttempt("id1", "sub1", d1));
Assert.ok(s.addSubmissionResult("id1", "sub1", d2, SUBMISSION_RESULT_OK)); Assert.ok(s.addSubmissionResult("id1", "sub1", d2, SUBMISSION_RESULT_OK));
Assert.ok(s.setRemoteCrashID("id1", "bp-1"));
yield s.save(); yield s.save();
@ -100,6 +101,7 @@ add_task(function test_save_load() {
Assert.equal(crashes.length, 2); Assert.equal(crashes.length, 2);
let c = s.getCrash("id1"); let c = s.getCrash("id1");
Assert.equal(c.crashDate.getTime(), d1.getTime()); Assert.equal(c.crashDate.getTime(), d1.getTime());
Assert.equal(c.remoteID, "bp-1");
Assert.ok(!!c.submissions); Assert.ok(!!c.submissions);
let submission = c.submissions.get("sub1"); let submission = c.submissions.get("sub1");
@ -554,3 +556,14 @@ add_task(function* test_convertSubmissionsStoredAsCrashes() {
Assert.equal(submission.requestDate.getTime(), DUMMY_DATE_2.getTime()); Assert.equal(submission.requestDate.getTime(), DUMMY_DATE_2.getTime());
Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime()); Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime());
}); });
add_task(function* test_setRemoteCrashID() {
let s = yield getStore();
Assert.ok(s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "crash1",
new Date()));
Assert.equal(s.crashes[0].remoteID, null);
Assert.ok(s.setRemoteCrashID("crash1", "bp-1"));
Assert.equal(s.crashes[0].remoteID, "bp-1");
});

View File

@ -15,6 +15,8 @@ let httpServer = new HttpServer();
let getEngine, postEngine, unresolvableEngine; let getEngine, postEngine, unresolvableEngine;
function run_test() { function run_test() {
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
removeMetadata(); removeMetadata();
updateAppInfo(); updateAppInfo();
@ -25,6 +27,7 @@ function run_test() {
// Remove added form history entries // Remove added form history entries
yield updateSearchHistory("remove", null); yield updateSearchHistory("remove", null);
FormHistory.shutdown(); FormHistory.shutdown();
Services.prefs.clearUserPref("browser.search.suggest.enabled");
})); }));
run_next_test(); run_next_test();
@ -288,7 +291,7 @@ add_task(function* local_result_returned_remote_result_disabled() {
do_check_eq(result.local.length, 1); do_check_eq(result.local.length, 1);
do_check_eq(result.local[0], "letter A"); do_check_eq(result.local[0], "letter A");
do_check_eq(result.remote.length, 0); do_check_eq(result.remote.length, 0);
Services.prefs.clearUserPref("browser.search.suggest.enabled"); Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
}); });
add_task(function* local_result_returned_remote_result_disabled_after_creation_of_controller() { add_task(function* local_result_returned_remote_result_disabled_after_creation_of_controller() {
@ -301,6 +304,7 @@ add_task(function* local_result_returned_remote_result_disabled_after_creation_o
do_check_eq(result.local.length, 1); do_check_eq(result.local.length, 1);
do_check_eq(result.local[0], "letter A"); do_check_eq(result.local[0], "letter A");
do_check_eq(result.remote.length, 0); do_check_eq(result.remote.length, 0);
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
}); });
add_task(function* one_of_each_disabled_before_creation_enabled_after_creation_of_controller() { add_task(function* one_of_each_disabled_before_creation_enabled_after_creation_of_controller() {
@ -317,8 +321,8 @@ add_task(function* one_of_each_disabled_before_creation_enabled_after_creation_o
do_check_eq(result.remote[0], "letter B"); do_check_eq(result.remote[0], "letter B");
}); });
add_task(function* clear_suggestions_pref() { add_task(function* reset_suggestions_pref() {
Services.prefs.clearUserPref("browser.search.suggest.enabled"); Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
}); });
add_task(function* one_local_zero_remote() { add_task(function* one_local_zero_remote() {

View File

@ -18,12 +18,12 @@ const gViewSourceCSS = 'resource://gre-resources/viewsource.css';
const NS_XHTML = 'http://www.w3.org/1999/xhtml'; const NS_XHTML = 'http://www.w3.org/1999/xhtml';
// These are markers used to delimit the selection during processing. They // These are markers used to delimit the selection during processing. They
// are removed from the final rendering, but we pick space-like characters for // are removed from the final rendering.
// safety (and futhermore, these are known to be mapped to a 0-length string // We use noncharacter Unicode codepoints to minimize the risk of clashing
// in transliterate.properties). It is okay to set start=end, we use findNext() // with anything that might legitimately be present in the document.
// U+200B ZERO WIDTH SPACE // U+FDD0..FDEF <noncharacters>
const MARK_SELECTION_START = '\u200B\u200B\u200B\u200B\u200B'; const MARK_SELECTION_START = '\uFDD0';
const MARK_SELECTION_END = '\u200B\u200B\u200B\u200B\u200B'; const MARK_SELECTION_END = '\uFDEF';
function onLoadViewPartialSource() function onLoadViewPartialSource()
{ {

View File

@ -282,7 +282,7 @@ Submitter.prototype = {
let submissionID = Cc["@mozilla.org/uuid-generator;1"] let submissionID = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator) .getService(Ci.nsIUUIDGenerator)
.generateUUID().toString(); .generateUUID().toString().slice(1, -1);
let manager = Services.crashmanager; let manager = Services.crashmanager;
let self = this; let self = this;
@ -297,6 +297,9 @@ Submitter.prototype = {
manager.SUBMISSION_RESULT_FAILED; manager.SUBMISSION_RESULT_FAILED;
manager.addSubmissionResult(self.id, submissionID, new Date(), manager.addSubmissionResult(self.id, submissionID, new Date(),
result); result);
if (submitted) {
manager.setRemoteCrashID(self.id, ret.CrashID);
}
} }
if (submitted) { if (submitted) {

View File

@ -15,12 +15,14 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
this.EXPORTED_SYMBOLS = ["LayoutHelpers"]; this.EXPORTED_SYMBOLS = ["LayoutHelpers"];
this.LayoutHelpers = LayoutHelpers = function(aTopLevelWindow) { let LayoutHelpers = function(aTopLevelWindow) {
this._topDocShell = aTopLevelWindow.QueryInterface(Ci.nsIInterfaceRequestor) this._topDocShell = aTopLevelWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation) .getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell); .QueryInterface(Ci.nsIDocShell);
}; };
this.LayoutHelpers = LayoutHelpers;
LayoutHelpers.prototype = { LayoutHelpers.prototype = {
/** /**

View File

@ -139,14 +139,14 @@ XPCOMUtils.defineLazyGetter(this, "Barriers", () => {
// We are waiting for the connections to close. The interesting // We are waiting for the connections to close. The interesting
// status is therefore the list of connections still pending. // status is therefore the list of connections still pending.
return { description: "Waiting for connections to close", return { description: "Waiting for connections to close",
status: Barriers.connections.status }; state: Barriers.connections.state };
} }
// We are still in the first stage: waiting for the barrier // We are still in the first stage: waiting for the barrier
// to be lifted. The interesting status is therefore that of // to be lifted. The interesting status is therefore that of
// the barrier. // the barrier.
return { description: "Waiting for the barrier to be lifted", return { description: "Waiting for the barrier to be lifted",
status: Barriers.shutdown.status }; state: Barriers.shutdown.state };
}); });
return Barriers; return Barriers;

View File

@ -125,6 +125,9 @@ endif # MOZ_PKG_PRETTYNAMES
SYMBOL_FULL_ARCHIVE_BASENAME = $(PKG_BASENAME).crashreporter-symbols-full SYMBOL_FULL_ARCHIVE_BASENAME = $(PKG_BASENAME).crashreporter-symbols-full
SYMBOL_ARCHIVE_BASENAME = $(PKG_BASENAME).crashreporter-symbols SYMBOL_ARCHIVE_BASENAME = $(PKG_BASENAME).crashreporter-symbols
# Code coverage package naming
CODE_COVERAGE_ARCHIVE_BASENAME = $(PKG_BASENAME).code-coverage-gcno
# Test package naming # Test package naming
TEST_PACKAGE = $(PKG_BASENAME).tests.zip TEST_PACKAGE = $(PKG_BASENAME).tests.zip

View File

@ -742,6 +742,13 @@ ifdef MOZ_PACKAGE_JSSHELL
$(MAKE_JSSHELL) $(MAKE_JSSHELL)
endif # MOZ_PACKAGE_JSSHELL endif # MOZ_PACKAGE_JSSHELL
endif # LIBXUL_SDK endif # LIBXUL_SDK
ifdef MOZ_CODE_COVERAGE
# Package code coverage gcno tree
@echo 'Packaging code coverage data...'
$(RM) $(CODE_COVERAGE_ARCHIVE_BASENAME).zip
$(PYTHON) -mmozbuild.codecoverage.packager \
--output-file='$(DIST)/$(PKG_PATH)$(CODE_COVERAGE_ARCHIVE_BASENAME).zip'
endif
prepare-package: stage-package prepare-package: stage-package
@ -892,6 +899,11 @@ UPLOAD_FILES += \
$(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip) $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip)
endif endif
ifdef MOZ_CODE_COVERAGE
UPLOAD_FILES += \
$(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(CODE_COVERAGE_ARCHIVE_BASENAME).zip)
endif
SIGN_CHECKSUM_CMD= SIGN_CHECKSUM_CMD=
ifdef MOZ_SIGN_CMD ifdef MOZ_SIGN_CMD
# If we're signing with gpg, we'll have a bunch of extra detached signatures to # If we're signing with gpg, we'll have a bunch of extra detached signatures to

View File

@ -697,6 +697,8 @@ PLDHashTable::Enumerate(PLDHashEnumerator aEtor, void* aArg)
{ {
INCREMENT_RECURSION_LEVEL(this); INCREMENT_RECURSION_LEVEL(this);
// Please keep this method in sync with the PLDHashTable::Iterator constructor
// and ::NextEntry methods below in this file.
char* entryAddr = mEntryStore; char* entryAddr = mEntryStore;
uint32_t capacity = Capacity(); uint32_t capacity = Capacity();
uint32_t tableSize = capacity * mEntrySize; uint32_t tableSize = capacity * mEntrySize;
@ -835,6 +837,97 @@ PL_DHashTableSizeOfIncludingThis(
aMallocSizeOf, aArg); aMallocSizeOf, aArg);
} }
PLDHashTable::Iterator::Iterator(const PLDHashTable* aTable)
: mTable(aTable),
mEntryAddr(mTable->mEntryStore),
mEntryOffset(0)
{
// Make sure that modifications can't simultaneously happen while the iterator
// is active.
INCREMENT_RECURSION_LEVEL(mTable);
// The following code is taken from, and should be kept in sync with, the
// PLDHashTable::Enumerate method above. The variables i and entryAddr (which
// vary over the course of the for loop) are converted into mEntryOffset and
// mEntryAddr, respectively.
uint32_t capacity = mTable->Capacity();
uint32_t tableSize = capacity * mTable->EntrySize();
char* entryLimit = mEntryAddr + tableSize;
if (ChaosMode::isActive()) {
// Start iterating at a random point in the hashtable. It would be
// even more chaotic to iterate in fully random order, but that's a lot
// more work.
mEntryAddr += ChaosMode::randomUint32LessThan(capacity) * mTable->mEntrySize;
if (mEntryAddr >= entryLimit) {
mEntryAddr -= tableSize;
}
}
}
PLDHashTable::Iterator::Iterator(const Iterator& aIterator)
: mTable(aIterator.mTable),
mEntryAddr(aIterator.mEntryAddr),
mEntryOffset(aIterator.mEntryOffset)
{
// We need the copy constructor only so that we can keep the recursion level
// consistent.
INCREMENT_RECURSION_LEVEL(mTable);
}
PLDHashTable::Iterator::~Iterator()
{
DECREMENT_RECURSION_LEVEL(mTable);
}
bool PLDHashTable::Iterator::HasMoreEntries() const
{
// Check the number of live entries seen, not the total number of entries
// seen. To see why, consider what happens if the last entry is not live: we
// would have to iterate after returning an entry to see if more live entries
// exist.
return mEntryOffset < mTable->EntryCount();
}
PLDHashEntryHdr* PLDHashTable::Iterator::NextEntry()
{
MOZ_ASSERT(HasMoreEntries());
// The following code is taken from, and should be kept in sync with, the
// PLDHashTable::Enumerate method above. The variables i and entryAddr (which
// vary over the course of the for loop) are converted into mEntryOffset and
// mEntryAddr, respectively.
uint32_t capacity = mTable->Capacity();
uint32_t tableSize = capacity * mTable->mEntrySize;
char* entryLimit = mEntryAddr + tableSize;
// Strictly speaking, we don't need to iterate over the full capacity each
// time. However, it is simpler to do so rather than unnecessarily track the
// current number of entries checked as opposed to only live entries. If debug
// checks pass, then this method will only iterate through the full capacity
// once. If they fail, then this loop may end up returning the early entries
// more than once.
for (uint32_t e = 0; e < capacity; ++e) {
PLDHashEntryHdr* entry = (PLDHashEntryHdr*)mEntryAddr;
// Increment the count before returning so we don't keep returning the same
// address. This may wrap around if ChaosMode is enabled.
mEntryAddr += mTable->mEntrySize;
if (mEntryAddr >= entryLimit) {
mEntryAddr -= tableSize;
}
if (ENTRY_IS_LIVE(entry)) {
++mEntryOffset;
return entry;
}
}
// If the debug checks pass, then the above loop should always find a live
// entry. If those checks are disabled, then it may be possible to reach this
// if the table is empty and this method is called.
MOZ_CRASH("Flagrant misuse of hashtable iterators not caught by checks.");
}
#ifdef DEBUG #ifdef DEBUG
MOZ_ALWAYS_INLINE void MOZ_ALWAYS_INLINE void
PLDHashTable::MarkImmutable() PLDHashTable::MarkImmutable()

View File

@ -194,7 +194,7 @@ private:
* non-DEBUG components. (Actually, even if it were removed, * non-DEBUG components. (Actually, even if it were removed,
* sizeof(PLDHashTable) wouldn't change, due to struct padding.) * sizeof(PLDHashTable) wouldn't change, due to struct padding.)
*/ */
uint16_t mRecursionLevel;/* used to detect unsafe re-entry */ mutable uint16_t mRecursionLevel;/* used to detect unsafe re-entry */
uint32_t mEntrySize; /* number of bytes in an entry */ uint32_t mEntrySize; /* number of bytes in an entry */
uint32_t mEntryCount; /* number of entries in table */ uint32_t mEntryCount; /* number of entries in table */
uint32_t mRemovedCount; /* removed entry sentinels in table */ uint32_t mRemovedCount; /* removed entry sentinels in table */
@ -272,6 +272,27 @@ public:
void DumpMeter(PLDHashEnumerator aDump, FILE* aFp); void DumpMeter(PLDHashEnumerator aDump, FILE* aFp);
#endif #endif
/**
* This is an iterator that works over the elements of PLDHashtable. It is not
* safe to modify the hashtable while it is being iterated over; on debug
* builds, attempting to do so will result in an assertion failure.
*/
class Iterator {
public:
Iterator(const PLDHashTable* aTable);
Iterator(const Iterator& aIterator);
~Iterator();
bool HasMoreEntries() const;
PLDHashEntryHdr* NextEntry();
private:
const PLDHashTable* mTable; /* Main table pointer */
char* mEntryAddr; /* Pointer to the next entry to check */
uint32_t mEntryOffset; /* The number of the elements returned */
};
Iterator Iterate() const { return Iterator(this); }
private: private:
PLDHashEntryHdr* PL_DHASH_FASTCALL PLDHashEntryHdr* PL_DHASH_FASTCALL
SearchTable(const void* aKey, PLDHashNumber aKeyHash, PLDHashOperator aOp); SearchTable(const void* aKey, PLDHashNumber aKeyHash, PLDHashOperator aOp);