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();
}
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);
return xpEvent.forget();
}

View File

@ -105,7 +105,8 @@ public:
eTextSelChangeEvent,
eSelectionChangeEvent,
eTableChangeEvent,
eVirtualCursorChangeEvent
eVirtualCursorChangeEvent,
eObjectAttrChangedEvent
};
static const EventGroup kEventGroup = eGenericEvent;
@ -494,6 +495,32 @@ private:
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.
*/

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
// change event; at least until native API comes up with a more meaningful event.
uint8_t attrFlags = aria::AttrCharacteristicsFor(aAttribute);
if (!(attrFlags & ATTR_BYPASSOBJ))
FireDelayedEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
aAccessible);
if (!(attrFlags & ATTR_BYPASSOBJ)) {
nsRefPtr<AccEvent> event =
new AccObjectAttrChangedEvent(aAccessible, aAttribute);
FireDelayedEvent(event);
}
nsIContent* elm = aAccessible->GetContent();

View File

@ -18,6 +18,7 @@ XPIDL_SOURCES += [
'nsIAccessibleHyperLink.idl',
'nsIAccessibleHyperText.idl',
'nsIAccessibleImage.idl',
'nsIAccessibleObjectAttributeChangedEvent.idl',
'nsIAccessiblePivot.idl',
'nsIAccessibleRelation.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) {
if (!Utils.isAliveAndVisible(
Utils.AccRetrieval.getAccessibleFor(aBrowser))) {
return;
}
for (let presenter of aPresentationData) {
if (!presenter) {
continue;

View File

@ -225,43 +225,30 @@ this.EventManager.prototype = {
this.editState = editState;
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:
{
let {liveRegion, isPolite} = this._handleLiveRegion(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));
this._handleShow(aEvent);
break;
}
case Events.HIDE:
{
let evt = aEvent.QueryInterface(Ci.nsIAccessibleHideEvent);
let {liveRegion, isPolite} = this._handleLiveRegion(
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 });
}
}
this._handleHide(evt);
break;
}
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) {
let event = aEvent.QueryInterface(Ci.nsIAccessibleTextChangeEvent);
let isInserted = event.isInserted;

View File

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

View File

@ -12,6 +12,8 @@ const nsIAccessibleTextChangeEvent =
Components.interfaces.nsIAccessibleTextChangeEvent;
const nsIAccessibleVirtualCursorChangeEvent =
Components.interfaces.nsIAccessibleVirtualCursorChangeEvent;
const nsIAccessibleObjectAttributeChangedEvent =
Components.interfaces.nsIAccessibleObjectAttributeChangedEvent;
const nsIAccessibleStates = Components.interfaces.nsIAccessibleStates;
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.
*/

View File

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

View File

@ -24,6 +24,22 @@
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>
<style>
#windows {
@ -58,6 +74,7 @@
<body>
<div>Phone status bar</div>
<div id="windows">
<button id="back">Back</button>
<div id="appframe"></div>
<div role="dialog" id="alert" hidden>
<h1>This is an alert!</h1>

View File

@ -24,6 +24,7 @@
function doTest() {
var doc = currentTabDocument();
var iframe = doc.createElement('iframe');
iframe.id = 'iframe';
iframe.mozbrowser = true;
iframe.addEventListener('mozbrowserloadend', function () {
var contentTest = new AccessFuContentTest(
@ -33,6 +34,9 @@
speak: ['Phone status bar', 'Traversal Rule test document'],
focused: 'body'
}],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMoveNext, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'],
focused: 'iframe'
@ -79,10 +83,16 @@
[ContentMessages.simpleMovePrevious, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]}]
}],
[ContentMessages.simpleMovePrevious, {
speak: ["Back", {"string": "pushbutton"}]
}],
[ContentMessages.simpleMovePrevious, {
speak: ['Phone status bar']
}],
[ContentMessages.simpleMoveNext, {
speak: ["Back", {"string": "pushbutton"}]
}],
// Moving to the absolute last item from an embedded document
// fails. Bug 972035.
[ContentMessages.simpleMoveNext, {
@ -101,6 +111,9 @@
[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']
}],
@ -134,6 +147,9 @@
[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']
}],
@ -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 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
[ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document']
@ -169,6 +233,9 @@
[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']
}],

View File

@ -33,6 +33,16 @@
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) {
var element = document.getElementById(id);
element[property] = text;
@ -60,7 +70,7 @@
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"},"I will be hidden"],
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": true
}
@ -92,6 +102,54 @@
[show(id) for (id of ["to_show_descendant1", "to_show_descendant2",
"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: {
"eventType": "liveregion-change",
@ -103,6 +161,17 @@
action: function action() {
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: {
"eventType": "liveregion-change",
@ -114,6 +183,18 @@
action: function action() {
[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: {
"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_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>
<p id="to_hide_descendant1">I should not be announced 1</p>
</div>
@ -297,11 +384,30 @@
<p id="to_hide_descendant4">I will be hidden</p>
</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_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_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>
<p id="to_show_descendant1" style="display: none">I should not be announced 1</p>
</div>
@ -315,13 +421,34 @@
<p id="to_show_descendant4" style="display: none">I will be shown</p>
</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">
<p id="to_hide_live_assertive">I will be hidden</p>
</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_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">
<p id="to_replace">I am replaced</p>
</div>

View File

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

View File

@ -103,8 +103,21 @@ function onSubmitStatus(subj, topic, data) {
if (data != "success" && data != "failed")
return;
let extra = getPropertyBagValue(subj.QueryInterface(Ci.nsIPropertyBag),
"extra");
let propBag = subj.QueryInterface(Ci.nsIPropertyBag);
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");
let val = getPropertyBagValue(extra, "PluginUserComment");

View File

@ -8756,6 +8756,7 @@ AC_SUBST(VPX_X86_ASM)
AC_SUBST(VPX_ARM_ASM)
AC_SUBST(VPX_NEED_OBJ_INT_EXTRACT)
AC_SUBST(MOZ_INSTRUMENT_EVENT_LOOP)
AC_SUBST(MOZ_CODE_COVERAGE)
AC_SUBST(LIBJPEG_TURBO_AS)
AC_SUBST(LIBJPEG_TURBO_ASFLAGS)
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.
UnsetFlags(NODE_FORCE_XBL_BINDINGS);
bool clearBindingParent = true;
#ifdef MOZ_XUL
nsXULElement* xulElem = nsXULElement::FromContent(this);
if (xulElem) {
xulElem->SetXULBindingParent(nullptr);
clearBindingParent = false;
}
else
#endif
{
nsDOMSlots *slots = GetExistingDOMSlots();
if (slots) {
nsDOMSlots* slots = GetExistingDOMSlots();
if (slots) {
if (clearBindingParent) {
slots->mBindingParent = nullptr;
slots->mContainingShadow = nullptr;
}
slots->mContainingShadow = nullptr;
}
// 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");
color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-inline-style-allowed')).color;
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 () {
@ -52,8 +55,6 @@ function checkBlocked () {
document.getElementById('cspframe').src = 'file_CSP_bug885433_allows.html';
document.getElementById('cspframe').addEventListener('load', checkAllowed, false);
document.getElementById('cspframe2').src = 'file_CSP_bug885433_blocks.html';
document.getElementById('cspframe2').addEventListener('load', checkBlocked, false);
</script>
</pre>
</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.
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
// been suspended by the audio channel service.
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),
mAudioCaptured(false),
mPlayingBeforeSeek(false),
mPlayingThroughTheAudioChannelBeforeSeek(false),
mPausedForInactiveDocumentOrChannel(false),
mEventDeliveryPaused(false),
mWaitingFired(false),
@ -3056,6 +3057,10 @@ void HTMLMediaElement::PlaybackEnded()
void HTMLMediaElement::SeekStarted()
{
DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
// Set the Variable if the Seekstarted while active playing
if(mPlayingThroughTheAudioChannel) {
mPlayingThroughTheAudioChannelBeforeSeek = true;
}
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
FireTimeUpdate(false);
}
@ -3073,6 +3078,8 @@ void HTMLMediaElement::SeekCompleted()
if (mCurrentPlayRangeStart == -1.0) {
mCurrentPlayRangeStart = CurrentTime();
}
// Unset the variable on seekend
mPlayingThroughTheAudioChannelBeforeSeek = false;
}
void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
@ -3913,7 +3920,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
(HasAttr(kNameSpaceID_None, nsGkAtoms::loop) ||
(mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
!IsPlaybackEnded()) ||
mPlayingBeforeSeek));
mPlayingThroughTheAudioChannelBeforeSeek));
if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;

View File

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

View File

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

View File

@ -77,4 +77,4 @@ load oscillator-ended-2.html
include ../../mediasource/test/crashtests/crashtests.list
# 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
AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
{
MOZ_ASSERT(aCx);
mCx = aCx;
if (aIsMainThread) {
// 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 (mEditor && mEditor->GetIsInEditAction()) {
bool isInEditAction = false;
if (mEditor && NS_SUCCEEDED(mEditor->GetIsInEditAction(&isInEditAction)) &&
isInEditAction) {
return;
}

View File

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

View File

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

View File

@ -75,6 +75,8 @@ public:
private:
~ServiceWorkerContainer();
void RemoveReadyPromise();
// This only changes when a worker hijacks everything in its scope by calling
// replace().
// 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)
{
MOZ_ASSERT(aDocumentURI);
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
if (!domainInfo) {
nsCString domain;
@ -1875,6 +1876,7 @@ ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOME
NS_IMETHODIMP
ServiceWorkerManager::RemoveRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
{
AssertIsOnMainThread();
MOZ_ASSERT(aDocumentURI);
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
if (!domainInfo) {

View File

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

View File

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

View File

@ -21,7 +21,7 @@ interface nsIEditActionListener;
interface nsIInlineSpellChecker;
interface nsITransferable;
[builtinclass, scriptable, uuid(c3b61bc9-ccdd-4bcd-acd8-1b8dcbe6a247)]
[scriptable, uuid(04714a01-e02f-4ef5-a388-612451d0db16)]
interface nsIEditor : nsISupports
{
@ -555,5 +555,5 @@ interface nsIEditor : nsISupports
* nsIEditorObserver::BeforeEditAction() and nsIEditorObserver::EditAction()
* 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);
[builtinclass, scriptable, uuid(9470bee7-cad3-4382-8fb4-6bdda9f0273a)]
[scriptable, uuid(393a364f-e8e2-48a1-a271-a0067b6bac9b)]
interface nsIHTMLEditor : nsISupports
{

View File

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

View File

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

View File

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

View File

@ -26,11 +26,18 @@
# though this may change if we find a need for additional properties.
#
# The Unicode data files listed above should be together in one directory.
#
# We also require the file
# http://www.unicode.org/Public/security/latest/xidmodifications.txt
# This file should be in a sub-directory "security" immediately below the
# 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
#
# perl genUnicodePropertyData.pl \
@ -301,6 +308,13 @@ my %bidicategoryCode = (
"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
my @script;
my @category;
@ -314,6 +328,7 @@ my @numericvalue;
my @hanVariant;
my @bidicategory;
my @fullWidth;
my @verticalOrientation;
for (my $i = 0; $i < 0x110000; ++$i) {
$script[$i] = $scriptCode{"UNKNOWN"};
$category[$i] = $catCode{"UNASSIGNED"};
@ -324,6 +339,7 @@ for (my $i = 0; $i < 0x110000; ++$i) {
$hanVariant[$i] = 0;
$bidicategory[$i] = $bidicategoryCode{"L"};
$fullWidth[$i] = 0;
$verticalOrientation[$i] = 1; # default for unlisted codepoints is 'R'
}
# blocks where the default for bidi category is not L
@ -628,6 +644,31 @@ while (<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();
open DATA_TABLES, "> nsUnicodePropertyData.cpp" or die "unable to open nsUnicodePropertyData.cpp for output";
@ -706,18 +747,35 @@ sub sprintCharProps1
my $usv = shift;
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};",
"nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1);
my $type = q/
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
{
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],
$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};",
"nsCharProps2", 11, 5, \&sprintCharProps2, 16, 4, 1);
$type = q/
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";

View File

@ -49,6 +49,18 @@ inline nsCharType GetBidiCat(uint32_t aCh) {
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 {
XIDMOD_INCLUSION,
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]
@ -52,6 +52,9 @@ Standard.
# Unihan_Variants.txt
# 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! * * * * *
*/
@ -61,22 +64,26 @@ Standard.
#pragma pack(1)
struct nsCharProps1 {
unsigned char mMirrorOffsetIndex:5;
unsigned char mHangulType:3;
unsigned char mCombiningClass:8;
};
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 mHanVariant:2;
signed char mNumericValue:5;
unsigned char mVertOrient:2;
};
#pragma pack()
enum {

View File

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

View File

@ -1,3 +1,6 @@
if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
quit();
Random = {
weighted: function(wa) {
var a = [];
@ -128,4 +131,4 @@ testMathyFunction(mathy2, [-0])
mathy5 = (function(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(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" });
assertEq(gScripts.indexOf(ggw.script) != -1, true);
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_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_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'innermost' property without both 'url' and 'line' properties")
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'url' property")
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 'displayURL', 'url', or 'source' property")
// Intl
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);
}
static inline ScriptSourceObject *GetSourceReferent(JSObject *obj);
/*
* A class for parsing 'findScripts' query arguments and searching for
* scripts that match the criteria they represent.
*/
class Debugger::ScriptQuery {
class MOZ_STACK_CLASS Debugger::ScriptQuery
{
public:
/* Construct a ScriptQuery to use matching scripts for |dbg|. */
ScriptQuery(JSContext *cx, Debugger *dbg):
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;
}
/* 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. */
RootedValue lineProperty(cx);
if (!JSObject::getProperty(cx, query, query, cx->names().line, &lineProperty))
@ -2586,7 +2622,7 @@ class Debugger::ScriptQuery {
if (lineProperty.isUndefined()) {
hasLine = false;
} else if (lineProperty.isNumber()) {
if (url.isUndefined()) {
if (displayURL.isUndefined() && url.isUndefined() && !source) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_QUERY_LINE_WITHOUT_URL);
return false;
@ -2613,30 +2649,13 @@ class Debugger::ScriptQuery {
innermost = ToBoolean(innermostProperty);
if (innermost) {
/* 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,
JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL);
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;
}
@ -2719,6 +2738,12 @@ class Debugger::ScriptQuery {
* it. */
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. */
bool hasLine;
@ -2841,6 +2866,8 @@ class Debugger::ScriptQuery {
if (CompareChars(s, js_strlen(s), displayURLString) != 0)
return;
}
if (source && source != script->sourceObject())
return;
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
load 1037903.html
load 1039454-1.html
load 1058954-1.html
load 1042489.html

View File

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

View File

@ -8146,7 +8146,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
const WritingMode outerWM = aState.OuterReflowState() ?
aState.OuterReflowState()->GetWritingMode() : ourWM;
nsHTMLReflowMetrics desiredSize(outerWM);
LogicalSize ourSize = GetLogicalSize().ConvertTo(outerWM, ourWM);
LogicalSize ourSize = GetLogicalSize(outerWM);
if (rendContext) {
@ -8186,7 +8186,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
}
// 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.BSize(outerWM) = size.BSize(outerWM);
desiredSize.UnionOverflowAreasWithDesiredBounds();
@ -8195,7 +8195,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
// Set up a |reflowState| to pass into ReflowAbsoluteFrames
nsHTMLReflowState reflowState(aState.PresContext(), this,
aState.GetRenderingContext(),
LogicalSize(ourWM, size.ISize(ourWM),
LogicalSize(ourWM, ISize(),
NS_UNCONSTRAINEDSIZE),
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
== 1053035-1-flex.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;
}
int64_t compensated_position = samplerate * (msec - mixer_latency) / 1000;
pthread_mutex_lock(&stm->mutex);
int64_t maximum_position = stm->written * (int64_t)stm->inputrate / stm->outputrate;
pthread_mutex_unlock(&stm->mutex);
assert(maximum_position >= 0);
if (compensated_position < 0) {
*position = 0;
} else if(compensated_position > maximum_position) {
*position = maximum_position;
if (msec > mixer_latency) {
int64_t unadjusted_position = samplerate * (msec - mixer_latency) / 1000;
*position = unadjusted_position < maximum_position ?
unadjusted_position : maximum_position;
} else {
*position = compensated_position;
*position = 0;
}
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");
if (that._tabsFinished == that._tabsAdded) {
Logger.logInfo("all tabs loaded, continuing...");
// 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");
that.FinishAsyncOperation();
}
});
break;
@ -895,7 +890,13 @@ let TPS = {
this._triggeredSync = true;
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() {

View File

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

View File

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

View File

@ -282,7 +282,6 @@ class BaseMarionetteOptions(OptionParser):
self.add_option('--type',
dest='type',
action='store',
default='browser+b2g',
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' "
"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)
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')

View File

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

View File

@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
import argparse
import json
import optparse
import os
import unittest
import StringIO
import json
import sys
import unittest
import mozfile
from mozlog.structured import (
@ -501,6 +503,15 @@ class TestCommandline(unittest.TestCase):
self.assertEqual(len(logger.handlers), 1)
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):
parser = argparse.ArgumentParser()
commandline.add_logging_group(parser)

View File

@ -125,10 +125,11 @@ class DeviceRunner(BaseRunner):
def on_finish(self):
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()
crashed = BaseRunner.check_for_crashes(self, dump_directory=dump_dir,
test_name=self.last_test)
crashed = BaseRunner.check_for_crashes(
self, dump_directory=dump_dir, test_name=test_name)
mozfile.remove(dump_dir)
return crashed

View File

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

View File

@ -367,6 +367,21 @@ this.CrashManager.prototype = Object.freeze({
}.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.
*
@ -1005,6 +1020,7 @@ CrashStore.prototype = Object.freeze({
if (!this._data.crashes.has(id)) {
this._data.crashes.set(id, {
id: id,
remoteID: null,
type: type,
crashDate: date,
submissions: new Map(),
@ -1032,6 +1048,19 @@ CrashStore.prototype = Object.freeze({
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) {
let crashes = [];
for (let crash of this.crashes) {
@ -1126,6 +1155,10 @@ CrashRecord.prototype = Object.freeze({
return this._o.id;
},
get remoteID() {
return this._o.remoteID;
},
get 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.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.addSubmissionAttempt("id1", "sub1", d1));
Assert.ok(s.addSubmissionResult("id1", "sub1", d2, SUBMISSION_RESULT_OK));
Assert.ok(s.setRemoteCrashID("id1", "bp-1"));
yield s.save();
@ -100,6 +101,7 @@ add_task(function test_save_load() {
Assert.equal(crashes.length, 2);
let c = s.getCrash("id1");
Assert.equal(c.crashDate.getTime(), d1.getTime());
Assert.equal(c.remoteID, "bp-1");
Assert.ok(!!c.submissions);
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.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;
function run_test() {
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
removeMetadata();
updateAppInfo();
@ -25,6 +27,7 @@ function run_test() {
// Remove added form history entries
yield updateSearchHistory("remove", null);
FormHistory.shutdown();
Services.prefs.clearUserPref("browser.search.suggest.enabled");
}));
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[0], "letter A");
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() {
@ -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[0], "letter A");
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() {
@ -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");
});
add_task(function* clear_suggestions_pref() {
Services.prefs.clearUserPref("browser.search.suggest.enabled");
add_task(function* reset_suggestions_pref() {
Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
});
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';
// These are markers used to delimit the selection during processing. They
// are removed from the final rendering, but we pick space-like characters for
// safety (and futhermore, these are known to be mapped to a 0-length string
// in transliterate.properties). It is okay to set start=end, we use findNext()
// U+200B ZERO WIDTH SPACE
const MARK_SELECTION_START = '\u200B\u200B\u200B\u200B\u200B';
const MARK_SELECTION_END = '\u200B\u200B\u200B\u200B\u200B';
// are removed from the final rendering.
// We use noncharacter Unicode codepoints to minimize the risk of clashing
// with anything that might legitimately be present in the document.
// U+FDD0..FDEF <noncharacters>
const MARK_SELECTION_START = '\uFDD0';
const MARK_SELECTION_END = '\uFDEF';
function onLoadViewPartialSource()
{

View File

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

View File

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

View File

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

View File

@ -125,6 +125,9 @@ endif # MOZ_PKG_PRETTYNAMES
SYMBOL_FULL_ARCHIVE_BASENAME = $(PKG_BASENAME).crashreporter-symbols-full
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 = $(PKG_BASENAME).tests.zip

View File

@ -742,6 +742,13 @@ ifdef MOZ_PACKAGE_JSSHELL
$(MAKE_JSSHELL)
endif # MOZ_PACKAGE_JSSHELL
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
@ -892,6 +899,11 @@ UPLOAD_FILES += \
$(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip)
endif
ifdef MOZ_CODE_COVERAGE
UPLOAD_FILES += \
$(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(CODE_COVERAGE_ARCHIVE_BASENAME).zip)
endif
SIGN_CHECKSUM_CMD=
ifdef MOZ_SIGN_CMD
# 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);
// Please keep this method in sync with the PLDHashTable::Iterator constructor
// and ::NextEntry methods below in this file.
char* entryAddr = mEntryStore;
uint32_t capacity = Capacity();
uint32_t tableSize = capacity * mEntrySize;
@ -835,6 +837,97 @@ PL_DHashTableSizeOfIncludingThis(
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
MOZ_ALWAYS_INLINE void
PLDHashTable::MarkImmutable()

View File

@ -194,7 +194,7 @@ private:
* non-DEBUG components. (Actually, even if it were removed,
* 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 mEntryCount; /* number of entries in table */
uint32_t mRemovedCount; /* removed entry sentinels in table */
@ -272,6 +272,27 @@ public:
void DumpMeter(PLDHashEnumerator aDump, FILE* aFp);
#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:
PLDHashEntryHdr* PL_DHASH_FASTCALL
SearchTable(const void* aKey, PLDHashNumber aKeyHash, PLDHashOperator aOp);