mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound.
This commit is contained in:
commit
6bfa72099d
@ -163,6 +163,9 @@ this.AccessFu = {
|
|||||||
Services.obs.removeObserver(this, 'Accessibility:LongPress');
|
Services.obs.removeObserver(this, 'Accessibility:LongPress');
|
||||||
Services.obs.removeObserver(this, 'Accessibility:MoveByGranularity');
|
Services.obs.removeObserver(this, 'Accessibility:MoveByGranularity');
|
||||||
|
|
||||||
|
delete this._quicknavModesPref;
|
||||||
|
delete this._notifyOutputPref;
|
||||||
|
|
||||||
if (this.doneCallback) {
|
if (this.doneCallback) {
|
||||||
this.doneCallback();
|
this.doneCallback();
|
||||||
delete this.doneCallback;
|
delete this.doneCallback;
|
||||||
@ -171,6 +174,9 @@ this.AccessFu = {
|
|||||||
|
|
||||||
_enableOrDisable: function _enableOrDisable() {
|
_enableOrDisable: function _enableOrDisable() {
|
||||||
try {
|
try {
|
||||||
|
if (!this._activatePref) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let activatePref = this._activatePref.value;
|
let activatePref = this._activatePref.value;
|
||||||
if (activatePref == ACCESSFU_ENABLE ||
|
if (activatePref == ACCESSFU_ENABLE ||
|
||||||
this._systemPref && activatePref == ACCESSFU_AUTO)
|
this._systemPref && activatePref == ACCESSFU_AUTO)
|
||||||
|
@ -14,10 +14,15 @@ const EVENT_TEXT_CARET_MOVED = Ci.nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
|
|||||||
const EVENT_TEXT_INSERTED = Ci.nsIAccessibleEvent.EVENT_TEXT_INSERTED;
|
const EVENT_TEXT_INSERTED = Ci.nsIAccessibleEvent.EVENT_TEXT_INSERTED;
|
||||||
const EVENT_TEXT_REMOVED = Ci.nsIAccessibleEvent.EVENT_TEXT_REMOVED;
|
const EVENT_TEXT_REMOVED = Ci.nsIAccessibleEvent.EVENT_TEXT_REMOVED;
|
||||||
const EVENT_FOCUS = Ci.nsIAccessibleEvent.EVENT_FOCUS;
|
const EVENT_FOCUS = Ci.nsIAccessibleEvent.EVENT_FOCUS;
|
||||||
|
const EVENT_SHOW = Ci.nsIAccessibleEvent.EVENT_SHOW;
|
||||||
|
const EVENT_HIDE = Ci.nsIAccessibleEvent.EVENT_HIDE;
|
||||||
|
|
||||||
const ROLE_INTERNAL_FRAME = Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME;
|
const ROLE_INTERNAL_FRAME = Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME;
|
||||||
const ROLE_DOCUMENT = Ci.nsIAccessibleRole.ROLE_DOCUMENT;
|
const ROLE_DOCUMENT = Ci.nsIAccessibleRole.ROLE_DOCUMENT;
|
||||||
const ROLE_CHROME_WINDOW = Ci.nsIAccessibleRole.ROLE_CHROME_WINDOW;
|
const ROLE_CHROME_WINDOW = Ci.nsIAccessibleRole.ROLE_CHROME_WINDOW;
|
||||||
|
const ROLE_TEXT_LEAF = Ci.nsIAccessibleRole.ROLE_TEXT_LEAF;
|
||||||
|
|
||||||
|
const TEXT_NODE = 3;
|
||||||
|
|
||||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, 'Services',
|
XPCOMUtils.defineLazyModuleGetter(this, 'Services',
|
||||||
@ -140,7 +145,11 @@ this.EventManager.prototype = {
|
|||||||
// Don't bother with non-content events in firefox.
|
// Don't bother with non-content events in firefox.
|
||||||
if (Utils.MozBuildApp == 'browser' &&
|
if (Utils.MozBuildApp == 'browser' &&
|
||||||
aEvent.eventType != EVENT_VIRTUALCURSOR_CHANGED &&
|
aEvent.eventType != EVENT_VIRTUALCURSOR_CHANGED &&
|
||||||
aEvent.accessibleDocument.docType == 'window') {
|
// XXX Bug 442005 results in DocAccessible::getDocType returning
|
||||||
|
// NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
|
||||||
|
// 'window' does not currently work.
|
||||||
|
(aEvent.accessibleDocument.DOMDocument.doctype &&
|
||||||
|
aEvent.accessibleDocument.DOMDocument.doctype.name === 'window')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,28 +228,47 @@ this.EventManager.prototype = {
|
|||||||
this.editState = editState;
|
this.editState = editState;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EVENT_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 === ROLE_TEXT_LEAF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this._dequeueLiveEvent(EVENT_HIDE, liveRegion);
|
||||||
|
this.present(Presentation.liveRegion(liveRegion, isPolite, false));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVENT_HIDE:
|
||||||
|
{
|
||||||
|
let {liveRegion, isPolite} = this._handleLiveRegion(
|
||||||
|
aEvent.QueryInterface(Ci.nsIAccessibleHideEvent),
|
||||||
|
['removals', 'all']);
|
||||||
|
// Only handle hide if it is a relevant live region.
|
||||||
|
if (!liveRegion) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Hide for text is handled by the EVENT_TEXT_REMOVED handler.
|
||||||
|
if (aEvent.accessible.role === ROLE_TEXT_LEAF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this._queueLiveEvent(EVENT_HIDE, liveRegion, isPolite);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case EVENT_TEXT_INSERTED:
|
case EVENT_TEXT_INSERTED:
|
||||||
case EVENT_TEXT_REMOVED:
|
case EVENT_TEXT_REMOVED:
|
||||||
{
|
{
|
||||||
if (aEvent.isFromUserInput) {
|
let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
|
||||||
// XXX support live regions as well.
|
['text', 'all']);
|
||||||
let event = aEvent.QueryInterface(Ci.nsIAccessibleTextChangeEvent);
|
if (aEvent.isFromUserInput || liveRegion) {
|
||||||
let isInserted = event.isInserted;
|
// Handle all text mutations coming from the user or if they happen
|
||||||
let txtIface = aEvent.accessible.QueryInterface(Ci.nsIAccessibleText);
|
// on a live region.
|
||||||
|
this._handleText(aEvent, liveRegion, isPolite);
|
||||||
let text = '';
|
|
||||||
try {
|
|
||||||
text = txtIface.
|
|
||||||
getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
|
|
||||||
} catch (x) {
|
|
||||||
// XXX we might have gotten an exception with of a
|
|
||||||
// zero-length text. If we did, ignore it (bug #749810).
|
|
||||||
if (txtIface.characterCount)
|
|
||||||
throw x;
|
|
||||||
}
|
|
||||||
this.present(Presentation.textChanged(
|
|
||||||
isInserted, event.start, event.length,
|
|
||||||
text, event.modifiedText));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -258,6 +286,130 @@ this.EventManager.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_handleText: function _handleText(aEvent, aLiveRegion, aIsPolite) {
|
||||||
|
let event = aEvent.QueryInterface(Ci.nsIAccessibleTextChangeEvent);
|
||||||
|
let isInserted = event.isInserted;
|
||||||
|
let txtIface = aEvent.accessible.QueryInterface(Ci.nsIAccessibleText);
|
||||||
|
|
||||||
|
let text = '';
|
||||||
|
try {
|
||||||
|
text = txtIface.getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
|
||||||
|
} catch (x) {
|
||||||
|
// XXX we might have gotten an exception with of a
|
||||||
|
// zero-length text. If we did, ignore it (bug #749810).
|
||||||
|
if (txtIface.characterCount) {
|
||||||
|
throw x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If there are embedded objects in the text, ignore them.
|
||||||
|
// Assuming changes to the descendants would already be handled by the
|
||||||
|
// show/hide event.
|
||||||
|
let modifiedText = event.modifiedText.replace(/\uFFFC/g, '').trim();
|
||||||
|
if (!modifiedText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aLiveRegion) {
|
||||||
|
if (aEvent.eventType === EVENT_TEXT_REMOVED) {
|
||||||
|
this._queueLiveEvent(EVENT_TEXT_REMOVED, aLiveRegion, aIsPolite,
|
||||||
|
modifiedText);
|
||||||
|
} else {
|
||||||
|
this._dequeueLiveEvent(EVENT_TEXT_REMOVED, aLiveRegion);
|
||||||
|
this.present(Presentation.liveRegion(aLiveRegion, aIsPolite, false,
|
||||||
|
modifiedText));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.present(Presentation.textChanged(isInserted, event.start,
|
||||||
|
event.length, text, modifiedText));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleLiveRegion: function _handleLiveRegion(aEvent, aRelevant) {
|
||||||
|
if (aEvent.isFromUserInput) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
let parseLiveAttrs = function parseLiveAttrs(aAccessible) {
|
||||||
|
let attrs = Utils.getAttributes(aAccessible);
|
||||||
|
if (attrs['container-live']) {
|
||||||
|
return {
|
||||||
|
live: attrs['container-live'],
|
||||||
|
relevant: attrs['container-relevant'] || 'additions text',
|
||||||
|
busy: attrs['container-busy'],
|
||||||
|
atomic: attrs['container-atomic'],
|
||||||
|
memberOf: attrs['member-of']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
// XXX live attributes are not set for hidden accessibles yet. Need to
|
||||||
|
// climb up the tree to check for them.
|
||||||
|
let getLiveAttributes = function getLiveAttributes(aEvent) {
|
||||||
|
let liveAttrs = parseLiveAttrs(aEvent.accessible);
|
||||||
|
if (liveAttrs) {
|
||||||
|
return liveAttrs;
|
||||||
|
}
|
||||||
|
let parent = aEvent.targetParent;
|
||||||
|
while (parent) {
|
||||||
|
liveAttrs = parseLiveAttrs(parent);
|
||||||
|
if (liveAttrs) {
|
||||||
|
return liveAttrs;
|
||||||
|
}
|
||||||
|
parent = parent.parent
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
let {live, relevant, busy, atomic, memberOf} = getLiveAttributes(aEvent);
|
||||||
|
// If container-live is not present or is set to |off| ignore the event.
|
||||||
|
if (!live || live === 'off') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// XXX: support busy and atomic.
|
||||||
|
|
||||||
|
// Determine if the type of the mutation is relevant. Default is additions
|
||||||
|
// and text.
|
||||||
|
let isRelevant = Utils.matchAttributeValue(relevant, aRelevant);
|
||||||
|
if (!isRelevant) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
liveRegion: aEvent.accessible,
|
||||||
|
isPolite: live === 'polite'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
_dequeueLiveEvent: function _dequeueLiveEvent(aEventType, aLiveRegion) {
|
||||||
|
let domNode = aLiveRegion.DOMNode;
|
||||||
|
if (this._liveEventQueue && this._liveEventQueue.has(domNode)) {
|
||||||
|
let queue = this._liveEventQueue.get(domNode);
|
||||||
|
let nextEvent = queue[0];
|
||||||
|
if (nextEvent.eventType === aEventType) {
|
||||||
|
Utils.win.clearTimeout(nextEvent.timeoutID);
|
||||||
|
queue.shift();
|
||||||
|
if (queue.length === 0) {
|
||||||
|
this._liveEventQueue.delete(domNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_queueLiveEvent: function _queueLiveEvent(aEventType, aLiveRegion, aIsPolite, aModifiedText) {
|
||||||
|
if (!this._liveEventQueue) {
|
||||||
|
this._liveEventQueue = new WeakMap();
|
||||||
|
}
|
||||||
|
let eventHandler = {
|
||||||
|
eventType: aEventType,
|
||||||
|
timeoutID: Utils.win.setTimeout(this.present.bind(this),
|
||||||
|
20, // Wait for a possible EVENT_SHOW or EVENT_TEXT_INSERTED event.
|
||||||
|
Presentation.liveRegion(aLiveRegion, aIsPolite, true, aModifiedText))
|
||||||
|
};
|
||||||
|
|
||||||
|
let domNode = aLiveRegion.DOMNode;
|
||||||
|
if (this._liveEventQueue.has(domNode)) {
|
||||||
|
this._liveEventQueue.get(domNode).push(eventHandler);
|
||||||
|
} else {
|
||||||
|
this._liveEventQueue.set(domNode, [eventHandler]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
present: function present(aPresentationData) {
|
present: function present(aPresentationData) {
|
||||||
this.sendMsgFunc("AccessFu:Present", aPresentationData);
|
this.sendMsgFunc("AccessFu:Present", aPresentationData);
|
||||||
},
|
},
|
||||||
|
@ -116,7 +116,6 @@ this.OutputGenerator = {
|
|||||||
let extState = {};
|
let extState = {};
|
||||||
aAccessible.getState(state, extState);
|
aAccessible.getState(state, extState);
|
||||||
let states = {base: state.value, ext: extState.value};
|
let states = {base: state.value, ext: extState.value};
|
||||||
|
|
||||||
return func.apply(this, [aAccessible, roleString, states, flags, aContext]);
|
return func.apply(this, [aAccessible, roleString, states, flags, aContext]);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -418,6 +417,15 @@ this.UtteranceGenerator = {
|
|||||||
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
|
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
genForLiveRegion: function genForLiveRegion(aContext, aIsHide, aModifiedText) {
|
||||||
|
let utterance = [];
|
||||||
|
if (aIsHide) {
|
||||||
|
utterance.push(gStringBundle.GetStringFromName('hidden'));
|
||||||
|
}
|
||||||
|
return utterance.concat(
|
||||||
|
aModifiedText || this.genForContext(aContext).output);
|
||||||
|
},
|
||||||
|
|
||||||
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
|
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
|
||||||
try {
|
try {
|
||||||
return [gStringBundle.GetStringFromName(aAnnouncement)];
|
return [gStringBundle.GetStringFromName(aAnnouncement)];
|
||||||
|
@ -102,7 +102,19 @@ Presenter.prototype = {
|
|||||||
/**
|
/**
|
||||||
* Announce something. Typically an app state change.
|
* Announce something. Typically an app state change.
|
||||||
*/
|
*/
|
||||||
announce: function announce(aAnnouncement) {}
|
announce: function announce(aAnnouncement) {},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Announce a live region.
|
||||||
|
* @param {PivotContext} aContext context object for an accessible.
|
||||||
|
* @param {boolean} aIsPolite A politeness level for a live region.
|
||||||
|
* @param {boolean} aIsHide An indicator of hide/remove event.
|
||||||
|
* @param {string} aModifiedText Optional modified text.
|
||||||
|
*/
|
||||||
|
liveRegion: function liveRegionShown(aContext, aIsPolite, aIsHide,
|
||||||
|
aModifiedText) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -409,6 +421,13 @@ AndroidPresenter.prototype = {
|
|||||||
fromIndex: 0
|
fromIndex: 0
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
liveRegion: function AndroidPresenter_liveRegion(aContext, aIsPolite,
|
||||||
|
aIsHide, aModifiedText) {
|
||||||
|
return this.announce(
|
||||||
|
UtteranceGenerator.genForLiveRegion(aContext, aIsHide,
|
||||||
|
aModifiedText).join(' '));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -451,6 +470,21 @@ SpeechPresenter.prototype = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
liveRegion: function SpeechPresenter_liveRegion(aContext, aIsPolite, aIsHide,
|
||||||
|
aModifiedText) {
|
||||||
|
return {
|
||||||
|
type: this.type,
|
||||||
|
details: {
|
||||||
|
actions: [{
|
||||||
|
method: 'speak',
|
||||||
|
data: UtteranceGenerator.genForLiveRegion(aContext, aIsHide,
|
||||||
|
aModifiedText).join(' '),
|
||||||
|
options: {enqueue: aIsPolite}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -570,5 +604,16 @@ this.Presentation = {
|
|||||||
// but there really isn't a point here.
|
// but there really isn't a point here.
|
||||||
return [p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)[0])
|
return [p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)[0])
|
||||||
for each (p in this.presenters)];
|
for each (p in this.presenters)];
|
||||||
|
},
|
||||||
|
|
||||||
|
liveRegion: function Presentation_liveRegion(aAccessible, aIsPolite, aIsHide,
|
||||||
|
aModifiedText) {
|
||||||
|
let context;
|
||||||
|
if (!aModifiedText) {
|
||||||
|
context = new PivotContext(aAccessible, null, -1, -1, true,
|
||||||
|
aIsHide ? true : false);
|
||||||
|
}
|
||||||
|
return [p.liveRegion(context, aIsPolite, aIsHide, aModifiedText) for (
|
||||||
|
p of this.presenters)];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -266,6 +266,15 @@ this.Utils = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
matchAttributeValue: function matchAttributeValue(aAttributeValue, values) {
|
||||||
|
let attrSet = new Set(aAttributeValue.split(' '));
|
||||||
|
for (let value of values) {
|
||||||
|
if (attrSet.has(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getLandmarkName: function getLandmarkName(aAccessible) {
|
getLandmarkName: function getLandmarkName(aAccessible) {
|
||||||
const landmarks = [
|
const landmarks = [
|
||||||
'banner',
|
'banner',
|
||||||
@ -281,11 +290,7 @@ this.Utils = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Looking up a role that would match a landmark.
|
// Looking up a role that would match a landmark.
|
||||||
for (let landmark of landmarks) {
|
return this.matchAttributeValue(roles, landmarks);
|
||||||
if (roles.indexOf(landmark) > -1) {
|
|
||||||
return landmark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -422,12 +427,15 @@ this.Logger = {
|
|||||||
* for a given accessible and its relationship with another accessible.
|
* for a given accessible and its relationship with another accessible.
|
||||||
*/
|
*/
|
||||||
this.PivotContext = function PivotContext(aAccessible, aOldAccessible,
|
this.PivotContext = function PivotContext(aAccessible, aOldAccessible,
|
||||||
aStartOffset, aEndOffset) {
|
aStartOffset, aEndOffset, aIgnoreAncestry = false,
|
||||||
|
aIncludeInvisible = false) {
|
||||||
this._accessible = aAccessible;
|
this._accessible = aAccessible;
|
||||||
this._oldAccessible =
|
this._oldAccessible =
|
||||||
this._isDefunct(aOldAccessible) ? null : aOldAccessible;
|
this._isDefunct(aOldAccessible) ? null : aOldAccessible;
|
||||||
this.startOffset = aStartOffset;
|
this.startOffset = aStartOffset;
|
||||||
this.endOffset = aEndOffset;
|
this.endOffset = aEndOffset;
|
||||||
|
this._ignoreAncestry = aIgnoreAncestry;
|
||||||
|
this._includeInvisible = aIncludeInvisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
PivotContext.prototype = {
|
PivotContext.prototype = {
|
||||||
@ -497,7 +505,7 @@ PivotContext.prototype = {
|
|||||||
*/
|
*/
|
||||||
get oldAncestry() {
|
get oldAncestry() {
|
||||||
if (!this._oldAncestry) {
|
if (!this._oldAncestry) {
|
||||||
if (!this._oldAccessible) {
|
if (!this._oldAccessible || this._ignoreAncestry) {
|
||||||
this._oldAncestry = [];
|
this._oldAncestry = [];
|
||||||
} else {
|
} else {
|
||||||
this._oldAncestry = this._getAncestry(this._oldAccessible);
|
this._oldAncestry = this._getAncestry(this._oldAccessible);
|
||||||
@ -512,7 +520,8 @@ PivotContext.prototype = {
|
|||||||
*/
|
*/
|
||||||
get currentAncestry() {
|
get currentAncestry() {
|
||||||
if (!this._currentAncestry) {
|
if (!this._currentAncestry) {
|
||||||
this._currentAncestry = this._getAncestry(this._accessible);
|
this._currentAncestry = this._ignoreAncestry ? [] :
|
||||||
|
this._getAncestry(this._accessible);
|
||||||
}
|
}
|
||||||
return this._currentAncestry;
|
return this._currentAncestry;
|
||||||
},
|
},
|
||||||
@ -524,7 +533,7 @@ PivotContext.prototype = {
|
|||||||
*/
|
*/
|
||||||
get newAncestry() {
|
get newAncestry() {
|
||||||
if (!this._newAncestry) {
|
if (!this._newAncestry) {
|
||||||
this._newAncestry = [currentAncestor for (
|
this._newAncestry = this._ignoreAncestry ? [] : [currentAncestor for (
|
||||||
[index, currentAncestor] of Iterator(this.currentAncestry)) if (
|
[index, currentAncestor] of Iterator(this.currentAncestry)) if (
|
||||||
currentAncestor !== this.oldAncestry[index])];
|
currentAncestor !== this.oldAncestry[index])];
|
||||||
}
|
}
|
||||||
@ -543,9 +552,14 @@ PivotContext.prototype = {
|
|||||||
}
|
}
|
||||||
let child = aAccessible.firstChild;
|
let child = aAccessible.firstChild;
|
||||||
while (child) {
|
while (child) {
|
||||||
let state = {};
|
let include;
|
||||||
child.getState(state, {});
|
if (this._includeInvisible) {
|
||||||
if (!(state.value & Ci.nsIAccessibleStates.STATE_INVISIBLE)) {
|
include = true;
|
||||||
|
} else {
|
||||||
|
let [state,] = Utils.getStates(child);
|
||||||
|
include = !(state.value & Ci.nsIAccessibleStates.STATE_INVISIBLE);
|
||||||
|
}
|
||||||
|
if (include) {
|
||||||
if (aPreorder) {
|
if (aPreorder) {
|
||||||
yield child;
|
yield child;
|
||||||
[yield node for (node of this._traverse(child, aPreorder, aStop))];
|
[yield node for (node of this._traverse(child, aPreorder, aStop))];
|
||||||
@ -703,7 +717,6 @@ PrefCache.prototype = {
|
|||||||
if (!this.type) {
|
if (!this.type) {
|
||||||
this.type = aBranch.getPrefType(this.name);
|
this.type = aBranch.getPrefType(this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case Ci.nsIPrefBranch.PREF_STRING:
|
case Ci.nsIPrefBranch.PREF_STRING:
|
||||||
return aBranch.getCharPref(this.name);
|
return aBranch.getCharPref(this.name);
|
||||||
|
@ -18,6 +18,7 @@ test_alive.html \
|
|||||||
test_braille.html \
|
test_braille.html \
|
||||||
test_explicit_names.html \
|
test_explicit_names.html \
|
||||||
test_landmarks.html \
|
test_landmarks.html \
|
||||||
|
test_live_regions.html \
|
||||||
test_tables.html \
|
test_tables.html \
|
||||||
test_utterance_order.html \
|
test_utterance_order.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@ -21,6 +21,68 @@ var AccessFuTest = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_registerListener: function AccessFuTest__registerListener(aWaitForMessage, aListenerFunc) {
|
||||||
|
var listener = {
|
||||||
|
observe: function observe(aMessage) {
|
||||||
|
// Ignore unexpected messages.
|
||||||
|
if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aMessage.message.indexOf(aWaitForMessage) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aListenerFunc.apply(listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Services.console.registerListener(listener);
|
||||||
|
return listener;
|
||||||
|
},
|
||||||
|
|
||||||
|
on_log: function AccessFuTest_on_log(aWaitForMessage, aListenerFunc) {
|
||||||
|
return this._registerListener(aWaitForMessage, aListenerFunc);
|
||||||
|
},
|
||||||
|
|
||||||
|
off_log: function AccessFuTest_off_log(aListener) {
|
||||||
|
Services.console.unregisterListener(aListener);
|
||||||
|
},
|
||||||
|
|
||||||
|
once_log: function AccessFuTest_once_log(aWaitForMessage, aListenerFunc) {
|
||||||
|
return this._registerListener(aWaitForMessage,
|
||||||
|
function listenAndUnregister() {
|
||||||
|
Services.console.unregisterListener(this);
|
||||||
|
aListenerFunc();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_addObserver: function AccessFuTest__addObserver(aWaitForData, aListener) {
|
||||||
|
var listener = function listener(aSubject, aTopic, aData) {
|
||||||
|
var data = JSON.parse(aData)[1];
|
||||||
|
// Ignore non-relevant outputs.
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isDeeply(data.details.actions, aWaitForData, "Data is correct");
|
||||||
|
aListener.apply(listener);
|
||||||
|
};
|
||||||
|
Services.obs.addObserver(listener, 'accessfu-output', false);
|
||||||
|
return listener;
|
||||||
|
},
|
||||||
|
|
||||||
|
on: function AccessFuTest_on(aWaitForData, aListener) {
|
||||||
|
return this._addObserver(aWaitForData, aListener);
|
||||||
|
},
|
||||||
|
|
||||||
|
off: function AccessFuTest_off(aListener) {
|
||||||
|
Services.obs.removeObserver(aListener, 'accessfu-output');
|
||||||
|
},
|
||||||
|
|
||||||
|
once: function AccessFuTest_once(aWaitForData, aListener) {
|
||||||
|
return this._addObserver(aWaitForData, function observerAndRemove() {
|
||||||
|
Services.obs.removeObserver(this, 'accessfu-output');
|
||||||
|
aListener();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
_waitForExplicitFinish: false,
|
_waitForExplicitFinish: false,
|
||||||
|
|
||||||
waitForExplicitFinish: function AccessFuTest_waitForExplicitFinish() {
|
waitForExplicitFinish: function AccessFuTest_waitForExplicitFinish() {
|
||||||
@ -38,6 +100,7 @@ var AccessFuTest = {
|
|||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
};
|
};
|
||||||
// Tear down accessibility and make AccessFu stop.
|
// Tear down accessibility and make AccessFu stop.
|
||||||
|
SpecialPowers.setIntPref("accessibility.accessfu.notify_output", 0);
|
||||||
SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
|
SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -87,5 +150,6 @@ var AccessFuTest = {
|
|||||||
|
|
||||||
// Invoke the whole thing.
|
// Invoke the whole thing.
|
||||||
SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
|
SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
|
||||||
|
SpecialPowers.setIntPref("accessibility.accessfu.notify_output", 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -18,52 +18,38 @@
|
|||||||
AccessFuTest.nextTest();
|
AccessFuTest.nextTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeEventManagerListener(waitForMessage, callback) {
|
// Listen for 'EventManager.stop' and enable AccessFu again.
|
||||||
return {
|
function onStop() {
|
||||||
observe: function observe(aMessage) {
|
ok(true, "EventManager was stopped.");
|
||||||
// Ignore unexpected messages.
|
isnot(AccessFu._enabled, true, "AccessFu was disabled.");
|
||||||
if (!(aMessage instanceof Components.interfaces.nsIConsoleMessage)) {
|
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
|
||||||
return;
|
AccessFu._enable();
|
||||||
}
|
|
||||||
if (aMessage.message.indexOf(waitForMessage) < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Services.console.unregisterListener(this);
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testEventManagerStartStop() {
|
// Make sure EventManager is started again.
|
||||||
// Firs listen for initial 'EventManager.start' and disable AccessFu.
|
function onFinalStart() {
|
||||||
var initialStartListener = makeEventManagerListener("EventManager.start",
|
ok(true, "EventManager was started again.");
|
||||||
function () {
|
ok(AccessFu._enabled, "AccessFu was enabled again.");
|
||||||
ok(true, "EventManager was started.");
|
AccessFuTest.finish();
|
||||||
Services.console.registerListener(stopListener);
|
}
|
||||||
AccessFu._disable();
|
|
||||||
});
|
|
||||||
// Listen for 'EventManager.stop' and enable AccessFu again.
|
|
||||||
var stopListener = makeEventManagerListener("EventManager.stop",
|
|
||||||
function () {
|
|
||||||
ok(true, "EventManager was stopped.");
|
|
||||||
isnot(AccessFu._enabled, true, "AccessFu was disabled.");
|
|
||||||
Services.console.registerListener(finalStartListener);
|
|
||||||
AccessFu._enable();
|
|
||||||
});
|
|
||||||
// Make sure EventManager is started again.
|
|
||||||
var finalStartListener = makeEventManagerListener("EventManager.start",
|
|
||||||
function () {
|
|
||||||
ok(true, "EventManager was started again.");
|
|
||||||
ok(AccessFu._enabled, "AccessFu was enabled again.");
|
|
||||||
AccessFuTest.finish();
|
|
||||||
});
|
|
||||||
|
|
||||||
Services.console.registerListener(initialStartListener);
|
// Listen for initial 'EventManager.start' and disable AccessFu.
|
||||||
|
function onInitialStart() {
|
||||||
|
ok(true, "EventManager was started.");
|
||||||
|
AccessFuTest.once_log("EventManager.stop", AccessFuTest.nextTest);
|
||||||
|
AccessFu._disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doTest() {
|
function doTest() {
|
||||||
AccessFuTest.addFunc(confirmAccessFuStart);
|
AccessFuTest.addFunc(confirmAccessFuStart);
|
||||||
AccessFuTest.addFunc(testEventManagerStartStop);
|
AccessFuTest.addFunc(init);
|
||||||
|
AccessFuTest.addFunc(onInitialStart);
|
||||||
|
AccessFuTest.addFunc(onStop);
|
||||||
|
AccessFuTest.addFunc(onFinalStart);
|
||||||
AccessFuTest.waitForExplicitFinish();
|
AccessFuTest.waitForExplicitFinish();
|
||||||
AccessFuTest.runTests(); // Will call SimpleTest.finish();
|
AccessFuTest.runTests(); // Will call SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
342
accessible/tests/mochitest/jsat/test_live_regions.html
Normal file
342
accessible/tests/mochitest/jsat/test_live_regions.html
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>AccessFu tests for live regions support</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../common.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="./jsatcommon.js"></script>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function EventManagerStarted() {
|
||||||
|
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide(id) {
|
||||||
|
var element = document.getElementById(id);
|
||||||
|
element.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(id) {
|
||||||
|
var element = document.getElementById(id);
|
||||||
|
element.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function udpate(id, text, property) {
|
||||||
|
var element = document.getElementById(id);
|
||||||
|
element[property] = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateText(id, text) {
|
||||||
|
udpate(id, text, "textContent");
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHTML(id, text) {
|
||||||
|
udpate(id, text, "innerHTML");
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = [{
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "hidden I will be hidden",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
[hide(id) for (id of ["to_hide1", "to_hide2", "to_hide3", "to_hide4"])];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "hidden I will be hidden",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
[hide(id) for (id of ["to_hide_descendant1", "to_hide_descendant2",
|
||||||
|
"to_hide_descendant3", "to_hide_descendant4"])];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "I will be shown",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
[show(id) for (id of ["to_show1", "to_show2", "to_show3", "to_show4"])];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "I will be shown",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
[show(id) for (id of ["to_show_descendant1", "to_show_descendant2",
|
||||||
|
"to_show_descendant3", "to_show_descendant4"])];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "hidden I will be hidden",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
hide("to_hide_live_assertive");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "I will be shown",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
[show(id) for (id of ["to_show_live_off", "to_show_live_assertive"])];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "Text Added",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateText("text_add", "Text Added");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "Text Added",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateHTML("text_add", "Text Added");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "hidden Text Removed",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateText("text_remove", "");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "Descendant Text Added",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateText("text_add_descendant", "Descendant Text Added");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "Descendant Text Added",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateHTML("text_add_descendant", "Descendant Text Added");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "hidden Descendant Text Removed",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateText("text_remove_descendant", "");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "Descendant Text Added",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateText("text_add_descendant2", "Descendant Text Added");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "Descendant Text Added",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateHTML("text_add_descendant2", "Descendant Text Added");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "hidden Descendant Text Removed",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateText("text_remove_descendant2", "");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "I am replaced main",
|
||||||
|
"options": {
|
||||||
|
"enqueue": true
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
var region = document.getElementById("to_replace_region");
|
||||||
|
var child = document.getElementById("to_replace");
|
||||||
|
child.setAttribute("role", "main");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "I am a replaced text",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateText("to_replace_text", "I am a replaced text");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
expected: [{
|
||||||
|
"method": "speak",
|
||||||
|
"data": "I am a replaced text",
|
||||||
|
"options": {
|
||||||
|
"enqueue": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
action: function action() {
|
||||||
|
updateHTML("to_replace_text", "I am a replaced text");
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
function doTest() {
|
||||||
|
AccessFuTest.addFunc(EventManagerStarted);
|
||||||
|
tests.forEach(function addTest(test) {
|
||||||
|
AccessFuTest.addFunc(function () {
|
||||||
|
AccessFuTest.once(test.expected, AccessFuTest.nextTest);
|
||||||
|
test.action();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
AccessFuTest.addFunc(AccessFuTest.finish);
|
||||||
|
AccessFuTest.waitForExplicitFinish();
|
||||||
|
AccessFuTest.runTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
addA11yLoadEvent(doTest);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=795957"
|
||||||
|
title="[AccessFu] Support live regions">
|
||||||
|
Mozilla Bug 795957
|
||||||
|
</a>
|
||||||
|
<div id="root">
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test"></pre>
|
||||||
|
|
||||||
|
<p id="to_hide1">I should not be announced 1</p>
|
||||||
|
<p id="to_hide2" aria-live="polite">I should not be announced 2</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>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p id="to_hide_descendant1">I should not be announced 1</p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="polite">
|
||||||
|
<p id="to_hide_descendant2">I should not be announced 2</p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="assertive" aria-relevant="text">
|
||||||
|
<p id="to_hide_descendant3">I should not be announced 3</p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="polite" aria-relevant="all">
|
||||||
|
<p id="to_hide_descendant4">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>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p id="to_show_descendant1" style="display: none">I should not be announced 1</p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="polite" aria-relevant="removals">
|
||||||
|
<p id="to_show_descendant2" style="display: none">I should not be announced 2</p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="assertive" aria-relevant="text">
|
||||||
|
<p id="to_show_descendant3" style="display: none">I should not be announced 3</p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="polite" aria-relevant="all">
|
||||||
|
<p id="to_show_descendant4" style="display: none">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>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<div id="to_replace_region" aria-live="polite" aria-relevant="all">
|
||||||
|
<p id="to_replace">I am replaced</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p id="to_replace_text" aria-live="assertive" aria-relevant="text">I am going to be replaced</p>
|
||||||
|
|
||||||
|
<p id="text_add" aria-live="assertive" aria-relevant="text"></p>
|
||||||
|
<p id="text_remove" aria-live="polite" aria-relevant="all">Text Removed</p>
|
||||||
|
|
||||||
|
<div aria-live="assertive" aria-relevant="all">
|
||||||
|
<p id="text_add_descendant"></p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="polite" aria-relevant="text">
|
||||||
|
<p id="text_remove_descendant">Descendant Text Removed</p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="assertive" aria-relevant="text">
|
||||||
|
<p id="text_add_descendant2"></p>
|
||||||
|
</div>
|
||||||
|
<div aria-live="polite" aria-relevant="all">
|
||||||
|
<p id="text_remove_descendant2">Descendant Text Removed</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -78,9 +78,9 @@ static void Output(const char *fmt, ... )
|
|||||||
#if MOZ_WINCONSOLE
|
#if MOZ_WINCONSOLE
|
||||||
fwprintf_s(stderr, wide_msg);
|
fwprintf_s(stderr, wide_msg);
|
||||||
#else
|
#else
|
||||||
MessageBoxW(NULL, wide_msg, L"Firefox", MB_OK
|
MessageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
|
||||||
| MB_ICONERROR
|
| MB_ICONERROR
|
||||||
| MB_SETFOREGROUND);
|
| MB_SETFOREGROUND);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -327,16 +327,16 @@ static int do_main(int argc, char* argv[], nsIFile *xreDirectory)
|
|||||||
// Check for a metro test harness command line args file
|
// Check for a metro test harness command line args file
|
||||||
HANDLE hTestFile = CreateFileA(path.get(),
|
HANDLE hTestFile = CreateFileA(path.get(),
|
||||||
GENERIC_READ,
|
GENERIC_READ,
|
||||||
0, NULL, OPEN_EXISTING,
|
0, nullptr, OPEN_EXISTING,
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
NULL);
|
nullptr);
|
||||||
if (hTestFile != INVALID_HANDLE_VALUE) {
|
if (hTestFile != INVALID_HANDLE_VALUE) {
|
||||||
// Typical test harness command line args string is around 100 bytes.
|
// Typical test harness command line args string is around 100 bytes.
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
if (!ReadFile(hTestFile, (VOID*)buffer, sizeof(buffer)-1,
|
if (!ReadFile(hTestFile, (VOID*)buffer, sizeof(buffer)-1,
|
||||||
&bytesRead, NULL) || !bytesRead) {
|
&bytesRead, nullptr) || !bytesRead) {
|
||||||
CloseHandle(hTestFile);
|
CloseHandle(hTestFile);
|
||||||
printf("failed to read test file '%s'", testFile);
|
printf("failed to read test file '%s'", testFile);
|
||||||
return -1;
|
return -1;
|
||||||
@ -351,7 +351,7 @@ static int do_main(int argc, char* argv[], nsIFile *xreDirectory)
|
|||||||
|
|
||||||
char* ptr = buffer;
|
char* ptr = buffer;
|
||||||
newArgv[0] = ptr;
|
newArgv[0] = ptr;
|
||||||
while (*ptr != NULL &&
|
while (*ptr != '\0' &&
|
||||||
(ptr - buffer) < sizeof(buffer) &&
|
(ptr - buffer) < sizeof(buffer) &&
|
||||||
newArgc < ARRAYSIZE(newArgv)) {
|
newArgc < ARRAYSIZE(newArgv)) {
|
||||||
if (isspace(*ptr)) {
|
if (isspace(*ptr)) {
|
||||||
@ -513,13 +513,13 @@ InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory)
|
|||||||
}
|
}
|
||||||
if (absfwurl) {
|
if (absfwurl) {
|
||||||
CFURLRef xulurl =
|
CFURLRef xulurl =
|
||||||
CFURLCreateCopyAppendingPathComponent(NULL, absfwurl,
|
CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl,
|
||||||
CFSTR("XUL.framework"),
|
CFSTR("XUL.framework"),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
if (xulurl) {
|
if (xulurl) {
|
||||||
CFURLRef xpcomurl =
|
CFURLRef xpcomurl =
|
||||||
CFURLCreateCopyAppendingPathComponent(NULL, xulurl,
|
CFURLCreateCopyAppendingPathComponent(nullptr, xulurl,
|
||||||
CFSTR("libxpcom.dylib"),
|
CFSTR("libxpcom.dylib"),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ pref("browser.download.manager.scanWhenDone", true);
|
|||||||
pref("browser.download.manager.resumeOnWakeDelay", 10000);
|
pref("browser.download.manager.resumeOnWakeDelay", 10000);
|
||||||
|
|
||||||
// Enables the asynchronous Downloads API in the Downloads Panel.
|
// Enables the asynchronous Downloads API in the Downloads Panel.
|
||||||
pref("browser.download.useJSTransfer", false);
|
pref("browser.download.useJSTransfer", true);
|
||||||
|
|
||||||
// This allows disabling the Downloads Panel in favor of the old interface.
|
// This allows disabling the Downloads Panel in favor of the old interface.
|
||||||
pref("browser.download.useToolkitUI", false);
|
pref("browser.download.useToolkitUI", false);
|
||||||
|
@ -112,10 +112,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reloadProvider() {
|
function reloadProvider() {
|
||||||
Social.enabled = false;
|
Social.provider.reload();
|
||||||
Services.tm.mainThread.dispatch(function() {
|
|
||||||
Social.enabled = true;
|
|
||||||
}, Components.interfaces.nsIThread.DISPATCH_NORMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parseQueryString();
|
parseQueryString();
|
||||||
|
@ -195,21 +195,7 @@ let gGestureSupport = {
|
|||||||
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
|
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
|
||||||
aEvent.DIRECTION_LEFT;
|
aEvent.DIRECTION_LEFT;
|
||||||
|
|
||||||
let isVerticalSwipe = false;
|
gHistorySwipeAnimation.startAnimation();
|
||||||
if (gHistorySwipeAnimation.active) {
|
|
||||||
if (aEvent.direction == aEvent.DIRECTION_UP) {
|
|
||||||
isVerticalSwipe = true;
|
|
||||||
// Force a synchronous scroll to the top of the page.
|
|
||||||
content.scrollTo(content.scrollX, 0);
|
|
||||||
}
|
|
||||||
else if (aEvent.direction == aEvent.DIRECTION_DOWN) {
|
|
||||||
isVerticalSwipe = true;
|
|
||||||
// Force a synchronous scroll to the bottom of the page.
|
|
||||||
content.scrollTo(content.scrollX, content.scrollMaxY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gHistorySwipeAnimation.startAnimation(isVerticalSwipe);
|
|
||||||
|
|
||||||
this._doUpdate = function GS__doUpdate(aEvent) {
|
this._doUpdate = function GS__doUpdate(aEvent) {
|
||||||
gHistorySwipeAnimation.updateAnimation(aEvent.delta);
|
gHistorySwipeAnimation.updateAnimation(aEvent.delta);
|
||||||
@ -563,13 +549,10 @@ let gHistorySwipeAnimation = {
|
|||||||
this.isLTR = document.documentElement.mozMatchesSelector(
|
this.isLTR = document.documentElement.mozMatchesSelector(
|
||||||
":-moz-locale-dir(ltr)");
|
":-moz-locale-dir(ltr)");
|
||||||
this._trackedSnapshots = [];
|
this._trackedSnapshots = [];
|
||||||
this._startingIndex = -1;
|
|
||||||
this._historyIndex = -1;
|
this._historyIndex = -1;
|
||||||
this._boxWidth = -1;
|
this._boxWidth = -1;
|
||||||
this._boxHeight = -1;
|
|
||||||
this._maxSnapshots = this._getMaxSnapshots();
|
this._maxSnapshots = this._getMaxSnapshots();
|
||||||
this._lastSwipeDir = "";
|
this._lastSwipeDir = "";
|
||||||
this._isVerticalSwipe = false;
|
|
||||||
|
|
||||||
// We only want to activate history swipe animations if we store snapshots.
|
// We only want to activate history swipe animations if we store snapshots.
|
||||||
// If we don't store any, we handle horizontal swipes without animations.
|
// If we don't store any, we handle horizontal swipes without animations.
|
||||||
@ -578,7 +561,6 @@ let gHistorySwipeAnimation = {
|
|||||||
gBrowser.addEventListener("pagehide", this, false);
|
gBrowser.addEventListener("pagehide", this, false);
|
||||||
gBrowser.addEventListener("pageshow", this, false);
|
gBrowser.addEventListener("pageshow", this, false);
|
||||||
gBrowser.addEventListener("popstate", this, false);
|
gBrowser.addEventListener("popstate", this, false);
|
||||||
gBrowser.addEventListener("DOMModalDialogClosed", this, false);
|
|
||||||
gBrowser.tabContainer.addEventListener("TabClose", this, false);
|
gBrowser.tabContainer.addEventListener("TabClose", this, false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -590,7 +572,6 @@ let gHistorySwipeAnimation = {
|
|||||||
gBrowser.removeEventListener("pagehide", this, false);
|
gBrowser.removeEventListener("pagehide", this, false);
|
||||||
gBrowser.removeEventListener("pageshow", this, false);
|
gBrowser.removeEventListener("pageshow", this, false);
|
||||||
gBrowser.removeEventListener("popstate", this, false);
|
gBrowser.removeEventListener("popstate", this, false);
|
||||||
gBrowser.removeEventListener("DOMModalDialogClosed", this, false);
|
|
||||||
gBrowser.tabContainer.removeEventListener("TabClose", this, false);
|
gBrowser.tabContainer.removeEventListener("TabClose", this, false);
|
||||||
|
|
||||||
this.active = false;
|
this.active = false;
|
||||||
@ -600,32 +581,17 @@ let gHistorySwipeAnimation = {
|
|||||||
/**
|
/**
|
||||||
* Starts the swipe animation and handles fast swiping (i.e. a swipe animation
|
* Starts the swipe animation and handles fast swiping (i.e. a swipe animation
|
||||||
* is already in progress when a new one is initiated).
|
* is already in progress when a new one is initiated).
|
||||||
*
|
|
||||||
* @param aIsVerticalSwipe
|
|
||||||
* Whether we're dealing with a vertical swipe or not.
|
|
||||||
*/
|
*/
|
||||||
startAnimation: function HSA_startAnimation(aIsVerticalSwipe) {
|
startAnimation: function HSA_startAnimation() {
|
||||||
this._isVerticalSwipe = aIsVerticalSwipe;
|
|
||||||
|
|
||||||
if (this.isAnimationRunning()) {
|
if (this.isAnimationRunning()) {
|
||||||
// If this is a horizontal scroll, or if this is a vertical scroll that
|
gBrowser.stop();
|
||||||
// was started while a horizontal scroll was still running, handle it as
|
this._lastSwipeDir = "RELOAD"; // just ensure that != ""
|
||||||
// as a fast swipe. In the case of the latter scenario, this allows us to
|
this._canGoBack = this.canGoBack();
|
||||||
// start the vertical animation without first loading the final page, or
|
this._canGoForward = this.canGoForward();
|
||||||
// taking another snapshot. If vertical scrolls are initiated repeatedly
|
this._handleFastSwiping();
|
||||||
// without prior horizontal scroll we skip this and restart the animation
|
|
||||||
// from 0.
|
|
||||||
if (!this._isVerticalSwipe || this._lastSwipeDir != "") {
|
|
||||||
gBrowser.stop();
|
|
||||||
this._lastSwipeDir = "RELOAD"; // just ensure that != ""
|
|
||||||
this._canGoBack = this.canGoBack();
|
|
||||||
this._canGoForward = this.canGoForward();
|
|
||||||
this._handleFastSwiping();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this._startingIndex = gBrowser.webNavigation.sessionHistory.index;
|
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
|
||||||
this._historyIndex = this._startingIndex;
|
|
||||||
this._canGoBack = this.canGoBack();
|
this._canGoBack = this.canGoBack();
|
||||||
this._canGoForward = this.canGoForward();
|
this._canGoForward = this.canGoForward();
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
@ -656,29 +622,20 @@ let gHistorySwipeAnimation = {
|
|||||||
if (!this.isAnimationRunning())
|
if (!this.isAnimationRunning())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We use the following value to decrease the bounce effect when scrolling
|
if ((aVal >= 0 && this.isLTR) ||
|
||||||
// to the top or bottom of the page, or when swiping back/forward past the
|
(aVal <= 0 && !this.isLTR)) {
|
||||||
// browsing history. This value was determined experimentally.
|
if (aVal > 1)
|
||||||
let dampValue = 4;
|
aVal = 1; // Cap value to avoid sliding the page further than allowed.
|
||||||
if (this._isVerticalSwipe) {
|
|
||||||
this._prevBox.collapsed = true;
|
|
||||||
this._nextBox.collapsed = true;
|
|
||||||
this._positionBox(this._curBox, -1 * aVal / dampValue);
|
|
||||||
}
|
|
||||||
else if ((aVal >= 0 && this.isLTR) ||
|
|
||||||
(aVal <= 0 && !this.isLTR)) {
|
|
||||||
let tempDampValue = 1;
|
|
||||||
if (this._canGoBack)
|
if (this._canGoBack)
|
||||||
this._prevBox.collapsed = false;
|
this._prevBox.collapsed = false;
|
||||||
else {
|
else
|
||||||
tempDampValue = dampValue;
|
|
||||||
this._prevBox.collapsed = true;
|
this._prevBox.collapsed = true;
|
||||||
}
|
|
||||||
|
|
||||||
// The current page is pushed to the right (LTR) or left (RTL),
|
// The current page is pushed to the right (LTR) or left (RTL),
|
||||||
// the intention is to go back.
|
// the intention is to go back.
|
||||||
// If there is a page to go back to, it should show in the background.
|
// If there is a page to go back to, it should show in the background.
|
||||||
this._positionBox(this._curBox, aVal / tempDampValue);
|
this._positionBox(this._curBox, aVal);
|
||||||
|
|
||||||
// The forward page should be pushed offscreen all the way to the right.
|
// The forward page should be pushed offscreen all the way to the right.
|
||||||
this._positionBox(this._nextBox, 1);
|
this._positionBox(this._nextBox, 1);
|
||||||
@ -694,14 +651,13 @@ let gHistorySwipeAnimation = {
|
|||||||
// For the backdrop to be visible in that case, the previous page needs
|
// For the backdrop to be visible in that case, the previous page needs
|
||||||
// to be hidden (if it exists).
|
// to be hidden (if it exists).
|
||||||
if (this._canGoForward) {
|
if (this._canGoForward) {
|
||||||
this._nextBox.collapsed = false;
|
|
||||||
let offset = this.isLTR ? 1 : -1;
|
let offset = this.isLTR ? 1 : -1;
|
||||||
this._positionBox(this._curBox, 0);
|
this._positionBox(this._curBox, 0);
|
||||||
this._positionBox(this._nextBox, offset + aVal);
|
this._positionBox(this._nextBox, offset + aVal); // aVal is negative
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this._prevBox.collapsed = true;
|
this._prevBox.collapsed = true;
|
||||||
this._positionBox(this._curBox, aVal / dampValue);
|
this._positionBox(this._curBox, aVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -718,14 +674,13 @@ let gHistorySwipeAnimation = {
|
|||||||
let browser = gBrowser.getBrowserForTab(aEvent.target);
|
let browser = gBrowser.getBrowserForTab(aEvent.target);
|
||||||
this._removeTrackedSnapshot(-1, browser);
|
this._removeTrackedSnapshot(-1, browser);
|
||||||
break;
|
break;
|
||||||
case "DOMModalDialogClosed":
|
|
||||||
this.stopAnimation();
|
|
||||||
break;
|
|
||||||
case "pageshow":
|
case "pageshow":
|
||||||
case "popstate":
|
case "popstate":
|
||||||
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
|
if (this.isAnimationRunning()) {
|
||||||
break;
|
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
|
||||||
this.stopAnimation();
|
break;
|
||||||
|
this.stopAnimation();
|
||||||
|
}
|
||||||
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
|
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
|
||||||
break;
|
break;
|
||||||
case "pagehide":
|
case "pagehide":
|
||||||
@ -793,7 +748,7 @@ let gHistorySwipeAnimation = {
|
|||||||
* any. This will also result in the animation overlay to be torn down.
|
* any. This will also result in the animation overlay to be torn down.
|
||||||
*/
|
*/
|
||||||
swipeEndEventReceived: function HSA_swipeEndEventReceived() {
|
swipeEndEventReceived: function HSA_swipeEndEventReceived() {
|
||||||
if (this._lastSwipeDir != "" && this._historyIndex != this._startingIndex)
|
if (this._lastSwipeDir != "")
|
||||||
this._navigateToHistoryIndex();
|
this._navigateToHistoryIndex();
|
||||||
else
|
else
|
||||||
this.stopAnimation();
|
this.stopAnimation();
|
||||||
@ -821,10 +776,9 @@ let gHistorySwipeAnimation = {
|
|||||||
* |this|.
|
* |this|.
|
||||||
*/
|
*/
|
||||||
_navigateToHistoryIndex: function HSA__navigateToHistoryIndex() {
|
_navigateToHistoryIndex: function HSA__navigateToHistoryIndex() {
|
||||||
if (this._doesIndexExistInHistory(this._historyIndex))
|
if (this._doesIndexExistInHistory(this._historyIndex)) {
|
||||||
gBrowser.webNavigation.gotoIndex(this._historyIndex);
|
gBrowser.webNavigation.gotoIndex(this._historyIndex);
|
||||||
else
|
}
|
||||||
this.stopAnimation();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -870,9 +824,7 @@ let gHistorySwipeAnimation = {
|
|||||||
"box");
|
"box");
|
||||||
this._container.appendChild(this._nextBox);
|
this._container.appendChild(this._nextBox);
|
||||||
|
|
||||||
// Cache width and height.
|
this._boxWidth = this._curBox.getBoundingClientRect().width; // cache width
|
||||||
this._boxWidth = this._curBox.getBoundingClientRect().width;
|
|
||||||
this._boxHeight = this._curBox.getBoundingClientRect().height;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -886,7 +838,6 @@ let gHistorySwipeAnimation = {
|
|||||||
this._container.parentNode.removeChild(this._container);
|
this._container.parentNode.removeChild(this._container);
|
||||||
this._container = null;
|
this._container = null;
|
||||||
this._boxWidth = -1;
|
this._boxWidth = -1;
|
||||||
this._boxHeight = -1;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -914,14 +865,7 @@ let gHistorySwipeAnimation = {
|
|||||||
* The position (in X coordinates) to move the box element to.
|
* The position (in X coordinates) to move the box element to.
|
||||||
*/
|
*/
|
||||||
_positionBox: function HSA__positionBox(aBox, aPosition) {
|
_positionBox: function HSA__positionBox(aBox, aPosition) {
|
||||||
let transform = "";
|
aBox.style.transform = "translateX(" + this._boxWidth * aPosition + "px)";
|
||||||
|
|
||||||
if (this._isVerticalSwipe)
|
|
||||||
transform = "translateY(" + this._boxHeight * aPosition + "px)";
|
|
||||||
else
|
|
||||||
transform = "translateX(" + this._boxWidth * aPosition + "px)";
|
|
||||||
|
|
||||||
aBox.style.transform = transform;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1060,17 +1004,12 @@ let gHistorySwipeAnimation = {
|
|||||||
return aBlob;
|
return aBlob;
|
||||||
|
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
let url = "";
|
let url = URL.createObjectURL(aBlob);
|
||||||
try {
|
img.onload = function() {
|
||||||
url = URL.createObjectURL(aBlob);
|
URL.revokeObjectURL(url);
|
||||||
img.onload = function() {
|
};
|
||||||
URL.revokeObjectURL(url);
|
img.src = url;
|
||||||
};
|
return img;
|
||||||
}
|
|
||||||
finally {
|
|
||||||
img.src = url;
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +36,7 @@ SocialUI = {
|
|||||||
Services.obs.addObserver(this, "social:frameworker-error", false);
|
Services.obs.addObserver(this, "social:frameworker-error", false);
|
||||||
Services.obs.addObserver(this, "social:provider-set", false);
|
Services.obs.addObserver(this, "social:provider-set", false);
|
||||||
Services.obs.addObserver(this, "social:providers-changed", false);
|
Services.obs.addObserver(this, "social:providers-changed", false);
|
||||||
|
Services.obs.addObserver(this, "social:provider-reload", false);
|
||||||
|
|
||||||
Services.prefs.addObserver("social.sidebar.open", this, false);
|
Services.prefs.addObserver("social.sidebar.open", this, false);
|
||||||
Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
|
Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
|
||||||
@ -60,6 +61,7 @@ SocialUI = {
|
|||||||
Services.obs.removeObserver(this, "social:frameworker-error");
|
Services.obs.removeObserver(this, "social:frameworker-error");
|
||||||
Services.obs.removeObserver(this, "social:provider-set");
|
Services.obs.removeObserver(this, "social:provider-set");
|
||||||
Services.obs.removeObserver(this, "social:providers-changed");
|
Services.obs.removeObserver(this, "social:providers-changed");
|
||||||
|
Services.obs.removeObserver(this, "social:provider-reload");
|
||||||
|
|
||||||
Services.prefs.removeObserver("social.sidebar.open", this);
|
Services.prefs.removeObserver("social.sidebar.open", this);
|
||||||
Services.prefs.removeObserver("social.toast-notifications.enabled", this);
|
Services.prefs.removeObserver("social.toast-notifications.enabled", this);
|
||||||
@ -74,6 +76,16 @@ SocialUI = {
|
|||||||
// manually :(
|
// manually :(
|
||||||
try {
|
try {
|
||||||
switch (topic) {
|
switch (topic) {
|
||||||
|
case "social:provider-reload":
|
||||||
|
// if the reloaded provider is our current provider, fall through
|
||||||
|
// to social:provider-set so the ui will be reset
|
||||||
|
if (!Social.provider || Social.provider.origin != data)
|
||||||
|
return;
|
||||||
|
// be sure to unload the sidebar as it will not reload if the origin
|
||||||
|
// has not changed, it will be loaded in provider-set below. Other
|
||||||
|
// panels will be unloaded or handle reload.
|
||||||
|
SocialSidebar.unloadSidebar();
|
||||||
|
// fall through to social:provider-set
|
||||||
case "social:provider-set":
|
case "social:provider-set":
|
||||||
// Social.provider has changed (possibly to null), update any state
|
// Social.provider has changed (possibly to null), update any state
|
||||||
// which depends on it.
|
// which depends on it.
|
||||||
@ -142,7 +154,7 @@ SocialUI = {
|
|||||||
|
|
||||||
// Miscellaneous helpers
|
// Miscellaneous helpers
|
||||||
showProfile: function SocialUI_showProfile() {
|
showProfile: function SocialUI_showProfile() {
|
||||||
if (Social.haveLoggedInUser())
|
if (Social.provider.haveLoggedInUser())
|
||||||
openUILinkIn(Social.provider.profile.profileURL, "tab");
|
openUILinkIn(Social.provider.profile.profileURL, "tab");
|
||||||
else {
|
else {
|
||||||
// XXX Bug 789585 will implement an API for provider-specified login pages.
|
// XXX Bug 789585 will implement an API for provider-specified login pages.
|
||||||
@ -976,22 +988,20 @@ SocialToolbar = {
|
|||||||
let toggleNotificationsCommand = document.getElementById("Social:ToggleNotifications");
|
let toggleNotificationsCommand = document.getElementById("Social:ToggleNotifications");
|
||||||
toggleNotificationsCommand.setAttribute("hidden", !socialEnabled);
|
toggleNotificationsCommand.setAttribute("hidden", !socialEnabled);
|
||||||
|
|
||||||
if (!Social.haveLoggedInUser() || !socialEnabled) {
|
let parent = document.getElementById("social-notification-panel");
|
||||||
let parent = document.getElementById("social-notification-panel");
|
while (parent.hasChildNodes()) {
|
||||||
while (parent.hasChildNodes()) {
|
let frame = parent.firstChild;
|
||||||
let frame = parent.firstChild;
|
SharedFrame.forgetGroup(frame.id);
|
||||||
SharedFrame.forgetGroup(frame.id);
|
parent.removeChild(frame);
|
||||||
parent.removeChild(frame);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let tbi = document.getElementById("social-toolbar-item");
|
let tbi = document.getElementById("social-toolbar-item");
|
||||||
if (tbi) {
|
if (tbi) {
|
||||||
// SocialMark is the last button allways
|
// SocialMark is the last button allways
|
||||||
let next = SocialMark.button.previousSibling;
|
let next = SocialMark.button.previousSibling;
|
||||||
while (next != this.button) {
|
while (next != this.button) {
|
||||||
tbi.removeChild(next);
|
tbi.removeChild(next);
|
||||||
next = SocialMark.button.previousSibling;
|
next = SocialMark.button.previousSibling;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1035,7 +1045,7 @@ SocialToolbar = {
|
|||||||
// provider.profile == undefined means no response yet from the provider
|
// provider.profile == undefined means no response yet from the provider
|
||||||
// to tell us whether the user is logged in or not.
|
// to tell us whether the user is logged in or not.
|
||||||
if (!SocialUI.enabled ||
|
if (!SocialUI.enabled ||
|
||||||
(!Social.haveLoggedInUser() && Social.provider.profile !== undefined)) {
|
(!Social.provider.haveLoggedInUser() && Social.provider.profile !== undefined)) {
|
||||||
// Either no enabled provider, or there is a provider and it has
|
// Either no enabled provider, or there is a provider and it has
|
||||||
// responded with a profile and the user isn't loggedin. The icons
|
// responded with a profile and the user isn't loggedin. The icons
|
||||||
// etc have already been removed by updateButtonHiddenState, so we want
|
// etc have already been removed by updateButtonHiddenState, so we want
|
||||||
|
@ -905,10 +905,7 @@ nsContextMenu.prototype = {
|
|||||||
reload: function(event) {
|
reload: function(event) {
|
||||||
if (this.onSocial) {
|
if (this.onSocial) {
|
||||||
// full reload of social provider
|
// full reload of social provider
|
||||||
Social.enabled = false;
|
Social.provider.reload();
|
||||||
Services.tm.mainThread.dispatch(function() {
|
|
||||||
Social.enabled = true;
|
|
||||||
}, Components.interfaces.nsIThread.DISPATCH_NORMAL);
|
|
||||||
} else {
|
} else {
|
||||||
BrowserReloadOrDuplicate(event);
|
BrowserReloadOrDuplicate(event);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|||||||
"resource://gre/modules/Task.jsm");
|
"resource://gre/modules/Task.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||||
"resource:///modules/DownloadsCommon.jsm");
|
"resource:///modules/DownloadsCommon.jsm");
|
||||||
|
|
||||||
function Sanitizer() {}
|
function Sanitizer() {}
|
||||||
Sanitizer.prototype = {
|
Sanitizer.prototype = {
|
||||||
// warning to the caller: this one may raise an exception (e.g. bug #265028)
|
// warning to the caller: this one may raise an exception (e.g. bug #265028)
|
||||||
@ -37,14 +37,14 @@ Sanitizer.prototype = {
|
|||||||
aCallback(aItemName, canClear, aArg);
|
aCallback(aItemName, canClear, aArg);
|
||||||
return canClear;
|
return canClear;
|
||||||
},
|
},
|
||||||
|
|
||||||
prefDomain: "",
|
prefDomain: "",
|
||||||
|
|
||||||
getNameFromPreference: function (aPreferenceName)
|
getNameFromPreference: function (aPreferenceName)
|
||||||
{
|
{
|
||||||
return aPreferenceName.substr(this.prefDomain.length);
|
return aPreferenceName.substr(this.prefDomain.length);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes privacy sensitive data in a batch, according to user preferences.
|
* Deletes privacy sensitive data in a batch, according to user preferences.
|
||||||
* Returns a promise which is resolved if no errors occurred. If an error
|
* Returns a promise which is resolved if no errors occurred. If an error
|
||||||
@ -87,7 +87,8 @@ Sanitizer.prototype = {
|
|||||||
item.clear();
|
item.clear();
|
||||||
} catch(er) {
|
} catch(er) {
|
||||||
seenError = true;
|
seenError = true;
|
||||||
Cu.reportError("Error sanitizing " + itemName + ": " + er + "\n");
|
Components.utils.reportError("Error sanitizing " + itemName +
|
||||||
|
": " + er + "\n");
|
||||||
}
|
}
|
||||||
onItemComplete();
|
onItemComplete();
|
||||||
};
|
};
|
||||||
@ -99,7 +100,7 @@ Sanitizer.prototype = {
|
|||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Time span only makes sense in certain cases. Consumers who want
|
// Time span only makes sense in certain cases. Consumers who want
|
||||||
// to only clear some private data can opt in by setting this to false,
|
// to only clear some private data can opt in by setting this to false,
|
||||||
// and can optionally specify a specific range. If timespan is not ignored,
|
// and can optionally specify a specific range. If timespan is not ignored,
|
||||||
@ -107,7 +108,7 @@ Sanitizer.prototype = {
|
|||||||
// pref to determine a range
|
// pref to determine a range
|
||||||
ignoreTimespan : true,
|
ignoreTimespan : true,
|
||||||
range : null,
|
range : null,
|
||||||
|
|
||||||
items: {
|
items: {
|
||||||
cache: {
|
cache: {
|
||||||
clear: function ()
|
clear: function ()
|
||||||
@ -126,13 +127,13 @@ Sanitizer.prototype = {
|
|||||||
imageCache.clearCache(false); // true=chrome, false=content
|
imageCache.clearCache(false); // true=chrome, false=content
|
||||||
} catch(er) {}
|
} catch(er) {}
|
||||||
},
|
},
|
||||||
|
|
||||||
get canClear()
|
get canClear()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
cookies: {
|
cookies: {
|
||||||
clear: function ()
|
clear: function ()
|
||||||
{
|
{
|
||||||
@ -143,7 +144,7 @@ Sanitizer.prototype = {
|
|||||||
var cookiesEnum = cookieMgr.enumerator;
|
var cookiesEnum = cookieMgr.enumerator;
|
||||||
while (cookiesEnum.hasMoreElements()) {
|
while (cookiesEnum.hasMoreElements()) {
|
||||||
var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
|
var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
|
||||||
|
|
||||||
if (cookie.creationTime > this.range[0])
|
if (cookie.creationTime > this.range[0])
|
||||||
// This cookie was created after our cutoff, clear it
|
// This cookie was created after our cutoff, clear it
|
||||||
cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
|
cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
|
||||||
@ -211,14 +212,14 @@ Sanitizer.prototype = {
|
|||||||
PlacesUtils.history.removeVisitsByTimeframe(this.range[0], this.range[1]);
|
PlacesUtils.history.removeVisitsByTimeframe(this.range[0], this.range[1]);
|
||||||
else
|
else
|
||||||
PlacesUtils.history.removeAllPages();
|
PlacesUtils.history.removeAllPages();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var os = Components.classes["@mozilla.org/observer-service;1"]
|
var os = Components.classes["@mozilla.org/observer-service;1"]
|
||||||
.getService(Components.interfaces.nsIObserverService);
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
os.notifyObservers(null, "browser:purge-session-history", "");
|
os.notifyObservers(null, "browser:purge-session-history", "");
|
||||||
}
|
}
|
||||||
catch (e) { }
|
catch (e) { }
|
||||||
|
|
||||||
// Clear last URL of the Open Web Location dialog
|
// Clear last URL of the Open Web Location dialog
|
||||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
.getService(Components.interfaces.nsIPrefBranch);
|
.getService(Components.interfaces.nsIPrefBranch);
|
||||||
@ -227,7 +228,7 @@ Sanitizer.prototype = {
|
|||||||
}
|
}
|
||||||
catch (e) { }
|
catch (e) { }
|
||||||
},
|
},
|
||||||
|
|
||||||
get canClear()
|
get canClear()
|
||||||
{
|
{
|
||||||
// bug 347231: Always allow clearing history due to dependencies on
|
// bug 347231: Always allow clearing history due to dependencies on
|
||||||
@ -235,7 +236,7 @@ Sanitizer.prototype = {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
formdata: {
|
formdata: {
|
||||||
clear: function ()
|
clear: function ()
|
||||||
{
|
{
|
||||||
@ -305,15 +306,20 @@ Sanitizer.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
downloads: {
|
downloads: {
|
||||||
clear: function ()
|
clear: function ()
|
||||||
{
|
{
|
||||||
if (DownloadsCommon.useJSTransfer) {
|
if (DownloadsCommon.useJSTransfer) {
|
||||||
Task.spawn(function () {
|
Task.spawn(function () {
|
||||||
let filterByTime = this.range ?
|
let filterByTime = null;
|
||||||
(download => download.startTime >= this.range[0] &&
|
if (this.range) {
|
||||||
download.startTime <= this.range[1]) : null;
|
// Convert microseconds back to milliseconds for date comparisons.
|
||||||
|
let rangeBeginMs = this.range[0] / 1000;
|
||||||
|
let rangeEndMs = this.range[1] / 1000;
|
||||||
|
filterByTime = download => download.startTime >= rangeBeginMs &&
|
||||||
|
download.startTime <= rangeEndMs;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear all completed/cancelled downloads
|
// Clear all completed/cancelled downloads
|
||||||
let publicList = yield Downloads.getPublicDownloadList();
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
@ -321,7 +327,7 @@ Sanitizer.prototype = {
|
|||||||
|
|
||||||
let privateList = yield Downloads.getPrivateDownloadList();
|
let privateList = yield Downloads.getPrivateDownloadList();
|
||||||
privateList.removeFinished(filterByTime);
|
privateList.removeFinished(filterByTime);
|
||||||
}.bind(this)).then(null, Cu.reportError);
|
}.bind(this)).then(null, Components.utils.reportError);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
|
var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
|
||||||
@ -352,7 +358,7 @@ Sanitizer.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
passwords: {
|
passwords: {
|
||||||
clear: function ()
|
clear: function ()
|
||||||
{
|
{
|
||||||
@ -361,7 +367,7 @@ Sanitizer.prototype = {
|
|||||||
// Passwords are timeless, and don't respect the timeSpan setting
|
// Passwords are timeless, and don't respect the timeSpan setting
|
||||||
pwmgr.removeAllLogins();
|
pwmgr.removeAllLogins();
|
||||||
},
|
},
|
||||||
|
|
||||||
get canClear()
|
get canClear()
|
||||||
{
|
{
|
||||||
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
||||||
@ -370,7 +376,7 @@ Sanitizer.prototype = {
|
|||||||
return (count > 0);
|
return (count > 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
sessions: {
|
sessions: {
|
||||||
clear: function ()
|
clear: function ()
|
||||||
{
|
{
|
||||||
@ -384,13 +390,13 @@ Sanitizer.prototype = {
|
|||||||
.getService(Components.interfaces.nsIObserverService);
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
os.notifyObservers(null, "net:clear-active-logins", null);
|
os.notifyObservers(null, "net:clear-active-logins", null);
|
||||||
},
|
},
|
||||||
|
|
||||||
get canClear()
|
get canClear()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
siteSettings: {
|
siteSettings: {
|
||||||
clear: function ()
|
clear: function ()
|
||||||
{
|
{
|
||||||
@ -398,12 +404,12 @@ Sanitizer.prototype = {
|
|||||||
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
|
||||||
.getService(Components.interfaces.nsIPermissionManager);
|
.getService(Components.interfaces.nsIPermissionManager);
|
||||||
pm.removeAll();
|
pm.removeAll();
|
||||||
|
|
||||||
// Clear site-specific settings like page-zoom level
|
// Clear site-specific settings like page-zoom level
|
||||||
var cps = Components.classes["@mozilla.org/content-pref/service;1"]
|
var cps = Components.classes["@mozilla.org/content-pref/service;1"]
|
||||||
.getService(Components.interfaces.nsIContentPrefService2);
|
.getService(Components.interfaces.nsIContentPrefService2);
|
||||||
cps.removeAllDomains(null);
|
cps.removeAllDomains(null);
|
||||||
|
|
||||||
// Clear "Never remember passwords for this site", which is not handled by
|
// Clear "Never remember passwords for this site", which is not handled by
|
||||||
// the permission manager
|
// the permission manager
|
||||||
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
|
||||||
@ -413,7 +419,7 @@ Sanitizer.prototype = {
|
|||||||
pwmgr.setLoginSavingEnabled(host, true);
|
pwmgr.setLoginSavingEnabled(host, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get canClear()
|
get canClear()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -446,7 +452,7 @@ Sanitizer.getClearRange = function (ts) {
|
|||||||
ts = Sanitizer.prefs.getIntPref("timeSpan");
|
ts = Sanitizer.prefs.getIntPref("timeSpan");
|
||||||
if (ts === Sanitizer.TIMESPAN_EVERYTHING)
|
if (ts === Sanitizer.TIMESPAN_EVERYTHING)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// PRTime is microseconds while JS time is milliseconds
|
// PRTime is microseconds while JS time is milliseconds
|
||||||
var endDate = Date.now() * 1000;
|
var endDate = Date.now() * 1000;
|
||||||
switch (ts) {
|
switch (ts) {
|
||||||
@ -473,7 +479,7 @@ Sanitizer.getClearRange = function (ts) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Sanitizer._prefs = null;
|
Sanitizer._prefs = null;
|
||||||
Sanitizer.__defineGetter__("prefs", function()
|
Sanitizer.__defineGetter__("prefs", function()
|
||||||
{
|
{
|
||||||
return Sanitizer._prefs ? Sanitizer._prefs
|
return Sanitizer._prefs ? Sanitizer._prefs
|
||||||
: Sanitizer._prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
: Sanitizer._prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||||
@ -482,7 +488,7 @@ Sanitizer.__defineGetter__("prefs", function()
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Shows sanitization UI
|
// Shows sanitization UI
|
||||||
Sanitizer.showUI = function(aParentWindow)
|
Sanitizer.showUI = function(aParentWindow)
|
||||||
{
|
{
|
||||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||||
.getService(Components.interfaces.nsIWindowWatcher);
|
.getService(Components.interfaces.nsIWindowWatcher);
|
||||||
@ -497,32 +503,32 @@ Sanitizer.showUI = function(aParentWindow)
|
|||||||
null);
|
null);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes privacy sensitive data in a batch, optionally showing the
|
* Deletes privacy sensitive data in a batch, optionally showing the
|
||||||
* sanitize UI, according to user preferences
|
* sanitize UI, according to user preferences
|
||||||
*/
|
*/
|
||||||
Sanitizer.sanitize = function(aParentWindow)
|
Sanitizer.sanitize = function(aParentWindow)
|
||||||
{
|
{
|
||||||
Sanitizer.showUI(aParentWindow);
|
Sanitizer.showUI(aParentWindow);
|
||||||
};
|
};
|
||||||
|
|
||||||
Sanitizer.onStartup = function()
|
Sanitizer.onStartup = function()
|
||||||
{
|
{
|
||||||
// we check for unclean exit with pending sanitization
|
// we check for unclean exit with pending sanitization
|
||||||
Sanitizer._checkAndSanitize();
|
Sanitizer._checkAndSanitize();
|
||||||
};
|
};
|
||||||
|
|
||||||
Sanitizer.onShutdown = function()
|
Sanitizer.onShutdown = function()
|
||||||
{
|
{
|
||||||
// we check if sanitization is needed and perform it
|
// we check if sanitization is needed and perform it
|
||||||
Sanitizer._checkAndSanitize();
|
Sanitizer._checkAndSanitize();
|
||||||
};
|
};
|
||||||
|
|
||||||
// this is called on startup and shutdown, to perform pending sanitizations
|
// this is called on startup and shutdown, to perform pending sanitizations
|
||||||
Sanitizer._checkAndSanitize = function()
|
Sanitizer._checkAndSanitize = function()
|
||||||
{
|
{
|
||||||
const prefs = Sanitizer.prefs;
|
const prefs = Sanitizer.prefs;
|
||||||
if (prefs.getBoolPref(Sanitizer.prefShutdown) &&
|
if (prefs.getBoolPref(Sanitizer.prefShutdown) &&
|
||||||
!prefs.prefHasUserValue(Sanitizer.prefDidShutdown)) {
|
!prefs.prefHasUserValue(Sanitizer.prefDidShutdown)) {
|
||||||
// this is a shutdown or a startup after an unclean exit
|
// this is a shutdown or a startup after an unclean exit
|
||||||
var s = new Sanitizer();
|
var s = new Sanitizer();
|
||||||
|
@ -2,10 +2,10 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
// Bug 453440 - Test the timespan-based logic of the sanitizer code
|
// Bug 453440 - Test the timespan-based logic of the sanitizer code
|
||||||
var now_uSec = Date.now() * 1000;
|
let now_mSec = Date.now();
|
||||||
|
let now_uSec = now_mSec * 1000;
|
||||||
const dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
|
|
||||||
|
|
||||||
|
const kMsecPerMin = 60 * 1000;
|
||||||
const kUsecPerMin = 60 * 1000000;
|
const kUsecPerMin = 60 * 1000000;
|
||||||
|
|
||||||
let tempScope = {};
|
let tempScope = {};
|
||||||
@ -14,6 +14,7 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
|||||||
let Sanitizer = tempScope.Sanitizer;
|
let Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
let FormHistory = (Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
|
let FormHistory = (Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
|
||||||
|
let Downloads = (Components.utils.import("resource://gre/modules/Downloads.jsm", {})).Downloads;
|
||||||
|
|
||||||
function promiseFormHistoryRemoved() {
|
function promiseFormHistoryRemoved() {
|
||||||
let deferred = Promise.defer();
|
let deferred = Promise.defer();
|
||||||
@ -24,15 +25,30 @@ function promiseFormHistoryRemoved() {
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function promiseDownloadRemoved(list) {
|
||||||
|
let deferred = Promise.defer();
|
||||||
|
|
||||||
|
let view = {
|
||||||
|
onDownloadRemoved: function(download) {
|
||||||
|
list.removeView(view);
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
list.addView(view);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
|
||||||
Task.spawn(function() {
|
Task.spawn(function() {
|
||||||
setupDownloads();
|
yield setupDownloads();
|
||||||
yield setupFormHistory();
|
yield setupFormHistory();
|
||||||
yield setupHistory();
|
yield setupHistory();
|
||||||
yield onHistoryReady();
|
yield onHistoryReady();
|
||||||
}).then(finish);
|
}).then(null, ex => ok(false, ex)).then(finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
function countEntries(name, message, check) {
|
function countEntries(name, message, check) {
|
||||||
@ -80,12 +96,16 @@ function onHistoryReady() {
|
|||||||
itemPrefs.setBoolPref("sessions", false);
|
itemPrefs.setBoolPref("sessions", false);
|
||||||
itemPrefs.setBoolPref("siteSettings", false);
|
itemPrefs.setBoolPref("siteSettings", false);
|
||||||
|
|
||||||
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
|
let downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Clear 10 minutes ago
|
// Clear 10 minutes ago
|
||||||
s.range = [now_uSec - 10*60*1000000, now_uSec];
|
s.range = [now_uSec - 10*60*1000000, now_uSec];
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
s.range = null;
|
s.range = null;
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://10minutes.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://10minutes.com"))),
|
||||||
"Pretend visit to 10minutes.com should now be deleted");
|
"Pretend visit to 10minutes.com should now be deleted");
|
||||||
@ -122,23 +142,26 @@ function onHistoryReady() {
|
|||||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
|
|
||||||
ok(!downloadExists(5555555), "10 minute download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-10-minutes")), "10 minute download should now be deleted");
|
||||||
ok(downloadExists(5555551), "<1 hour download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-1-hour")), "<1 hour download should still be present");
|
||||||
ok(downloadExists(5555556), "1 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-1-hour-10-minutes")), "1 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
ok(downloadExists(5555552), "<2 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-2-hour")), "<2 hour old download should still be present");
|
||||||
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-2-hour-10-minutes")), "2 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555553), "<4 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour")), "<4 hour old download should still be present");
|
||||||
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "4 hour 10 minute download should still be present");
|
||||||
|
|
||||||
if (minutesSinceMidnight > 10)
|
if (minutesSinceMidnight > 10)
|
||||||
ok(downloadExists(5555554), "'Today' download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-today")), "'Today' download should still be present");
|
||||||
|
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Clear 1 hour
|
// Clear 1 hour
|
||||||
Sanitizer.prefs.setIntPref("timeSpan", 1);
|
Sanitizer.prefs.setIntPref("timeSpan", 1);
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://1hour.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://1hour.com"))),
|
||||||
"Pretend visit to 1hour.com should now be deleted");
|
"Pretend visit to 1hour.com should now be deleted");
|
||||||
@ -169,23 +192,26 @@ function onHistoryReady() {
|
|||||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
|
|
||||||
ok(!downloadExists(5555551), "<1 hour download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-1-hour")), "<1 hour download should now be deleted");
|
||||||
ok(downloadExists(5555556), "1 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-1-hour-10-minutes")), "1 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
ok(downloadExists(5555552), "<2 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-2-hour")), "<2 hour old download should still be present");
|
||||||
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-2-hour-10-minutes")), "2 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555553), "<4 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour")), "<4 hour old download should still be present");
|
||||||
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "4 hour 10 minute download should still be present");
|
||||||
|
|
||||||
if (hoursSinceMidnight > 1)
|
if (hoursSinceMidnight > 1)
|
||||||
ok(downloadExists(5555554), "'Today' download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-today")), "'Today' download should still be present");
|
||||||
|
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Clear 1 hour 10 minutes
|
// Clear 1 hour 10 minutes
|
||||||
s.range = [now_uSec - 70*60*1000000, now_uSec];
|
s.range = [now_uSec - 70*60*1000000, now_uSec];
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
s.range = null;
|
s.range = null;
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://1hour10minutes.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://1hour10minutes.com"))),
|
||||||
"Pretend visit to 1hour10minutes.com should now be deleted");
|
"Pretend visit to 1hour10minutes.com should now be deleted");
|
||||||
@ -213,20 +239,23 @@ function onHistoryReady() {
|
|||||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
|
|
||||||
ok(!downloadExists(5555556), "1 hour 10 minute old download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-1-hour-10-minutes")), "1 hour 10 minute old download should now be deleted");
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
ok(downloadExists(5555552), "<2 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-2-hour")), "<2 hour old download should still be present");
|
||||||
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-2-hour-10-minutes")), "2 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555553), "<4 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour")), "<4 hour old download should still be present");
|
||||||
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "4 hour 10 minute download should still be present");
|
||||||
if (minutesSinceMidnight > 70)
|
if (minutesSinceMidnight > 70)
|
||||||
ok(downloadExists(5555554), "'Today' download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-today")), "'Today' download should still be present");
|
||||||
|
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Clear 2 hours
|
// Clear 2 hours
|
||||||
Sanitizer.prefs.setIntPref("timeSpan", 2);
|
Sanitizer.prefs.setIntPref("timeSpan", 2);
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://2hour.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://2hour.com"))),
|
||||||
"Pretend visit to 2hour.com should now be deleted");
|
"Pretend visit to 2hour.com should now be deleted");
|
||||||
@ -251,20 +280,23 @@ function onHistoryReady() {
|
|||||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
|
|
||||||
ok(!downloadExists(5555552), "<2 hour old download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-2-hour")), "<2 hour old download should now be deleted");
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-2-hour-10-minutes")), "2 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555553), "<4 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour")), "<4 hour old download should still be present");
|
||||||
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "4 hour 10 minute download should still be present");
|
||||||
if (hoursSinceMidnight > 2)
|
if (hoursSinceMidnight > 2)
|
||||||
ok(downloadExists(5555554), "'Today' download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-today")), "'Today' download should still be present");
|
||||||
|
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Clear 2 hours 10 minutes
|
// Clear 2 hours 10 minutes
|
||||||
s.range = [now_uSec - 130*60*1000000, now_uSec];
|
s.range = [now_uSec - 130*60*1000000, now_uSec];
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
s.range = null;
|
s.range = null;
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://2hour10minutes.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://2hour10minutes.com"))),
|
||||||
"Pretend visit to 2hour10minutes.com should now be deleted");
|
"Pretend visit to 2hour10minutes.com should now be deleted");
|
||||||
@ -286,18 +318,21 @@ function onHistoryReady() {
|
|||||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
|
|
||||||
ok(!downloadExists(5555557), "2 hour 10 minute old download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-2-hour-10-minutes")), "2 hour 10 minute old download should now be deleted");
|
||||||
ok(downloadExists(5555553), "<4 hour old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour")), "<4 hour old download should still be present");
|
||||||
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "4 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
if (minutesSinceMidnight > 130)
|
if (minutesSinceMidnight > 130)
|
||||||
ok(downloadExists(5555554), "'Today' download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-today")), "'Today' download should still be present");
|
||||||
|
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Clear 4 hours
|
// Clear 4 hours
|
||||||
Sanitizer.prefs.setIntPref("timeSpan", 3);
|
Sanitizer.prefs.setIntPref("timeSpan", 3);
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://4hour.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://4hour.com"))),
|
||||||
"Pretend visit to 4hour.com should now be deleted");
|
"Pretend visit to 4hour.com should now be deleted");
|
||||||
@ -316,11 +351,13 @@ function onHistoryReady() {
|
|||||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
|
|
||||||
ok(!downloadExists(5555553), "<4 hour old download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-4-hour")), "<4 hour old download should now be deleted");
|
||||||
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "4 hour 10 minute download should still be present");
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
if (hoursSinceMidnight > 4)
|
if (hoursSinceMidnight > 4)
|
||||||
ok(downloadExists(5555554), "'Today' download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-today")), "'Today' download should still be present");
|
||||||
|
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Clear 4 hours 10 minutes
|
// Clear 4 hours 10 minutes
|
||||||
s.range = [now_uSec - 250*60*1000000, now_uSec];
|
s.range = [now_uSec - 250*60*1000000, now_uSec];
|
||||||
@ -328,6 +365,7 @@ function onHistoryReady() {
|
|||||||
s.range = null;
|
s.range = null;
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://4hour10minutes.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://4hour10minutes.com"))),
|
||||||
"Pretend visit to 4hour10minutes.com should now be deleted");
|
"Pretend visit to 4hour10minutes.com should now be deleted");
|
||||||
@ -343,48 +381,60 @@ function onHistoryReady() {
|
|||||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
|
|
||||||
ok(!downloadExists(5555558), "4 hour 10 minute download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "4 hour 10 minute download should now be deleted");
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
if (minutesSinceMidnight > 250)
|
if (minutesSinceMidnight > 250)
|
||||||
ok(downloadExists(5555554), "'Today' download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-today")), "'Today' download should still be present");
|
||||||
|
|
||||||
|
// The 'Today' download might have been already deleted, in which case we
|
||||||
|
// should not wait for a download removal notification.
|
||||||
|
if (minutesSinceMidnight > 250) {
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
} else {
|
||||||
|
downloadPromise = Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
// Clear Today
|
// Clear Today
|
||||||
Sanitizer.prefs.setIntPref("timeSpan", 4);
|
Sanitizer.prefs.setIntPref("timeSpan", 4);
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
// Be careful. If we add our objectss just before midnight, and sanitize
|
// Be careful. If we add our objectss just before midnight, and sanitize
|
||||||
// runs immediately after, they won't be expired. This is expected, but
|
// runs immediately after, they won't be expired. This is expected, but
|
||||||
// we should not test in that case. We cannot just test for opposite
|
// we should not test in that case. We cannot just test for opposite
|
||||||
// condition because we could cross midnight just one moment after we
|
// condition because we could cross midnight just one moment after we
|
||||||
// cache our time, then we would have an even worse random failure.
|
// cache our time, then we would have an even worse random failure.
|
||||||
var today = isToday(new Date(now_uSec/1000));
|
var today = isToday(new Date(now_mSec));
|
||||||
if (today) {
|
if (today) {
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://today.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://today.com"))),
|
||||||
"Pretend visit to today.com should now be deleted");
|
"Pretend visit to today.com should now be deleted");
|
||||||
|
|
||||||
yield countEntries("today", "today form entry should be deleted", checkZero);
|
yield countEntries("today", "today form entry should be deleted", checkZero);
|
||||||
ok(!downloadExists(5555554), "'Today' download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-today")), "'Today' download should now be deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||||
"Pretend visit to before-today.com should still exist");
|
"Pretend visit to before-today.com should still exist");
|
||||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||||
ok(downloadExists(5555550), "Year old download should still be present");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Year old download should still be present");
|
||||||
|
|
||||||
|
downloadPromise = promiseDownloadRemoved(publicList);
|
||||||
|
|
||||||
// Choose everything
|
// Choose everything
|
||||||
Sanitizer.prefs.setIntPref("timeSpan", 0);
|
Sanitizer.prefs.setIntPref("timeSpan", 0);
|
||||||
s.sanitize();
|
s.sanitize();
|
||||||
|
|
||||||
yield promiseFormHistoryRemoved();
|
yield promiseFormHistoryRemoved();
|
||||||
|
yield downloadPromise;
|
||||||
|
|
||||||
ok(!(yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
ok(!(yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||||
"Pretend visit to before-today.com should now be deleted");
|
"Pretend visit to before-today.com should now be deleted");
|
||||||
|
|
||||||
yield countEntries("b4today", "b4today form entry should be deleted", checkZero);
|
yield countEntries("b4today", "b4today form entry should be deleted", checkZero);
|
||||||
|
|
||||||
ok(!downloadExists(5555550), "Year old download should now be deleted");
|
ok(!(yield downloadExists(publicList, "fakefile-old")), "Year old download should now be deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupHistory() {
|
function setupHistory() {
|
||||||
@ -562,227 +612,103 @@ function setupFormHistory() {
|
|||||||
|
|
||||||
function setupDownloads() {
|
function setupDownloads() {
|
||||||
|
|
||||||
// Add 10-minutes download to DB
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
let data = {
|
|
||||||
id: "5555555",
|
|
||||||
name: "fakefile-10-minutes",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
|
||||||
target: "fakefile-10-minutes",
|
|
||||||
startTime: now_uSec - 10 * kUsecPerMin, // 10 minutes ago, in uSec
|
|
||||||
endTime: now_uSec - 11 * kUsecPerMin, // 1 minute later
|
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
|
||||||
guid: "a1bcD23eF4g5"
|
|
||||||
};
|
|
||||||
|
|
||||||
let db = dm.DBConnection;
|
let download = yield Downloads.createDownload({
|
||||||
let stmt = db.createStatement(
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
||||||
"INSERT INTO moz_downloads (id, name, source, target, startTime, endTime, " +
|
target: "fakefile-10-minutes"
|
||||||
"state, currBytes, maxBytes, preferredAction, autoResume, guid) " +
|
});
|
||||||
"VALUES (:id, :name, :source, :target, :startTime, :endTime, :state, " +
|
download.startTime = new Date(now_mSec - 10 * kMsecPerMin), // 10 minutes ago
|
||||||
":currBytes, :maxBytes, :preferredAction, :autoResume, :guid)");
|
download.canceled = true;
|
||||||
try {
|
publicList.add(download);
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
download = yield Downloads.createDownload({
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add within-1-hour download to DB
|
|
||||||
data = {
|
|
||||||
id: "5555551",
|
|
||||||
name: "fakefile-1-hour",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
||||||
target: "fakefile-1-hour",
|
target: "fakefile-1-hour"
|
||||||
startTime: now_uSec - 45 * kUsecPerMin, // 45 minutes ago, in uSec
|
});
|
||||||
endTime: now_uSec - 44 * kUsecPerMin, // 1 minute later
|
download.startTime = new Date(now_mSec - 45 * kMsecPerMin), // 45 minutes ago
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "1bcD23eF4g5a"
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
download = yield Downloads.createDownload({
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add 1-hour-10-minutes download to DB
|
|
||||||
data = {
|
|
||||||
id: "5555556",
|
|
||||||
name: "fakefile-1-hour-10-minutes",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
||||||
target: "fakefile-1-hour-10-minutes",
|
target: "fakefile-1-hour-10-minutes"
|
||||||
startTime: now_uSec - 70 * kUsecPerMin, // 70 minutes ago, in uSec
|
});
|
||||||
endTime: now_uSec - 71 * kUsecPerMin, // 1 minute later
|
download.startTime = new Date(now_mSec - 70 * kMsecPerMin), // 70 minutes ago
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "a1cbD23e4Fg5"
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
download = yield Downloads.createDownload({
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add within-2-hour download
|
|
||||||
data = {
|
|
||||||
id: "5555552",
|
|
||||||
name: "fakefile-2-hour",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
||||||
target: "fakefile-2-hour",
|
target: "fakefile-2-hour"
|
||||||
startTime: now_uSec - 90 * kUsecPerMin, // 90 minutes ago, in uSec
|
});
|
||||||
endTime: now_uSec - 89 * kUsecPerMin, // 1 minute later
|
download.startTime = new Date(now_mSec - 90 * kMsecPerMin), // 90 minutes ago
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "b1aDc23eFg54"
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
download = yield Downloads.createDownload({
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add 2-hour-10-minutes download
|
|
||||||
data = {
|
|
||||||
id: "5555557",
|
|
||||||
name: "fakefile-2-hour-10-minutes",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
||||||
target: "fakefile-2-hour-10-minutes",
|
target: "fakefile-2-hour-10-minutes"
|
||||||
startTime: now_uSec - 130 * kUsecPerMin, // 130 minutes ago, in uSec
|
});
|
||||||
endTime: now_uSec - 131 * kUsecPerMin, // 1 minute later
|
download.startTime = new Date(now_mSec - 130 * kMsecPerMin), // 130 minutes ago
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "z1bcD23eF4g5"
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
download = yield Downloads.createDownload({
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add within-4-hour download
|
|
||||||
data = {
|
|
||||||
id: "5555553",
|
|
||||||
name: "fakefile-4-hour",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
||||||
target: "fakefile-4-hour",
|
target: "fakefile-4-hour"
|
||||||
startTime: now_uSec - 180 * kUsecPerMin, // 180 minutes ago, in uSec
|
});
|
||||||
endTime: now_uSec - 179 * kUsecPerMin, // 1 minute later
|
download.startTime = new Date(now_mSec - 180 * kMsecPerMin), // 180 minutes ago
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "zzzcD23eF4g5"
|
|
||||||
};
|
download = yield Downloads.createDownload({
|
||||||
|
|
||||||
try {
|
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add 4-hour-10-minutes download
|
|
||||||
data = {
|
|
||||||
id: "5555558",
|
|
||||||
name: "fakefile-4-hour-10-minutes",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
||||||
target: "fakefile-4-hour-10-minutes",
|
target: "fakefile-4-hour-10-minutes"
|
||||||
startTime: now_uSec - 250 * kUsecPerMin, // 250 minutes ago, in uSec
|
});
|
||||||
endTime: now_uSec - 251 * kUsecPerMin, // 1 minute later
|
download.startTime = new Date(now_mSec - 250 * kMsecPerMin), // 250 minutes ago
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "z1bzz23eF4gz"
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add "today" download
|
// Add "today" download
|
||||||
let today = new Date();
|
let today = new Date();
|
||||||
today.setHours(0);
|
today.setHours(0);
|
||||||
today.setMinutes(0);
|
today.setMinutes(0);
|
||||||
today.setSeconds(1);
|
today.setSeconds(1);
|
||||||
|
|
||||||
data = {
|
download = yield Downloads.createDownload({
|
||||||
id: "5555554",
|
|
||||||
name: "fakefile-today",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
||||||
target: "fakefile-today",
|
target: "fakefile-today"
|
||||||
startTime: today.getTime() * 1000, // 12:00:30am this morning, in uSec
|
});
|
||||||
endTime: (today.getTime() + 1000) * 1000, // 1 second later
|
download.startTime = today, // 12:00:01 AM this morning
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "ffffD23eF4g5"
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add "before today" download
|
// Add "before today" download
|
||||||
let lastYear = new Date();
|
let lastYear = new Date();
|
||||||
lastYear.setFullYear(lastYear.getFullYear() - 1);
|
lastYear.setFullYear(lastYear.getFullYear() - 1);
|
||||||
data = {
|
|
||||||
id: "5555550",
|
download = yield Downloads.createDownload({
|
||||||
name: "fakefile-old",
|
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
|
||||||
target: "fakefile-old",
|
target: "fakefile-old"
|
||||||
startTime: lastYear.getTime() * 1000, // 1 year ago, in uSec
|
});
|
||||||
endTime: (lastYear.getTime() + 1000) * 1000, // 1 second later
|
download.startTime = lastYear,
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
download.canceled = true;
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0,
|
publicList.add(download);
|
||||||
guid: "ggggg23eF4g5"
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (let prop in data)
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm everything worked
|
// Confirm everything worked
|
||||||
ok(downloadExists(5555550), "Pretend download for everything case should exist");
|
let downloads = yield publicList.getAll();
|
||||||
ok(downloadExists(5555555), "Pretend download for 10-minutes case should exist");
|
is(downloads.length, 9, "9 Pretend downloads added");
|
||||||
ok(downloadExists(5555551), "Pretend download for 1-hour case should exist");
|
|
||||||
ok(downloadExists(5555556), "Pretend download for 1-hour-10-minutes case should exist");
|
ok((yield downloadExists(publicList, "fakefile-old")), "Pretend download for everything case should exist");
|
||||||
ok(downloadExists(5555552), "Pretend download for 2-hour case should exist");
|
ok((yield downloadExists(publicList, "fakefile-10-minutes")), "Pretend download for 10-minutes case should exist");
|
||||||
ok(downloadExists(5555557), "Pretend download for 2-hour-10-minutes case should exist");
|
ok((yield downloadExists(publicList, "fakefile-1-hour")), "Pretend download for 1-hour case should exist");
|
||||||
ok(downloadExists(5555553), "Pretend download for 4-hour case should exist");
|
ok((yield downloadExists(publicList, "fakefile-1-hour-10-minutes")), "Pretend download for 1-hour-10-minutes case should exist");
|
||||||
ok(downloadExists(5555558), "Pretend download for 4-hour-10-minutes case should exist");
|
ok((yield downloadExists(publicList, "fakefile-2-hour")), "Pretend download for 2-hour case should exist");
|
||||||
ok(downloadExists(5555554), "Pretend download for Today case should exist");
|
ok((yield downloadExists(publicList, "fakefile-2-hour-10-minutes")), "Pretend download for 2-hour-10-minutes case should exist");
|
||||||
|
ok((yield downloadExists(publicList, "fakefile-4-hour")), "Pretend download for 4-hour case should exist");
|
||||||
|
ok((yield downloadExists(publicList, "fakefile-4-hour-10-minutes")), "Pretend download for 4-hour-10-minutes case should exist");
|
||||||
|
ok((yield downloadExists(publicList, "fakefile-today")), "Pretend download for Today case should exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -791,18 +717,12 @@ function setupDownloads() {
|
|||||||
* @param aID
|
* @param aID
|
||||||
* The ids of the downloads to check.
|
* The ids of the downloads to check.
|
||||||
*/
|
*/
|
||||||
function downloadExists(aID)
|
function downloadExists(list, path)
|
||||||
{
|
{
|
||||||
let db = dm.DBConnection;
|
return Task.spawn(function() {
|
||||||
let stmt = db.createStatement(
|
let listArray = yield list.getAll();
|
||||||
"SELECT * " +
|
throw new Task.Result(listArray.some(i => i.target.path == path));
|
||||||
"FROM moz_downloads " +
|
});
|
||||||
"WHERE id = :id"
|
|
||||||
);
|
|
||||||
stmt.params.id = aID;
|
|
||||||
var rows = stmt.executeStep();
|
|
||||||
stmt.finalize();
|
|
||||||
return rows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isToday(aDate) {
|
function isToday(aDate) {
|
||||||
|
@ -21,18 +21,18 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||||
"resource://gre/modules/FormHistory.jsm");
|
"resource://gre/modules/FormHistory.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||||
|
"resource://gre/modules/Downloads.jsm");
|
||||||
|
|
||||||
let tempScope = {};
|
let tempScope = {};
|
||||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||||
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||||
let Sanitizer = tempScope.Sanitizer;
|
let Sanitizer = tempScope.Sanitizer;
|
||||||
|
|
||||||
const dm = Cc["@mozilla.org/download-manager;1"].
|
const kMsecPerMin = 60 * 1000;
|
||||||
getService(Ci.nsIDownloadManager);
|
|
||||||
|
|
||||||
const kUsecPerMin = 60 * 1000000;
|
const kUsecPerMin = 60 * 1000000;
|
||||||
|
|
||||||
let formEntries;
|
let formEntries, downloadIDs, olderDownloadIDs;
|
||||||
|
|
||||||
// Add tests here. Each is a function that's called by doNextTest().
|
// Add tests here. Each is a function that's called by doNextTest().
|
||||||
var gAllTests = [
|
var gAllTests = [
|
||||||
@ -92,6 +92,23 @@ var gAllTests = [
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
function () {
|
||||||
|
// Add downloads (within the past hour).
|
||||||
|
Task.spawn(function () {
|
||||||
|
downloadIDs = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
yield addDownloadWithMinutesAgo(downloadIDs, i);
|
||||||
|
}
|
||||||
|
// Add downloads (over an hour ago).
|
||||||
|
olderDownloadIDs = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
yield addDownloadWithMinutesAgo(olderDownloadIDs, 61 + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
doNextTest();
|
||||||
|
}).then(null, Components.utils.reportError);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the combined history-downloads checkbox clears both history
|
* Ensures that the combined history-downloads checkbox clears both history
|
||||||
* visits and downloads when checked; the dialog respects simple timespan.
|
* visits and downloads when checked; the dialog respects simple timespan.
|
||||||
@ -115,16 +132,6 @@ var gAllTests = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
addVisits(places, function() {
|
addVisits(places, function() {
|
||||||
// Add downloads (within the past hour).
|
|
||||||
let downloadIDs = [];
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
downloadIDs.push(addDownloadWithMinutesAgo(i));
|
|
||||||
}
|
|
||||||
// Add downloads (over an hour ago).
|
|
||||||
let olderDownloadIDs = [];
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
olderDownloadIDs.push(addDownloadWithMinutesAgo(61 + i));
|
|
||||||
}
|
|
||||||
let totalHistoryVisits = uris.length + olderURIs.length;
|
let totalHistoryVisits = uris.length + olderURIs.length;
|
||||||
|
|
||||||
let wh = new WindowHelper();
|
let wh = new WindowHelper();
|
||||||
@ -146,16 +153,16 @@ var gAllTests = [
|
|||||||
wh.onunload = function () {
|
wh.onunload = function () {
|
||||||
// History visits and downloads within one hour should be cleared.
|
// History visits and downloads within one hour should be cleared.
|
||||||
yield promiseHistoryClearedState(uris, true);
|
yield promiseHistoryClearedState(uris, true);
|
||||||
ensureDownloadsClearedState(downloadIDs, true);
|
yield ensureDownloadsClearedState(downloadIDs, true);
|
||||||
|
|
||||||
// Visits and downloads > 1 hour should still exist.
|
// Visits and downloads > 1 hour should still exist.
|
||||||
yield promiseHistoryClearedState(olderURIs, false);
|
yield promiseHistoryClearedState(olderURIs, false);
|
||||||
ensureDownloadsClearedState(olderDownloadIDs, false);
|
yield ensureDownloadsClearedState(olderDownloadIDs, false);
|
||||||
|
|
||||||
// OK, done, cleanup after ourselves.
|
// OK, done, cleanup after ourselves.
|
||||||
yield blankSlate();
|
yield blankSlate();
|
||||||
yield promiseHistoryClearedState(olderURIs, true);
|
yield promiseHistoryClearedState(olderURIs, true);
|
||||||
ensureDownloadsClearedState(olderDownloadIDs, true);
|
yield ensureDownloadsClearedState(olderDownloadIDs, true);
|
||||||
};
|
};
|
||||||
wh.open();
|
wh.open();
|
||||||
});
|
});
|
||||||
@ -178,6 +185,18 @@ var gAllTests = [
|
|||||||
iter.next();
|
iter.next();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
function () {
|
||||||
|
// Add downloads (within the past hour).
|
||||||
|
Task.spawn(function () {
|
||||||
|
downloadIDs = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
yield addDownloadWithMinutesAgo(downloadIDs, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
doNextTest();
|
||||||
|
}).then(null, Components.utils.reportError);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the combined history-downloads checkbox removes neither
|
* Ensures that the combined history-downloads checkbox removes neither
|
||||||
* history visits nor downloads when not checked.
|
* history visits nor downloads when not checked.
|
||||||
@ -194,11 +213,6 @@ var gAllTests = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
addVisits(places, function() {
|
addVisits(places, function() {
|
||||||
let downloadIDs = [];
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
downloadIDs.push(addDownloadWithMinutesAgo(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
let wh = new WindowHelper();
|
let wh = new WindowHelper();
|
||||||
wh.onload = function () {
|
wh.onload = function () {
|
||||||
is(this.isWarningPanelVisible(), false,
|
is(this.isWarningPanelVisible(), false,
|
||||||
@ -224,7 +238,7 @@ var gAllTests = [
|
|||||||
wh.onunload = function () {
|
wh.onunload = function () {
|
||||||
// Of the three only form entries should be cleared.
|
// Of the three only form entries should be cleared.
|
||||||
yield promiseHistoryClearedState(uris, false);
|
yield promiseHistoryClearedState(uris, false);
|
||||||
ensureDownloadsClearedState(downloadIDs, false);
|
yield ensureDownloadsClearedState(downloadIDs, false);
|
||||||
|
|
||||||
formEntries.forEach(function (entry) {
|
formEntries.forEach(function (entry) {
|
||||||
let exists = yield formNameExists(entry);
|
let exists = yield formNameExists(entry);
|
||||||
@ -234,7 +248,7 @@ var gAllTests = [
|
|||||||
// OK, done, cleanup after ourselves.
|
// OK, done, cleanup after ourselves.
|
||||||
yield blankSlate();
|
yield blankSlate();
|
||||||
yield promiseHistoryClearedState(uris, true);
|
yield promiseHistoryClearedState(uris, true);
|
||||||
ensureDownloadsClearedState(downloadIDs, true);
|
yield ensureDownloadsClearedState(downloadIDs, true);
|
||||||
};
|
};
|
||||||
wh.open();
|
wh.open();
|
||||||
});
|
});
|
||||||
@ -639,15 +653,12 @@ var gAllTests = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// Used as the download database ID for a new download. Incremented for each
|
|
||||||
// new download. See addDownloadWithMinutesAgo().
|
|
||||||
var gDownloadId = 5555551;
|
|
||||||
|
|
||||||
// Index in gAllTests of the test currently being run. Incremented for each
|
// Index in gAllTests of the test currently being run. Incremented for each
|
||||||
// test run. See doNextTest().
|
// test run. See doNextTest().
|
||||||
var gCurrTest = 0;
|
var gCurrTest = 0;
|
||||||
|
|
||||||
var now_uSec = Date.now() * 1000;
|
let now_mSec = Date.now();
|
||||||
|
let now_uSec = now_mSec * 1000;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -847,7 +858,7 @@ WindowHelper.prototype = {
|
|||||||
if (wh.onunload) {
|
if (wh.onunload) {
|
||||||
Task.spawn(wh.onunload).then(function() {
|
Task.spawn(wh.onunload).then(function() {
|
||||||
waitForAsyncUpdates(doNextTest);
|
waitForAsyncUpdates(doNextTest);
|
||||||
});
|
}).then(null, Components.utils.reportError);
|
||||||
} else {
|
} else {
|
||||||
waitForAsyncUpdates(doNextTest);
|
waitForAsyncUpdates(doNextTest);
|
||||||
}
|
}
|
||||||
@ -900,40 +911,23 @@ WindowHelper.prototype = {
|
|||||||
* @param aMinutesAgo
|
* @param aMinutesAgo
|
||||||
* The download will be downloaded this many minutes ago
|
* The download will be downloaded this many minutes ago
|
||||||
*/
|
*/
|
||||||
function addDownloadWithMinutesAgo(aMinutesAgo) {
|
function addDownloadWithMinutesAgo(aExpectedPathList, aMinutesAgo) {
|
||||||
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
|
|
||||||
let name = "fakefile-" + aMinutesAgo + "-minutes-ago";
|
let name = "fakefile-" + aMinutesAgo + "-minutes-ago";
|
||||||
let data = {
|
let download = yield Downloads.createDownload({
|
||||||
id: gDownloadId,
|
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
||||||
name: name,
|
target: name
|
||||||
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
|
});
|
||||||
target: name,
|
download.startTime = new Date(now_mSec - (aMinutesAgo * kMsecPerMin));
|
||||||
startTime: now_uSec - (aMinutesAgo * kUsecPerMin),
|
download.canceled = true;
|
||||||
endTime: now_uSec - ((aMinutesAgo + 1) * kUsecPerMin),
|
publicList.add(download);
|
||||||
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
|
|
||||||
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
let db = dm.DBConnection;
|
ok((yield downloadExists(name)),
|
||||||
let stmt = db.createStatement(
|
"Sanity check: download " + name +
|
||||||
"INSERT INTO moz_downloads (id, name, source, target, startTime, endTime, " +
|
|
||||||
"state, currBytes, maxBytes, preferredAction, autoResume) " +
|
|
||||||
"VALUES (:id, :name, :source, :target, :startTime, :endTime, :state, " +
|
|
||||||
":currBytes, :maxBytes, :preferredAction, :autoResume)");
|
|
||||||
try {
|
|
||||||
for (let prop in data) {
|
|
||||||
stmt.params[prop] = data[prop];
|
|
||||||
}
|
|
||||||
stmt.execute();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
stmt.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
is(downloadExists(gDownloadId), true,
|
|
||||||
"Sanity check: download " + gDownloadId +
|
|
||||||
" should exist after creating it");
|
" should exist after creating it");
|
||||||
|
|
||||||
return gDownloadId++;
|
aExpectedPathList.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -984,15 +978,37 @@ function formNameExists(name)
|
|||||||
*/
|
*/
|
||||||
function blankSlate() {
|
function blankSlate() {
|
||||||
PlacesUtils.bhistory.removeAllPages();
|
PlacesUtils.bhistory.removeAllPages();
|
||||||
dm.cleanUp();
|
|
||||||
|
|
||||||
|
// The promise is resolved only when removing both downloads and form history are done.
|
||||||
let deferred = Promise.defer();
|
let deferred = Promise.defer();
|
||||||
|
let formHistoryDone = false, downloadsDone = false;
|
||||||
|
|
||||||
|
Task.spawn(function deleteAllDownloads() {
|
||||||
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
|
let downloads = yield publicList.getAll();
|
||||||
|
for (let download of downloads) {
|
||||||
|
publicList.remove(download);
|
||||||
|
yield download.finalize(true);
|
||||||
|
}
|
||||||
|
downloadsDone = true;
|
||||||
|
if (formHistoryDone) {
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
}).then(null, Components.utils.reportError);
|
||||||
|
|
||||||
FormHistory.update({ op: "remove" },
|
FormHistory.update({ op: "remove" },
|
||||||
{ handleError: function (error) {
|
{ handleError: function (error) {
|
||||||
do_throw("Error occurred updating form history: " + error);
|
do_throw("Error occurred updating form history: " + error);
|
||||||
deferred.reject(error);
|
deferred.reject(error);
|
||||||
},
|
},
|
||||||
handleCompletion: function (reason) { if (!reason) deferred.resolve(); }
|
handleCompletion: function (reason) {
|
||||||
|
if (!reason) {
|
||||||
|
formHistoryDone = true;
|
||||||
|
if (downloadsDone) {
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
@ -1012,24 +1028,19 @@ function boolPrefIs(aPrefName, aExpectedVal, aMsg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if the download with the specified ID exists.
|
* Checks to see if the download with the specified path exists.
|
||||||
*
|
*
|
||||||
* @param aID
|
* @param aPath
|
||||||
* The ID of the download to check
|
* The path of the download to check
|
||||||
* @return True if the download exists, false otherwise
|
* @return True if the download exists, false otherwise
|
||||||
*/
|
*/
|
||||||
function downloadExists(aID)
|
function downloadExists(aPath)
|
||||||
{
|
{
|
||||||
let db = dm.DBConnection;
|
return Task.spawn(function() {
|
||||||
let stmt = db.createStatement(
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
"SELECT * " +
|
let listArray = yield publicList.getAll();
|
||||||
"FROM moz_downloads " +
|
throw new Task.Result(listArray.some(i => i.target.path == aPath));
|
||||||
"WHERE id = :id"
|
});
|
||||||
);
|
|
||||||
stmt.params.id = aID;
|
|
||||||
let rows = stmt.executeStep();
|
|
||||||
stmt.finalize();
|
|
||||||
return !!rows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1059,7 +1070,7 @@ function doNextTest() {
|
|||||||
function ensureDownloadsClearedState(aDownloadIDs, aShouldBeCleared) {
|
function ensureDownloadsClearedState(aDownloadIDs, aShouldBeCleared) {
|
||||||
let niceStr = aShouldBeCleared ? "no longer" : "still";
|
let niceStr = aShouldBeCleared ? "no longer" : "still";
|
||||||
aDownloadIDs.forEach(function (id) {
|
aDownloadIDs.forEach(function (id) {
|
||||||
is(downloadExists(id), !aShouldBeCleared,
|
is((yield downloadExists(id)), !aShouldBeCleared,
|
||||||
"download " + id + " should " + niceStr + " exist");
|
"download " + id + " should " + niceStr + " exist");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||||||
browser_newtab_block.js \
|
browser_newtab_block.js \
|
||||||
browser_newtab_disable.js \
|
browser_newtab_disable.js \
|
||||||
browser_newtab_drag_drop.js \
|
browser_newtab_drag_drop.js \
|
||||||
|
browser_newtab_drag_drop_ext.js \
|
||||||
browser_newtab_drop_preview.js \
|
browser_newtab_drop_preview.js \
|
||||||
browser_newtab_focus.js \
|
browser_newtab_focus.js \
|
||||||
browser_newtab_reset.js \
|
browser_newtab_reset.js \
|
||||||
|
@ -71,47 +71,4 @@ function runTests() {
|
|||||||
|
|
||||||
yield simulateDrop(0, 4);
|
yield simulateDrop(0, 4);
|
||||||
checkGrid("3,1p,2p,4,0p,5p,6,7,8");
|
checkGrid("3,1p,2p,4,0p,5p,6,7,8");
|
||||||
|
|
||||||
// drag a new site onto the very first cell
|
|
||||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
|
||||||
setPinnedLinks(",,,,,,,7,8");
|
|
||||||
|
|
||||||
yield addNewTabPageTab();
|
|
||||||
checkGrid("0,1,2,3,4,5,6,7p,8p");
|
|
||||||
|
|
||||||
yield simulateExternalDrop(0);
|
|
||||||
checkGrid("99p,0,1,2,3,4,5,7p,8p");
|
|
||||||
|
|
||||||
// drag a new site onto the grid and make sure that pinned cells don't get
|
|
||||||
// pushed out
|
|
||||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
|
||||||
setPinnedLinks(",,,,,,,7,8");
|
|
||||||
|
|
||||||
yield addNewTabPageTab();
|
|
||||||
checkGrid("0,1,2,3,4,5,6,7p,8p");
|
|
||||||
|
|
||||||
yield simulateExternalDrop(7);
|
|
||||||
checkGrid("0,1,2,3,4,5,7p,99p,8p");
|
|
||||||
|
|
||||||
// drag a new site beneath a pinned cell and make sure the pinned cell is
|
|
||||||
// not moved
|
|
||||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
|
||||||
setPinnedLinks(",,,,,,,,8");
|
|
||||||
|
|
||||||
yield addNewTabPageTab();
|
|
||||||
checkGrid("0,1,2,3,4,5,6,7,8p");
|
|
||||||
|
|
||||||
yield simulateExternalDrop(7);
|
|
||||||
checkGrid("0,1,2,3,4,5,6,99p,8p");
|
|
||||||
|
|
||||||
// drag a new site onto a block of pinned sites and make sure they're shifted
|
|
||||||
// around accordingly
|
|
||||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
|
||||||
setPinnedLinks("0,1,2,,,,,,");
|
|
||||||
|
|
||||||
yield addNewTabPageTab();
|
|
||||||
checkGrid("0p,1p,2p");
|
|
||||||
|
|
||||||
yield simulateExternalDrop(1);
|
|
||||||
checkGrid("0p,99p,1p,2p,3,4,5,6,7");
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These tests make sure that dragging and dropping sites works as expected.
|
||||||
|
* Sites contained in the grid need to shift around to indicate the result
|
||||||
|
* of the drag-and-drop operation. If the grid is full and we're dragging
|
||||||
|
* a new site into it another one gets pushed out.
|
||||||
|
* This is a continuation of browser_newtab_drag_drop.js
|
||||||
|
* to decrease test run time, focusing on external sites.
|
||||||
|
*/
|
||||||
|
function runTests() {
|
||||||
|
// drag a new site onto the very first cell
|
||||||
|
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||||
|
setPinnedLinks(",,,,,,,7,8");
|
||||||
|
|
||||||
|
yield addNewTabPageTab();
|
||||||
|
checkGrid("0,1,2,3,4,5,6,7p,8p");
|
||||||
|
|
||||||
|
yield simulateExternalDrop(0);
|
||||||
|
checkGrid("99p,0,1,2,3,4,5,7p,8p");
|
||||||
|
|
||||||
|
// drag a new site onto the grid and make sure that pinned cells don't get
|
||||||
|
// pushed out
|
||||||
|
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||||
|
setPinnedLinks(",,,,,,,7,8");
|
||||||
|
|
||||||
|
yield addNewTabPageTab();
|
||||||
|
checkGrid("0,1,2,3,4,5,6,7p,8p");
|
||||||
|
|
||||||
|
yield simulateExternalDrop(7);
|
||||||
|
checkGrid("0,1,2,3,4,5,7p,99p,8p");
|
||||||
|
|
||||||
|
// drag a new site beneath a pinned cell and make sure the pinned cell is
|
||||||
|
// not moved
|
||||||
|
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||||
|
setPinnedLinks(",,,,,,,,8");
|
||||||
|
|
||||||
|
yield addNewTabPageTab();
|
||||||
|
checkGrid("0,1,2,3,4,5,6,7,8p");
|
||||||
|
|
||||||
|
yield simulateExternalDrop(7);
|
||||||
|
checkGrid("0,1,2,3,4,5,6,99p,8p");
|
||||||
|
|
||||||
|
// drag a new site onto a block of pinned sites and make sure they're shifted
|
||||||
|
// around accordingly
|
||||||
|
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||||
|
setPinnedLinks("0,1,2,,,,,,");
|
||||||
|
|
||||||
|
yield addNewTabPageTab();
|
||||||
|
checkGrid("0p,1p,2p");
|
||||||
|
|
||||||
|
yield simulateExternalDrop(1);
|
||||||
|
checkGrid("0p,99p,1p,2p,3,4,5,6,7");
|
||||||
|
}
|
@ -30,6 +30,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||||||
browser_social_chatwindow_resize.js \
|
browser_social_chatwindow_resize.js \
|
||||||
browser_social_chatwindowfocus.js \
|
browser_social_chatwindowfocus.js \
|
||||||
browser_social_multiprovider.js \
|
browser_social_multiprovider.js \
|
||||||
|
browser_social_multiworker.js \
|
||||||
browser_social_errorPage.js \
|
browser_social_errorPage.js \
|
||||||
browser_social_window.js \
|
browser_social_window.js \
|
||||||
social_activate.html \
|
social_activate.html \
|
||||||
|
@ -2,17 +2,71 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
|
||||||
|
|
||||||
|
let manifests = [
|
||||||
|
{
|
||||||
|
name: "provider@example.com",
|
||||||
|
origin: "https://example.com",
|
||||||
|
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html?example.com",
|
||||||
|
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||||
|
iconURL: "chrome://branding/content/icon48.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "provider@test1",
|
||||||
|
origin: "https://test1.example.com",
|
||||||
|
sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html?test1",
|
||||||
|
workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||||
|
iconURL: "chrome://branding/content/icon48.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "provider@test2",
|
||||||
|
origin: "https://test2.example.com",
|
||||||
|
sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html?test2",
|
||||||
|
workerURL: "https://test2.example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||||
|
iconURL: "chrome://branding/content/icon48.png"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let chatId = 0;
|
||||||
|
function openChat(provider, callback) {
|
||||||
|
let chatUrl = provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
|
let port = provider.getWorkerPort();
|
||||||
|
port.onmessage = function(e) {
|
||||||
|
if (e.data.topic == "got-chatbox-message") {
|
||||||
|
port.close();
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let url = chatUrl + "?" + (chatId++);
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
port.postMessage({topic: "test-worker-chat", data: url});
|
||||||
|
gURLsNotRemembered.push(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitPrefChange(cb) {
|
||||||
|
Services.prefs.addObserver("social.enabled", function prefObserver(subject, topic, data) {
|
||||||
|
Services.prefs.removeObserver("social.enabled", prefObserver);
|
||||||
|
executeSoon(cb);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setWorkerMode(multiple, cb) {
|
||||||
|
waitPrefChange(function() {
|
||||||
|
if (multiple)
|
||||||
|
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
|
||||||
|
else
|
||||||
|
Services.prefs.clearUserPref("social.allowMultipleWorkers");
|
||||||
|
waitPrefChange(cb);
|
||||||
|
Social.enabled = true;
|
||||||
|
});
|
||||||
|
Social.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
requestLongerTimeout(2); // only debug builds seem to need more time...
|
requestLongerTimeout(2); // only debug builds seem to need more time...
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
|
||||||
let manifest = { // normal provider
|
|
||||||
name: "provider 1",
|
|
||||||
origin: "https://example.com",
|
|
||||||
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
|
|
||||||
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
|
|
||||||
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
|
|
||||||
};
|
|
||||||
let oldwidth = window.outerWidth; // we futz with these, so we restore them
|
let oldwidth = window.outerWidth; // we futz with these, so we restore them
|
||||||
let oldleft = window.screenX;
|
let oldleft = window.screenX;
|
||||||
window.moveTo(0, window.screenY)
|
window.moveTo(0, window.screenY)
|
||||||
@ -21,7 +75,7 @@ function test() {
|
|||||||
ok(chats.children.length == 0, "no chatty children left behind");
|
ok(chats.children.length == 0, "no chatty children left behind");
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
runSocialTestWithProvider(manifest, function (finishcb) {
|
runSocialTestWithProvider(manifests, function (finishcb) {
|
||||||
runSocialTests(tests, undefined, postSubTest, function() {
|
runSocialTests(tests, undefined, postSubTest, function() {
|
||||||
window.moveTo(oldleft, window.screenY)
|
window.moveTo(oldleft, window.screenY)
|
||||||
window.resizeTo(oldwidth, window.outerHeight);
|
window.resizeTo(oldwidth, window.outerHeight);
|
||||||
@ -147,7 +201,7 @@ var tests = {
|
|||||||
maybeOpenAnother();
|
maybeOpenAnother();
|
||||||
},
|
},
|
||||||
testWorkerChatWindow: function(next) {
|
testWorkerChatWindow: function(next) {
|
||||||
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
const chatUrl = Social.provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
let chats = document.getElementById("pinnedchats");
|
let chats = document.getElementById("pinnedchats");
|
||||||
let port = Social.provider.getWorkerPort();
|
let port = Social.provider.getWorkerPort();
|
||||||
ok(port, "provider has a port");
|
ok(port, "provider has a port");
|
||||||
@ -384,7 +438,7 @@ var tests = {
|
|||||||
|
|
||||||
testSecondTopLevelWindow: function(next) {
|
testSecondTopLevelWindow: function(next) {
|
||||||
// Bug 817782 - check chats work in new top-level windows.
|
// Bug 817782 - check chats work in new top-level windows.
|
||||||
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
const chatUrl = Social.provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
let port = Social.provider.getWorkerPort();
|
let port = Social.provider.getWorkerPort();
|
||||||
let secondWindow;
|
let secondWindow;
|
||||||
port.onmessage = function(e) {
|
port.onmessage = function(e) {
|
||||||
@ -407,23 +461,9 @@ var tests = {
|
|||||||
testChatWindowChooser: function(next) {
|
testChatWindowChooser: function(next) {
|
||||||
// Tests that when a worker creates a chat, it is opened in the correct
|
// Tests that when a worker creates a chat, it is opened in the correct
|
||||||
// window.
|
// window.
|
||||||
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
|
||||||
let chatId = 1;
|
|
||||||
let port = Social.provider.getWorkerPort();
|
|
||||||
port.postMessage({topic: "test-init"});
|
|
||||||
|
|
||||||
function openChat(callback) {
|
|
||||||
port.onmessage = function(e) {
|
|
||||||
if (e.data.topic == "got-chatbox-message")
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
let url = chatUrl + "?" + (chatId++);
|
|
||||||
port.postMessage({topic: "test-worker-chat", data: url});
|
|
||||||
}
|
|
||||||
|
|
||||||
// open a chat (it will open in the main window)
|
// open a chat (it will open in the main window)
|
||||||
ok(!window.SocialChatBar.hasChats, "first window should start with no chats");
|
ok(!window.SocialChatBar.hasChats, "first window should start with no chats");
|
||||||
openChat(function() {
|
openChat(Social.provider, function() {
|
||||||
ok(window.SocialChatBar.hasChats, "first window has the chat");
|
ok(window.SocialChatBar.hasChats, "first window has the chat");
|
||||||
// create a second window - this will be the "most recent" and will
|
// create a second window - this will be the "most recent" and will
|
||||||
// therefore be the window that hosts the new chat (see bug 835111)
|
// therefore be the window that hosts the new chat (see bug 835111)
|
||||||
@ -431,27 +471,55 @@ var tests = {
|
|||||||
secondWindow.addEventListener("load", function loadListener() {
|
secondWindow.addEventListener("load", function loadListener() {
|
||||||
secondWindow.removeEventListener("load", loadListener);
|
secondWindow.removeEventListener("load", loadListener);
|
||||||
ok(!secondWindow.SocialChatBar.hasChats, "second window has no chats");
|
ok(!secondWindow.SocialChatBar.hasChats, "second window has no chats");
|
||||||
openChat(function() {
|
openChat(Social.provider, function() {
|
||||||
ok(secondWindow.SocialChatBar.hasChats, "second window now has chats");
|
ok(secondWindow.SocialChatBar.hasChats, "second window now has chats");
|
||||||
is(window.SocialChatBar.chatbar.childElementCount, 1, "first window still has 1 chat");
|
is(window.SocialChatBar.chatbar.childElementCount, 1, "first window still has 1 chat");
|
||||||
window.SocialChatBar.chatbar.removeAll();
|
window.SocialChatBar.chatbar.removeAll();
|
||||||
// now open another chat - it should still open in the second.
|
// now open another chat - it should still open in the second.
|
||||||
openChat(function() {
|
openChat(Social.provider, function() {
|
||||||
ok(!window.SocialChatBar.hasChats, "first window has no chats");
|
ok(!window.SocialChatBar.hasChats, "first window has no chats");
|
||||||
ok(secondWindow.SocialChatBar.hasChats, "second window has a chat");
|
ok(secondWindow.SocialChatBar.hasChats, "second window has a chat");
|
||||||
secondWindow.close();
|
secondWindow.close();
|
||||||
port.close();
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
testMultipleProviderChat: function(next) {
|
||||||
|
// while pref'd off, we need to set the worker mode to multiple providers
|
||||||
|
setWorkerMode(true, function() {
|
||||||
|
// test incomming chats from all providers
|
||||||
|
openChat(Social.providers[0], function() {
|
||||||
|
openChat(Social.providers[1], function() {
|
||||||
|
openChat(Social.providers[2], function() {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
waitForCondition(function() chats.children.length == Social.providers.length,
|
||||||
|
function() {
|
||||||
|
ok(true, "one chat window per provider opened");
|
||||||
|
// test logout of a single provider
|
||||||
|
let provider = Social.providers[0];
|
||||||
|
let port = provider.getWorkerPort();
|
||||||
|
port.postMessage({topic: "test-logout"});
|
||||||
|
waitForCondition(function() chats.children.length == Social.providers.length - 1,
|
||||||
|
function() {
|
||||||
|
port.close();
|
||||||
|
chats.removeAll();
|
||||||
|
ok(!chats.selectedChat, "chats are all closed");
|
||||||
|
setWorkerMode(false, next);
|
||||||
|
},
|
||||||
|
"chat window didn't close");
|
||||||
|
}, "chat windows did not open");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// XXX - note this must be the last test until we restore the login state
|
// XXX - note this must be the last test until we restore the login state
|
||||||
// between tests...
|
// between tests...
|
||||||
testCloseOnLogout: function(next) {
|
testCloseOnLogout: function(next) {
|
||||||
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
const chatUrl = Social.provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
let port = Social.provider.getWorkerPort();
|
let port = Social.provider.getWorkerPort();
|
||||||
ok(port, "provider has a port");
|
ok(port, "provider has a port");
|
||||||
let opened = false;
|
let opened = false;
|
||||||
|
101
browser/base/content/test/social/browser_social_multiworker.js
Normal file
101
browser/base/content/test/social/browser_social_multiworker.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
|
||||||
|
runSocialTestWithProvider(gProviders, function (finishcb) {
|
||||||
|
runSocialTests(tests, undefined, undefined, function() {
|
||||||
|
Services.prefs.clearUserPref("social.allowMultipleWorkers");
|
||||||
|
finishcb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let gProviders = [
|
||||||
|
{
|
||||||
|
name: "provider 1",
|
||||||
|
origin: "https://example.com",
|
||||||
|
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html?provider1",
|
||||||
|
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||||
|
iconURL: "chrome://branding/content/icon48.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "provider 2",
|
||||||
|
origin: "https://test1.example.com",
|
||||||
|
sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html?provider2",
|
||||||
|
workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||||
|
iconURL: "chrome://branding/content/icon48.png"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var tests = {
|
||||||
|
testWorkersAlive: function(next) {
|
||||||
|
// verify we can get a message from all providers that are enabled
|
||||||
|
let messageReceived = 0;
|
||||||
|
function oneWorkerTest(provider) {
|
||||||
|
let port = provider.getWorkerPort();
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "test-init-done":
|
||||||
|
ok(true, "got message from provider " + provider.name);
|
||||||
|
port.close();
|
||||||
|
messageReceived++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let p of Social.providers) {
|
||||||
|
oneWorkerTest(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForCondition(function() messageReceived == Social.providers.length,
|
||||||
|
next, "received messages from all workers");
|
||||||
|
},
|
||||||
|
testWorkerDisabling: function(next) {
|
||||||
|
Social.enabled = false;
|
||||||
|
is(Social.providers.length, gProviders.length, "providers still available");
|
||||||
|
for (let p of Social.providers) {
|
||||||
|
ok(!p.enabled, "provider disabled");
|
||||||
|
ok(!p.getWorkerPort(), "worker disabled");
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
testSingleWorkerEnabling: function(next) {
|
||||||
|
// test that only one worker is enabled when we limit workers
|
||||||
|
Services.prefs.setBoolPref("social.allowMultipleWorkers", false);
|
||||||
|
Social.enabled = true;
|
||||||
|
for (let p of Social.providers) {
|
||||||
|
if (p == Social.provider) {
|
||||||
|
ok(p.enabled, "primary provider enabled");
|
||||||
|
let port = p.getWorkerPort();
|
||||||
|
ok(port, "primary worker enabled");
|
||||||
|
port.close();
|
||||||
|
} else {
|
||||||
|
ok(!p.enabled, "secondary provider is not enabled");
|
||||||
|
ok(!p.getWorkerPort(), "secondary worker disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
testMultipleWorkerEnabling: function(next) {
|
||||||
|
// test that all workers are enabled when we allow multiple workers
|
||||||
|
Social.enabled = false;
|
||||||
|
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
|
||||||
|
Social.enabled = true;
|
||||||
|
for (let p of Social.providers) {
|
||||||
|
ok(p.enabled, "provider enabled");
|
||||||
|
let port = p.getWorkerPort();
|
||||||
|
ok(port, "worker enabled");
|
||||||
|
port.close();
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
@ -417,8 +417,8 @@ function get3ChatsForCollapsing(mode, cb) {
|
|||||||
|
|
||||||
function makeChat(mode, uniqueid, cb) {
|
function makeChat(mode, uniqueid, cb) {
|
||||||
info("making a chat window '" + uniqueid +"'");
|
info("making a chat window '" + uniqueid +"'");
|
||||||
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
|
||||||
let provider = Social.provider;
|
let provider = Social.provider;
|
||||||
|
const chatUrl = provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
let isOpened = window.SocialChatBar.openChat(provider, chatUrl + "?id=" + uniqueid, function(chat) {
|
let isOpened = window.SocialChatBar.openChat(provider, chatUrl + "?id=" + uniqueid, function(chat) {
|
||||||
info("chat window has opened");
|
info("chat window has opened");
|
||||||
// we can't callback immediately or we might close the chat during
|
// we can't callback immediately or we might close the chat during
|
||||||
|
@ -61,20 +61,20 @@ NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
|
static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
|
||||||
{ &kNS_BROWSERDIRECTORYPROVIDER_CID, false, NULL, DirectoryProviderConstructor },
|
{ &kNS_BROWSERDIRECTORYPROVIDER_CID, false, nullptr, DirectoryProviderConstructor },
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
{ &kNS_SHELLSERVICE_CID, false, NULL, nsWindowsShellServiceConstructor },
|
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsWindowsShellServiceConstructor },
|
||||||
#elif defined(MOZ_WIDGET_GTK)
|
#elif defined(MOZ_WIDGET_GTK)
|
||||||
{ &kNS_SHELLSERVICE_CID, false, NULL, nsGNOMEShellServiceConstructor },
|
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsGNOMEShellServiceConstructor },
|
||||||
#endif
|
#endif
|
||||||
{ &kNS_FEEDSNIFFER_CID, false, NULL, nsFeedSnifferConstructor },
|
{ &kNS_FEEDSNIFFER_CID, false, nullptr, nsFeedSnifferConstructor },
|
||||||
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, NULL, AboutRedirector::Create },
|
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, NULL, nsIEHistoryEnumeratorConstructor },
|
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
|
||||||
#elif defined(XP_MACOSX)
|
#elif defined(XP_MACOSX)
|
||||||
{ &kNS_SHELLSERVICE_CID, false, NULL, nsMacShellServiceConstructor },
|
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
|
||||||
#endif
|
#endif
|
||||||
{ NULL }
|
{ nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
||||||
@ -113,13 +113,13 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
|||||||
#elif defined(XP_MACOSX)
|
#elif defined(XP_MACOSX)
|
||||||
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
|
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
|
||||||
#endif
|
#endif
|
||||||
{ NULL }
|
{ nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const mozilla::Module::CategoryEntry kBrowserCategories[] = {
|
static const mozilla::Module::CategoryEntry kBrowserCategories[] = {
|
||||||
{ XPCOM_DIRECTORY_PROVIDER_CATEGORY, "browser-directory-provider", NS_BROWSERDIRECTORYPROVIDER_CONTRACTID },
|
{ XPCOM_DIRECTORY_PROVIDER_CATEGORY, "browser-directory-provider", NS_BROWSERDIRECTORYPROVIDER_CONTRACTID },
|
||||||
{ NS_CONTENT_SNIFFER_CATEGORY, "Feed Sniffer", NS_FEEDSNIFFER_CONTRACTID },
|
{ NS_CONTENT_SNIFFER_CATEGORY, "Feed Sniffer", NS_FEEDSNIFFER_CONTRACTID },
|
||||||
{ NULL }
|
{ nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const mozilla::Module kBrowserModule = {
|
static const mozilla::Module kBrowserModule = {
|
||||||
|
@ -7,39 +7,33 @@
|
|||||||
* Make sure the downloads panel can display items in the right order and
|
* Make sure the downloads panel can display items in the right order and
|
||||||
* contains the expected data.
|
* contains the expected data.
|
||||||
*/
|
*/
|
||||||
function gen_test()
|
function test_task()
|
||||||
{
|
{
|
||||||
// Display one of each download state.
|
// Display one of each download state.
|
||||||
const DownloadData = [
|
const DownloadData = [
|
||||||
{ endTime: 1180493839859239, state: nsIDM.DOWNLOAD_NOTSTARTED },
|
{ state: nsIDM.DOWNLOAD_NOTSTARTED },
|
||||||
{ endTime: 1180493839859238, state: nsIDM.DOWNLOAD_DOWNLOADING },
|
{ state: nsIDM.DOWNLOAD_PAUSED },
|
||||||
{ endTime: 1180493839859237, state: nsIDM.DOWNLOAD_PAUSED },
|
{ state: nsIDM.DOWNLOAD_FINISHED },
|
||||||
{ endTime: 1180493839859236, state: nsIDM.DOWNLOAD_SCANNING },
|
{ state: nsIDM.DOWNLOAD_FAILED },
|
||||||
{ endTime: 1180493839859235, state: nsIDM.DOWNLOAD_QUEUED },
|
{ state: nsIDM.DOWNLOAD_CANCELED },
|
||||||
{ endTime: 1180493839859234, state: nsIDM.DOWNLOAD_FINISHED },
|
|
||||||
{ endTime: 1180493839859233, state: nsIDM.DOWNLOAD_FAILED },
|
|
||||||
{ endTime: 1180493839859232, state: nsIDM.DOWNLOAD_CANCELED },
|
|
||||||
{ endTime: 1180493839859231, state: nsIDM.DOWNLOAD_BLOCKED_PARENTAL },
|
|
||||||
{ endTime: 1180493839859230, state: nsIDM.DOWNLOAD_DIRTY },
|
|
||||||
{ endTime: 1180493839859229, state: nsIDM.DOWNLOAD_BLOCKED_POLICY },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// For testing purposes, show all the download items at once.
|
|
||||||
var originalCountLimit = DownloadsView.kItemCountLimit;
|
|
||||||
DownloadsView.kItemCountLimit = DownloadData.length;
|
|
||||||
registerCleanupFunction(function () {
|
|
||||||
DownloadsView.kItemCountLimit = originalCountLimit;
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Ensure that state is reset in case previous tests didn't finish.
|
// Ensure that state is reset in case previous tests didn't finish.
|
||||||
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
|
yield task_resetState();
|
||||||
|
|
||||||
|
// For testing purposes, show all the download items at once.
|
||||||
|
var originalCountLimit = DownloadsView.kItemCountLimit;
|
||||||
|
DownloadsView.kItemCountLimit = DownloadData.length;
|
||||||
|
registerCleanupFunction(function () {
|
||||||
|
DownloadsView.kItemCountLimit = originalCountLimit;
|
||||||
|
});
|
||||||
|
|
||||||
// Populate the downloads database with the data required by this test.
|
// Populate the downloads database with the data required by this test.
|
||||||
for (let yy in gen_addDownloadRows(DownloadData)) yield undefined;
|
yield task_addDownloads(DownloadData);
|
||||||
|
|
||||||
// Open the user interface and wait for data to be fully loaded.
|
// Open the user interface and wait for data to be fully loaded.
|
||||||
for (let yy in gen_openPanel(DownloadsCommon.getData(window))) yield undefined;
|
yield task_openPanel();
|
||||||
|
|
||||||
// Test item data and count. This also tests the ordering of the display.
|
// Test item data and count. This also tests the ordering of the display.
|
||||||
let richlistbox = document.getElementById("downloadsListBox");
|
let richlistbox = document.getElementById("downloadsListBox");
|
||||||
@ -47,16 +41,14 @@ function gen_test()
|
|||||||
is(richlistbox.children.length, DownloadData.length,
|
is(richlistbox.children.length, DownloadData.length,
|
||||||
"There is the correct number of richlistitems");
|
"There is the correct number of richlistitems");
|
||||||
*/
|
*/
|
||||||
for (let i = 0; i < richlistbox.children.length; i++) {
|
let itemCount = richlistbox.children.length;
|
||||||
let element = richlistbox.children[i];
|
for (let i = 0; i < itemCount; i++) {
|
||||||
|
let element = richlistbox.children[itemCount - i - 1];
|
||||||
let dataItem = new DownloadsViewItemController(element).dataItem;
|
let dataItem = new DownloadsViewItemController(element).dataItem;
|
||||||
is(dataItem.target, DownloadData[i].name, "Download names match up");
|
|
||||||
is(dataItem.state, DownloadData[i].state, "Download states match up");
|
is(dataItem.state, DownloadData[i].state, "Download states match up");
|
||||||
is(dataItem.file, DownloadData[i].target, "Download targets match up");
|
|
||||||
is(dataItem.uri, DownloadData[i].source, "Download sources match up");
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Clean up when the test finishes.
|
// Clean up when the test finishes.
|
||||||
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
|
yield task_resetState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,19 @@
|
|||||||
* download it notices. All subsequent downloads, even across sessions, should
|
* download it notices. All subsequent downloads, even across sessions, should
|
||||||
* not open the panel automatically.
|
* not open the panel automatically.
|
||||||
*/
|
*/
|
||||||
function gen_test()
|
function test_task()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Ensure that state is reset in case previous tests didn't finish.
|
// Ensure that state is reset in case previous tests didn't finish.
|
||||||
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
|
yield task_resetState();
|
||||||
|
|
||||||
// With this set to false, we should automatically open the panel
|
// With this set to false, we should automatically open the panel the first
|
||||||
// the first time a download is started.
|
// time a download is started.
|
||||||
DownloadsCommon.getData(window).panelHasShownBefore = false;
|
DownloadsCommon.getData(window).panelHasShownBefore = false;
|
||||||
|
|
||||||
prepareForPanelOpen();
|
let promise = promisePanelOpened();
|
||||||
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
||||||
yield undefined;
|
yield promise;
|
||||||
|
|
||||||
// If we got here, that means the panel opened.
|
// If we got here, that means the panel opened.
|
||||||
DownloadsPanel.hidePanel();
|
DownloadsPanel.hidePanel();
|
||||||
@ -28,29 +28,26 @@ function gen_test()
|
|||||||
ok(DownloadsCommon.getData(window).panelHasShownBefore,
|
ok(DownloadsCommon.getData(window).panelHasShownBefore,
|
||||||
"Should have recorded that the panel was opened on a download.")
|
"Should have recorded that the panel was opened on a download.")
|
||||||
|
|
||||||
// Next, make sure that if we start another download, we don't open
|
// Next, make sure that if we start another download, we don't open the
|
||||||
// the panel automatically.
|
// panel automatically.
|
||||||
panelShouldNotOpen();
|
let originalOnPopupShown = DownloadsPanel.onPopupShown;
|
||||||
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
DownloadsPanel.onPopupShown = function () {
|
||||||
yield waitFor(2);
|
originalOnPopupShown.apply(this, arguments);
|
||||||
} catch(e) {
|
ok(false, "Should not have opened the downloads panel.");
|
||||||
ok(false, e);
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
DownloadsCommon.getData(window)._notifyDownloadEvent("start");
|
||||||
|
|
||||||
|
// Wait 2 seconds to ensure that the panel does not open.
|
||||||
|
let deferTimeout = Promise.defer();
|
||||||
|
setTimeout(deferTimeout.resolve, 2000);
|
||||||
|
yield deferTimeout.promise;
|
||||||
|
} finally {
|
||||||
|
DownloadsPanel.onPopupShown = originalOnPopupShown;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Clean up when the test finishes.
|
// Clean up when the test finishes.
|
||||||
for (let yy in gen_resetState(DownloadsCommon.getData(window))) yield undefined;
|
yield task_resetState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this to record a test failure for the next time the downloads panel
|
|
||||||
* opens.
|
|
||||||
*/
|
|
||||||
function panelShouldNotOpen()
|
|
||||||
{
|
|
||||||
// Hook to wait until the test data has been loaded.
|
|
||||||
let originalOnViewLoadCompleted = DownloadsPanel.onViewLoadCompleted;
|
|
||||||
DownloadsPanel.onViewLoadCompleted = function () {
|
|
||||||
DownloadsPanel.onViewLoadCompleted = originalOnViewLoadCompleted;
|
|
||||||
ok(false, "Should not have opened the downloads panel.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@ -10,10 +10,16 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Globals
|
//// Globals
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||||
"resource://gre/modules/FileUtils.jsm");
|
"resource://gre/modules/Downloads.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||||
"resource:///modules/DownloadsCommon.jsm");
|
"resource:///modules/DownloadsCommon.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||||
|
"resource://gre/modules/FileUtils.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||||
|
"resource://gre/modules/Promise.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||||
|
"resource://gre/modules/Task.jsm");
|
||||||
const nsIDM = Ci.nsIDownloadManager;
|
const nsIDM = Ci.nsIDownloadManager;
|
||||||
|
|
||||||
let gTestTargetFile = FileUtils.getFile("TmpD", ["dm-ui-test.file"]);
|
let gTestTargetFile = FileUtils.getFile("TmpD", ["dm-ui-test.file"]);
|
||||||
@ -22,253 +28,85 @@ registerCleanupFunction(function () {
|
|||||||
gTestTargetFile.remove(false);
|
gTestTargetFile.remove(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* This objects contains a property for each column in the downloads table.
|
|
||||||
*/
|
|
||||||
let gDownloadRowTemplate = {
|
|
||||||
name: "test-download.txt",
|
|
||||||
source: "http://www.example.com/test-download.txt",
|
|
||||||
target: NetUtil.newURI(gTestTargetFile).spec,
|
|
||||||
startTime: 1180493839859230,
|
|
||||||
endTime: 1180493839859234,
|
|
||||||
state: nsIDM.DOWNLOAD_FINISHED,
|
|
||||||
currBytes: 0,
|
|
||||||
maxBytes: -1,
|
|
||||||
preferredAction: 0,
|
|
||||||
autoResume: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Infrastructure
|
//// Infrastructure
|
||||||
|
|
||||||
// All test are run through the test runner.
|
|
||||||
function test()
|
function test()
|
||||||
{
|
{
|
||||||
testRunner.runTest(this.gen_test);
|
waitForExplicitFinish();
|
||||||
|
Task.spawn(test_task).then(null, ex => ok(false, ex)).then(finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs a browser-chrome test defined through a generator function.
|
|
||||||
*
|
|
||||||
* This object is a singleton, initialized automatically when this script is
|
|
||||||
* included. Every browser-chrome test file includes a new copy of this object.
|
|
||||||
*/
|
|
||||||
var testRunner = {
|
|
||||||
_testIterator: null,
|
|
||||||
_lastEventResult: undefined,
|
|
||||||
_testRunning: false,
|
|
||||||
_eventRaised: false,
|
|
||||||
|
|
||||||
// --- Main test runner ---
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the test described by the provided generator function asynchronously.
|
|
||||||
*
|
|
||||||
* Calling yield in the generator will cause it to wait until continueTest is
|
|
||||||
* called. The parameter provided to continueTest will be the return value of
|
|
||||||
* the yield operator.
|
|
||||||
*
|
|
||||||
* @param aGenerator
|
|
||||||
* Test generator function. The function will be called with no
|
|
||||||
* arguments to retrieve its iterator.
|
|
||||||
*/
|
|
||||||
runTest: function TR_runTest(aGenerator) {
|
|
||||||
waitForExplicitFinish();
|
|
||||||
testRunner._testIterator = aGenerator();
|
|
||||||
testRunner.continueTest();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Continues the currently running test.
|
|
||||||
*
|
|
||||||
* @param aEventResult
|
|
||||||
* This will be the return value of the yield operator in the test.
|
|
||||||
*/
|
|
||||||
continueTest: function TR_continueTest(aEventResult) {
|
|
||||||
// Store the last event result, or set it to undefined.
|
|
||||||
testRunner._lastEventResult = aEventResult;
|
|
||||||
|
|
||||||
// Never reenter the main loop, but notify that the event has been raised.
|
|
||||||
if (testRunner._testRunning) {
|
|
||||||
testRunner._eventRaised = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enter the main iteration loop.
|
|
||||||
testRunner._testRunning = true;
|
|
||||||
try {
|
|
||||||
do {
|
|
||||||
// Call the iterator, but don't leave the loop if the expected event is
|
|
||||||
// raised during the execution of the generator.
|
|
||||||
testRunner._eventRaised = false;
|
|
||||||
testRunner._testIterator.send(testRunner._lastEventResult);
|
|
||||||
} while (testRunner._eventRaised);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
// This block catches exceptions raised by the generator, including the
|
|
||||||
// normal StopIteration exception. Unexpected exceptions are reported as
|
|
||||||
// test failures.
|
|
||||||
if (!(e instanceof StopIteration))
|
|
||||||
ok(false, e);
|
|
||||||
// In any case, stop the tests in this file.
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the next event or finish.
|
|
||||||
testRunner._testRunning = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Asynchronous generator-based support subroutines
|
//// Asynchronous support subroutines
|
||||||
|
|
||||||
//
|
function promiseFocus()
|
||||||
// The following functions are all generators that can be used inside the main
|
|
||||||
// test generator to perform specific tasks asynchronously. To invoke these
|
|
||||||
// subroutines correctly, an iteration syntax should be used:
|
|
||||||
//
|
|
||||||
// for (let yy in gen_example("Parameter")) yield undefined;
|
|
||||||
//
|
|
||||||
|
|
||||||
function gen_resetState(aData)
|
|
||||||
{
|
{
|
||||||
let statement = Services.downloads.DBConnection.createAsyncStatement(
|
let deferred = Promise.defer();
|
||||||
"DELETE FROM moz_downloads");
|
waitForFocus(deferred.resolve);
|
||||||
try {
|
return deferred.promise;
|
||||||
statement.executeAsync({
|
}
|
||||||
handleResult: function(aResultSet) { },
|
|
||||||
handleError: function(aError)
|
function promisePanelOpened()
|
||||||
{
|
{
|
||||||
Cu.reportError(aError);
|
let deferred = Promise.defer();
|
||||||
},
|
|
||||||
handleCompletion: function(aReason)
|
// Hook to wait until the panel is shown.
|
||||||
{
|
let originalOnPopupShown = DownloadsPanel.onPopupShown;
|
||||||
testRunner.continueTest();
|
DownloadsPanel.onPopupShown = function () {
|
||||||
}
|
DownloadsPanel.onPopupShown = originalOnPopupShown;
|
||||||
});
|
originalOnPopupShown.apply(this, arguments);
|
||||||
yield undefined;
|
|
||||||
} finally {
|
// Defer to the next tick of the event loop so that we don't continue
|
||||||
statement.finalize();
|
// processing during the DOM event handler itself.
|
||||||
|
setTimeout(deferred.resolve, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function task_resetState()
|
||||||
|
{
|
||||||
|
// Remove all downloads.
|
||||||
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
|
let downloads = yield publicList.getAll();
|
||||||
|
for (let download of downloads) {
|
||||||
|
publicList.remove(download);
|
||||||
|
yield download.finalize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset any prefs that might have been changed.
|
// Reset any prefs that might have been changed.
|
||||||
Services.prefs.clearUserPref("browser.download.panel.shown");
|
Services.prefs.clearUserPref("browser.download.panel.shown");
|
||||||
|
|
||||||
// Ensure that the panel is closed and data is unloaded.
|
|
||||||
aData.clear();
|
|
||||||
aData._loadState = aData.kLoadNone;
|
|
||||||
DownloadsPanel.hidePanel();
|
DownloadsPanel.hidePanel();
|
||||||
|
|
||||||
// Wait for focus on the main window.
|
yield promiseFocus();
|
||||||
waitForFocus(testRunner.continueTest);
|
|
||||||
yield undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function gen_addDownloadRows(aDataRows)
|
function task_addDownloads(aItems)
|
||||||
{
|
{
|
||||||
let columnNames = Object.keys(gDownloadRowTemplate).join(", ");
|
let startTimeMs = Date.now();
|
||||||
let parameterNames = Object.keys(gDownloadRowTemplate)
|
|
||||||
.map(function(n) ":" + n)
|
|
||||||
.join(", ");
|
|
||||||
let statement = Services.downloads.DBConnection.createAsyncStatement(
|
|
||||||
"INSERT INTO moz_downloads (" + columnNames +
|
|
||||||
", guid) VALUES(" + parameterNames + ", GENERATE_GUID())");
|
|
||||||
try {
|
|
||||||
// Execute the statement for each of the provided downloads in reverse.
|
|
||||||
for (let i = aDataRows.length - 1; i >= 0; i--) {
|
|
||||||
let dataRow = aDataRows[i];
|
|
||||||
|
|
||||||
// Populate insert parameters from the provided data.
|
let publicList = yield Downloads.getPublicDownloadList();
|
||||||
for (let columnName in gDownloadRowTemplate) {
|
for (let item of aItems) {
|
||||||
if (!(columnName in dataRow)) {
|
publicList.add(yield Downloads.createDownload({
|
||||||
// Update the provided row object with data from the global template,
|
source: "http://www.example.com/test-download.txt",
|
||||||
// for columns whose value is not provided explicitly.
|
target: gTestTargetFile,
|
||||||
dataRow[columnName] = gDownloadRowTemplate[columnName];
|
succeeded: item.state == nsIDM.DOWNLOAD_FINISHED,
|
||||||
}
|
canceled: item.state == nsIDM.DOWNLOAD_CANCELED ||
|
||||||
statement.params[columnName] = dataRow[columnName];
|
item.state == nsIDM.DOWNLOAD_PAUSED,
|
||||||
}
|
error: item.state == nsIDM.DOWNLOAD_FAILED ? new Error("Failed.") : null,
|
||||||
|
hasPartialData: item.state == nsIDM.DOWNLOAD_PAUSED,
|
||||||
// Run the statement asynchronously and wait.
|
startTime: new Date(startTimeMs++),
|
||||||
statement.executeAsync({
|
}));
|
||||||
handleResult: function(aResultSet) { },
|
|
||||||
handleError: function(aError)
|
|
||||||
{
|
|
||||||
Cu.reportError(aError.message + " (Result = " + aError.result + ")");
|
|
||||||
},
|
|
||||||
handleCompletion: function(aReason)
|
|
||||||
{
|
|
||||||
testRunner.continueTest();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
yield undefined;
|
|
||||||
|
|
||||||
// At each iteration, ensure that the start and end time in the global
|
|
||||||
// template is distinct, as these column are used to sort each download
|
|
||||||
// in its category.
|
|
||||||
gDownloadRowTemplate.startTime++;
|
|
||||||
gDownloadRowTemplate.endTime++;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
statement.finalize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function gen_openPanel(aData)
|
function task_openPanel()
|
||||||
{
|
{
|
||||||
// Hook to wait until the test data has been loaded.
|
yield promiseFocus();
|
||||||
let originalOnViewLoadCompleted = DownloadsPanel.onViewLoadCompleted;
|
|
||||||
DownloadsPanel.onViewLoadCompleted = function () {
|
|
||||||
DownloadsPanel.onViewLoadCompleted = originalOnViewLoadCompleted;
|
|
||||||
originalOnViewLoadCompleted.apply(this);
|
|
||||||
testRunner.continueTest();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Start loading all the downloads from the database asynchronously.
|
let promise = promisePanelOpened();
|
||||||
aData.ensurePersistentDataLoaded(false);
|
|
||||||
|
|
||||||
// Wait for focus on the main window.
|
|
||||||
waitForFocus(testRunner.continueTest);
|
|
||||||
yield undefined;
|
|
||||||
|
|
||||||
// Open the downloads panel, waiting until loading is completed.
|
|
||||||
DownloadsPanel.showPanel();
|
DownloadsPanel.showPanel();
|
||||||
yield undefined;
|
yield promise;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spin the event loop for aSeconds seconds, and then signal the test to
|
|
||||||
* continue.
|
|
||||||
*
|
|
||||||
* @param aSeconds the number of seconds to wait.
|
|
||||||
* @note This helper should _only_ be used when there's no valid event to
|
|
||||||
* listen to and one can't be made.
|
|
||||||
*/
|
|
||||||
function waitFor(aSeconds)
|
|
||||||
{
|
|
||||||
setTimeout(function() {
|
|
||||||
testRunner.continueTest();
|
|
||||||
}, aSeconds * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make it so that the next time the downloads panel opens, we signal to
|
|
||||||
* continue the test. This function needs to be called each time you want
|
|
||||||
* to wait for the panel to open.
|
|
||||||
*
|
|
||||||
* Example usage:
|
|
||||||
*
|
|
||||||
* prepareForPanelOpen();
|
|
||||||
* // Do something to open the panel
|
|
||||||
* yield undefined;
|
|
||||||
* // We can assume the panel is open now.
|
|
||||||
*/
|
|
||||||
function prepareForPanelOpen()
|
|
||||||
{
|
|
||||||
// Hook to wait until the test data has been loaded.
|
|
||||||
let originalOnPopupShown = DownloadsPanel.onPopupShown;
|
|
||||||
DownloadsPanel.onPopupShown = function (aEvent) {
|
|
||||||
DownloadsPanel.onPopupShown = originalOnPopupShown;
|
|
||||||
DownloadsPanel.onPopupShown.apply(this, [aEvent]);
|
|
||||||
testRunner.continueTest();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ NS_IMPL_ISUPPORTS1(nsIEHistoryEnumerator, nsISimpleEnumerator)
|
|||||||
|
|
||||||
nsIEHistoryEnumerator::nsIEHistoryEnumerator()
|
nsIEHistoryEnumerator::nsIEHistoryEnumerator()
|
||||||
{
|
{
|
||||||
::CoInitialize(NULL);
|
::CoInitialize(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
|
nsIEHistoryEnumerator::~nsIEHistoryEnumerator()
|
||||||
@ -60,7 +60,7 @@ nsIEHistoryEnumerator::EnsureInitialized()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
|
HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
|
||||||
NULL,
|
nullptr,
|
||||||
CLSCTX_INPROC_SERVER,
|
CLSCTX_INPROC_SERVER,
|
||||||
IID_IUrlHistoryStg2,
|
IID_IUrlHistoryStg2,
|
||||||
getter_AddRefs(mIEHistory));
|
getter_AddRefs(mIEHistory));
|
||||||
|
@ -262,6 +262,12 @@ let SessionSaverInternal = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We update the time stamp before writing so that we don't write again
|
||||||
|
// too soon, if saving is requested before the write completes. Without
|
||||||
|
// this update we may save repeatedly if actions cause a runDelayed
|
||||||
|
// before writing has completed. See Bug 902280
|
||||||
|
this.updateLastSaveTime();
|
||||||
|
|
||||||
// Write (atomically) to a session file, using a tmp file. Once the session
|
// Write (atomically) to a session file, using a tmp file. Once the session
|
||||||
// file is successfully updated, save the time stamp of the last save and
|
// file is successfully updated, save the time stamp of the last save and
|
||||||
// notify the observers.
|
// notify the observers.
|
||||||
|
@ -75,7 +75,7 @@ this._SessionFile = {
|
|||||||
* state. This must only be called once, it will throw an error otherwise.
|
* state. This must only be called once, it will throw an error otherwise.
|
||||||
*/
|
*/
|
||||||
writeLoadStateOnceAfterStartup: function (aLoadState) {
|
writeLoadStateOnceAfterStartup: function (aLoadState) {
|
||||||
return SessionFileInternal.writeLoadStateOnceAfterStartup(aLoadState);
|
SessionFileInternal.writeLoadStateOnceAfterStartup(aLoadState);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Create a backup copy, asynchronously.
|
* Create a backup copy, asynchronously.
|
||||||
@ -95,7 +95,7 @@ this._SessionFile = {
|
|||||||
* Wipe the contents of the session file, asynchronously.
|
* Wipe the contents of the session file, asynchronously.
|
||||||
*/
|
*/
|
||||||
wipe: function () {
|
wipe: function () {
|
||||||
return SessionFileInternal.wipe();
|
SessionFileInternal.wipe();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ let SessionFileInternal = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
writeLoadStateOnceAfterStartup: function (aLoadState) {
|
writeLoadStateOnceAfterStartup: function (aLoadState) {
|
||||||
return SessionWorker.post("writeLoadStateOnceAfterStartup", [aLoadState]).then(msg => {
|
SessionWorker.post("writeLoadStateOnceAfterStartup", [aLoadState]).then(msg => {
|
||||||
this._recordTelemetry(msg.telemetry);
|
this._recordTelemetry(msg.telemetry);
|
||||||
return msg;
|
return msg;
|
||||||
});
|
});
|
||||||
@ -246,7 +246,7 @@ let SessionFileInternal = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
wipe: function () {
|
wipe: function () {
|
||||||
return SessionWorker.post("wipe");
|
SessionWorker.post("wipe");
|
||||||
},
|
},
|
||||||
|
|
||||||
_recordTelemetry: function(telemetry) {
|
_recordTelemetry: function(telemetry) {
|
||||||
|
@ -152,7 +152,8 @@ nsGNOMEShellService::KeyMatchesAppName(const char *aKeyValue) const
|
|||||||
|
|
||||||
gchar *commandPath;
|
gchar *commandPath;
|
||||||
if (mUseLocaleFilenames) {
|
if (mUseLocaleFilenames) {
|
||||||
gchar *nativePath = g_filename_from_utf8(aKeyValue, -1, NULL, NULL, NULL);
|
gchar *nativePath = g_filename_from_utf8(aKeyValue, -1,
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
if (!nativePath) {
|
if (!nativePath) {
|
||||||
NS_ERROR("Error converting path to filesystem encoding");
|
NS_ERROR("Error converting path to filesystem encoding");
|
||||||
return false;
|
return false;
|
||||||
@ -182,7 +183,7 @@ nsGNOMEShellService::CheckHandlerMatchesAppName(const nsACString &handler) const
|
|||||||
// The string will be something of the form: [/path/to/]browser "%s"
|
// The string will be something of the form: [/path/to/]browser "%s"
|
||||||
// We want to remove all of the parameters and get just the binary name.
|
// We want to remove all of the parameters and get just the binary name.
|
||||||
|
|
||||||
if (g_shell_parse_argv(command.get(), &argc, &argv, NULL) && argc > 0) {
|
if (g_shell_parse_argv(command.get(), &argc, &argv, nullptr) && argc > 0) {
|
||||||
command.Assign(argv[0]);
|
command.Assign(argv[0]);
|
||||||
g_strfreev(argv);
|
g_strfreev(argv);
|
||||||
}
|
}
|
||||||
@ -380,7 +381,7 @@ WriteImage(const nsCString& aPath, imgIContainer* aImage)
|
|||||||
if (!pixbuf)
|
if (!pixbuf)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", NULL, NULL);
|
gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", nullptr, nullptr);
|
||||||
|
|
||||||
g_object_unref(pixbuf);
|
g_object_unref(pixbuf);
|
||||||
return res ? NS_OK : NS_ERROR_FAILURE;
|
return res ? NS_OK : NS_ERROR_FAILURE;
|
||||||
@ -454,7 +455,7 @@ nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement,
|
|||||||
gsettings->GetCollectionForSchema(
|
gsettings->GetCollectionForSchema(
|
||||||
NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings));
|
NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings));
|
||||||
if (background_settings) {
|
if (background_settings) {
|
||||||
gchar *file_uri = g_filename_to_uri(filePath.get(), NULL, NULL);
|
gchar *file_uri = g_filename_to_uri(filePath.get(), nullptr, nullptr);
|
||||||
if (!file_uri)
|
if (!file_uri)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
@ -615,7 +616,7 @@ nsGNOMEShellService::OpenApplication(int32_t aApplication)
|
|||||||
// Perform shell argument expansion
|
// Perform shell argument expansion
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
if (!g_shell_parse_argv(appCommand.get(), &argc, &argv, NULL))
|
if (!g_shell_parse_argv(appCommand.get(), &argc, &argv, nullptr))
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
char **newArgv = new char*[argc + 1];
|
char **newArgv = new char*[argc + 1];
|
||||||
@ -630,8 +631,8 @@ nsGNOMEShellService::OpenApplication(int32_t aApplication)
|
|||||||
|
|
||||||
newArgv[newArgc] = nullptr;
|
newArgv[newArgc] = nullptr;
|
||||||
|
|
||||||
gboolean err = g_spawn_async(NULL, newArgv, NULL, G_SPAWN_SEARCH_PATH,
|
gboolean err = g_spawn_async(nullptr, newArgv, nullptr, G_SPAWN_SEARCH_PATH,
|
||||||
NULL, NULL, NULL, NULL);
|
nullptr, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
g_strfreev(argv);
|
g_strfreev(argv);
|
||||||
delete[] newArgv;
|
delete[] newArgv;
|
||||||
|
@ -40,13 +40,14 @@ nsMacShellService::IsDefaultBrowser(bool aStartupCheck,
|
|||||||
|
|
||||||
CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
|
CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
|
||||||
if (!firefoxID) {
|
if (!firefoxID) {
|
||||||
// CFBundleGetIdentifier is expected to return NULL only if the specified
|
// CFBundleGetIdentifier is expected to return nullptr only if the specified
|
||||||
// bundle doesn't have a bundle identifier in its plist. In this case, that
|
// bundle doesn't have a bundle identifier in its plist. In this case, that
|
||||||
// means a failure, since our bundle does have an identifier.
|
// means a failure, since our bundle does have an identifier.
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the default http handler's bundle ID (or NULL if it has not been explicitly set)
|
// Get the default http handler's bundle ID (or nullptr if it has not been
|
||||||
|
// explicitly set)
|
||||||
CFStringRef defaultBrowserID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("http"));
|
CFStringRef defaultBrowserID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("http"));
|
||||||
if (defaultBrowserID) {
|
if (defaultBrowserID) {
|
||||||
*aIsDefaultBrowser = ::CFStringCompare(firefoxID, defaultBrowserID, 0) == kCFCompareEqualTo;
|
*aIsDefaultBrowser = ::CFStringCompare(firefoxID, defaultBrowserID, 0) == kCFCompareEqualTo;
|
||||||
@ -259,7 +260,8 @@ nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
|
|||||||
OSStatus status;
|
OSStatus status;
|
||||||
|
|
||||||
// Convert the path into a FSRef
|
// Convert the path into a FSRef
|
||||||
status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef, NULL);
|
status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef,
|
||||||
|
nullptr);
|
||||||
if (status == noErr) {
|
if (status == noErr) {
|
||||||
err = ::FSNewAlias(nil, &pictureRef, &aliasHandle);
|
err = ::FSNewAlias(nil, &pictureRef, &aliasHandle);
|
||||||
if (err == noErr && aliasHandle == nil)
|
if (err == noErr && aliasHandle == nil)
|
||||||
@ -312,22 +314,22 @@ nsMacShellService::OpenApplication(int32_t aApplication)
|
|||||||
case nsIShellService::APPLICATION_MAIL:
|
case nsIShellService::APPLICATION_MAIL:
|
||||||
{
|
{
|
||||||
CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
|
CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
|
||||||
CFSTR("mailto:"), NULL);
|
CFSTR("mailto:"), nullptr);
|
||||||
err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, NULL, &appURL);
|
err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, nullptr, &appURL);
|
||||||
::CFRelease(tempURL);
|
::CFRelease(tempURL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case nsIShellService::APPLICATION_NEWS:
|
case nsIShellService::APPLICATION_NEWS:
|
||||||
{
|
{
|
||||||
CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
|
CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
|
||||||
CFSTR("news:"), NULL);
|
CFSTR("news:"), nullptr);
|
||||||
err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, NULL, &appURL);
|
err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, nullptr, &appURL);
|
||||||
::CFRelease(tempURL);
|
::CFRelease(tempURL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case nsIMacShellService::APPLICATION_KEYCHAIN_ACCESS:
|
case nsIMacShellService::APPLICATION_KEYCHAIN_ACCESS:
|
||||||
err = ::LSGetApplicationForInfo('APPL', 'kcmr', NULL, kLSRolesAll, NULL,
|
err = ::LSGetApplicationForInfo('APPL', 'kcmr', nullptr, kLSRolesAll,
|
||||||
&appURL);
|
nullptr, &appURL);
|
||||||
break;
|
break;
|
||||||
case nsIMacShellService::APPLICATION_NETWORK:
|
case nsIMacShellService::APPLICATION_NETWORK:
|
||||||
{
|
{
|
||||||
@ -356,7 +358,7 @@ nsMacShellService::OpenApplication(int32_t aApplication)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (appURL && err == noErr) {
|
if (appURL && err == noErr) {
|
||||||
err = ::LSOpenCFURLRef(appURL, NULL);
|
err = ::LSOpenCFURLRef(appURL, nullptr);
|
||||||
rv = err != noErr ? NS_ERROR_FAILURE : NS_OK;
|
rv = err != noErr ? NS_ERROR_FAILURE : NS_OK;
|
||||||
|
|
||||||
::CFRelease(appURL);
|
::CFRelease(appURL);
|
||||||
@ -394,12 +396,12 @@ nsMacShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACStrin
|
|||||||
|
|
||||||
const nsCString spec(aURI);
|
const nsCString spec(aURI);
|
||||||
const UInt8* uriString = (const UInt8*)spec.get();
|
const UInt8* uriString = (const UInt8*)spec.get();
|
||||||
CFURLRef uri = ::CFURLCreateWithBytes(NULL, uriString, aURI.Length(),
|
CFURLRef uri = ::CFURLCreateWithBytes(nullptr, uriString, aURI.Length(),
|
||||||
kCFStringEncodingUTF8, NULL);
|
kCFStringEncodingUTF8, nullptr);
|
||||||
if (!uri)
|
if (!uri)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
CFArrayRef uris = ::CFArrayCreate(NULL, (const void**)&uri, 1, NULL);
|
CFArrayRef uris = ::CFArrayCreate(nullptr, (const void**)&uri, 1, nullptr);
|
||||||
if (!uris) {
|
if (!uris) {
|
||||||
::CFRelease(uri);
|
::CFRelease(uri);
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
@ -408,11 +410,11 @@ nsMacShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACStrin
|
|||||||
LSLaunchURLSpec launchSpec;
|
LSLaunchURLSpec launchSpec;
|
||||||
launchSpec.appURL = appURL;
|
launchSpec.appURL = appURL;
|
||||||
launchSpec.itemURLs = uris;
|
launchSpec.itemURLs = uris;
|
||||||
launchSpec.passThruParams = NULL;
|
launchSpec.passThruParams = nullptr;
|
||||||
launchSpec.launchFlags = kLSLaunchDefaults;
|
launchSpec.launchFlags = kLSLaunchDefaults;
|
||||||
launchSpec.asyncRefCon = NULL;
|
launchSpec.asyncRefCon = nullptr;
|
||||||
|
|
||||||
OSErr err = ::LSOpenFromURLSpec(&launchSpec, NULL);
|
OSErr err = ::LSOpenFromURLSpec(&launchSpec, nullptr);
|
||||||
|
|
||||||
::CFRelease(uris);
|
::CFRelease(uris);
|
||||||
::CFRelease(uri);
|
::CFRelease(uri);
|
||||||
@ -433,11 +435,11 @@ nsMacShellService::GetDefaultFeedReader(nsIFile** _retval)
|
|||||||
kCFStringEncodingASCII);
|
kCFStringEncodingASCII);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFURLRef defaultHandlerURL = NULL;
|
CFURLRef defaultHandlerURL = nullptr;
|
||||||
OSStatus status = ::LSFindApplicationForInfo(kLSUnknownCreator,
|
OSStatus status = ::LSFindApplicationForInfo(kLSUnknownCreator,
|
||||||
defaultHandlerID,
|
defaultHandlerID,
|
||||||
NULL, // inName
|
nullptr, // inName
|
||||||
NULL, // outAppRef
|
nullptr, // outAppRef
|
||||||
&defaultHandlerURL);
|
&defaultHandlerURL);
|
||||||
|
|
||||||
if (status == noErr && defaultHandlerURL) {
|
if (status == noErr && defaultHandlerURL) {
|
||||||
|
@ -223,8 +223,8 @@ LaunchHelper(nsAutoString& aPath)
|
|||||||
STARTUPINFOW si = {sizeof(si), 0};
|
STARTUPINFOW si = {sizeof(si), 0};
|
||||||
PROCESS_INFORMATION pi = {0};
|
PROCESS_INFORMATION pi = {0};
|
||||||
|
|
||||||
if (!CreateProcessW(NULL, (LPWSTR)aPath.get(), NULL, NULL, FALSE, 0, NULL,
|
if (!CreateProcessW(nullptr, (LPWSTR)aPath.get(), nullptr, nullptr, FALSE,
|
||||||
NULL, &si, &pi)) {
|
0, nullptr, nullptr, &si, &pi)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +361,7 @@ nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes,
|
|||||||
{
|
{
|
||||||
IApplicationAssociationRegistration* pAAR;
|
IApplicationAssociationRegistration* pAAR;
|
||||||
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
||||||
NULL,
|
nullptr,
|
||||||
CLSCTX_INPROC,
|
CLSCTX_INPROC,
|
||||||
IID_IApplicationAssociationRegistration,
|
IID_IApplicationAssociationRegistration,
|
||||||
(void**)&pAAR);
|
(void**)&pAAR);
|
||||||
@ -447,7 +447,8 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
|
|||||||
|
|
||||||
::ZeroMemory(currValue, sizeof(currValue));
|
::ZeroMemory(currValue, sizeof(currValue));
|
||||||
DWORD len = sizeof currValue;
|
DWORD len = sizeof currValue;
|
||||||
res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue, &len);
|
res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
|
||||||
|
(LPBYTE)currValue, &len);
|
||||||
// Close the key that was opened.
|
// Close the key that was opened.
|
||||||
::RegCloseKey(theKey);
|
::RegCloseKey(theKey);
|
||||||
if (REG_FAILED(res) ||
|
if (REG_FAILED(res) ||
|
||||||
@ -516,8 +517,8 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
|
|||||||
|
|
||||||
::ZeroMemory(currValue, sizeof(currValue));
|
::ZeroMemory(currValue, sizeof(currValue));
|
||||||
DWORD len = sizeof currValue;
|
DWORD len = sizeof currValue;
|
||||||
res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue,
|
res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
|
||||||
&len);
|
(LPBYTE)currValue, &len);
|
||||||
// Close the key that was opened.
|
// Close the key that was opened.
|
||||||
::RegCloseKey(theKey);
|
::RegCloseKey(theKey);
|
||||||
if (REG_FAILED(res) || PRUnichar('\0') != *currValue) {
|
if (REG_FAILED(res) || PRUnichar('\0') != *currValue) {
|
||||||
@ -525,9 +526,9 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
|
|||||||
// Delete the key along with all of its childrean and then recreate it.
|
// Delete the key along with all of its childrean and then recreate it.
|
||||||
const nsString &flatName = PromiseFlatString(keyName);
|
const nsString &flatName = PromiseFlatString(keyName);
|
||||||
::SHDeleteKeyW(HKEY_CURRENT_USER, flatName.get());
|
::SHDeleteKeyW(HKEY_CURRENT_USER, flatName.get());
|
||||||
res = ::RegCreateKeyExW(HKEY_CURRENT_USER, flatName.get(), 0, NULL,
|
res = ::RegCreateKeyExW(HKEY_CURRENT_USER, flatName.get(), 0, nullptr,
|
||||||
REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL,
|
REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
|
||||||
&theKey, NULL);
|
nullptr, &theKey, nullptr);
|
||||||
if (REG_FAILED(res)) {
|
if (REG_FAILED(res)) {
|
||||||
// If disabling DDE fails try to disable it using the helper
|
// If disabling DDE fails try to disable it using the helper
|
||||||
// application when setting Firefox as the default browser.
|
// application when setting Firefox as the default browser.
|
||||||
@ -564,7 +565,7 @@ nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
|
|||||||
|
|
||||||
::ZeroMemory(currValue, sizeof(currValue));
|
::ZeroMemory(currValue, sizeof(currValue));
|
||||||
DWORD len = sizeof currValue;
|
DWORD len = sizeof currValue;
|
||||||
res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue,
|
res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr, (LPBYTE)currValue,
|
||||||
&len);
|
&len);
|
||||||
|
|
||||||
// Don't update the FTP protocol handler's shell open command when the
|
// Don't update the FTP protocol handler's shell open command when the
|
||||||
@ -606,7 +607,7 @@ DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
|
|||||||
{
|
{
|
||||||
typedef HRESULT (WINAPI * SHOpenWithDialogPtr)(HWND hwndParent,
|
typedef HRESULT (WINAPI * SHOpenWithDialogPtr)(HWND hwndParent,
|
||||||
const OPENASINFO *poainfo);
|
const OPENASINFO *poainfo);
|
||||||
static SHOpenWithDialogPtr SHOpenWithDialogFn = NULL;
|
static SHOpenWithDialogPtr SHOpenWithDialogFn = nullptr;
|
||||||
if (!SHOpenWithDialogFn) {
|
if (!SHOpenWithDialogFn) {
|
||||||
// shell32.dll is in the knownDLLs list so will always be loaded from the
|
// shell32.dll is in the knownDLLs list so will always be loaded from the
|
||||||
// system32 directory.
|
// system32 directory.
|
||||||
@ -650,8 +651,8 @@ nsWindowsShellService::LaunchControlPanelDefaultPrograms()
|
|||||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||||
si.wShowWindow = SW_SHOWDEFAULT;
|
si.wShowWindow = SW_SHOWDEFAULT;
|
||||||
PROCESS_INFORMATION pi = {0};
|
PROCESS_INFORMATION pi = {0};
|
||||||
if (!CreateProcessW(controlEXEPath, params, NULL, NULL, FALSE, 0, NULL,
|
if (!CreateProcessW(controlEXEPath, params, nullptr, nullptr, FALSE,
|
||||||
NULL, &si, &pi)) {
|
0, nullptr, nullptr, &si, &pi)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
@ -665,11 +666,11 @@ nsWindowsShellService::LaunchHTTPHandlerPane()
|
|||||||
{
|
{
|
||||||
OPENASINFO info;
|
OPENASINFO info;
|
||||||
info.pcszFile = L"http";
|
info.pcszFile = L"http";
|
||||||
info.pcszClass = NULL;
|
info.pcszClass = nullptr;
|
||||||
info.oaifInFlags = OAIF_FORCE_REGISTRATION |
|
info.oaifInFlags = OAIF_FORCE_REGISTRATION |
|
||||||
OAIF_URL_PROTOCOL |
|
OAIF_URL_PROTOCOL |
|
||||||
OAIF_REGISTER_EXT;
|
OAIF_REGISTER_EXT;
|
||||||
return DynSHOpenWithDialog(NULL, &info);
|
return DynSHOpenWithDialog(nullptr, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
@ -1028,8 +1029,8 @@ nsWindowsShellService::OpenApplication(int32_t aApplication)
|
|||||||
::ZeroMemory(&si, sizeof(STARTUPINFOW));
|
::ZeroMemory(&si, sizeof(STARTUPINFOW));
|
||||||
::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
||||||
|
|
||||||
BOOL success = ::CreateProcessW(NULL, (LPWSTR)path.get(), NULL,
|
BOOL success = ::CreateProcessW(nullptr, (LPWSTR)path.get(), nullptr,
|
||||||
NULL, FALSE, 0, NULL, NULL,
|
nullptr, FALSE, 0, nullptr, nullptr,
|
||||||
&si, &pi);
|
&si, &pi);
|
||||||
if (!success)
|
if (!success)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
@ -46,11 +46,13 @@ var APZCObserver = {
|
|||||||
case 'TabOpen': {
|
case 'TabOpen': {
|
||||||
let browser = aEvent.originalTarget.linkedBrowser;
|
let browser = aEvent.originalTarget.linkedBrowser;
|
||||||
browser.addEventListener("pageshow", this, true);
|
browser.addEventListener("pageshow", this, true);
|
||||||
|
browser.messageManager.addMessageListener("scroll", this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'TabClose': {
|
case 'TabClose': {
|
||||||
let browser = aEvent.originalTarget.linkedBrowser;
|
let browser = aEvent.originalTarget.linkedBrowser;
|
||||||
browser.removeEventListener("pageshow", this);
|
browser.removeEventListener("pageshow", this, true);
|
||||||
|
browser.messageManager.removeMessageListener("scroll", this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,5 +115,16 @@ var APZCObserver = {
|
|||||||
} else if (aTopic == "apzc-handle-pan-end") {
|
} else if (aTopic == "apzc-handle-pan-end") {
|
||||||
Util.dumpLn("APZC pan-end");
|
Util.dumpLn("APZC pan-end");
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
receiveMessage: function(aMessage) {
|
||||||
|
let json = aMessage.json;
|
||||||
|
switch (aMessage.name) {
|
||||||
|
case "scroll": {
|
||||||
|
let data = json.viewId + " " + json.presShellId + " (" + json.scrollOffset.x + ", " + json.scrollOffset.y + ")";
|
||||||
|
Services.obs.notifyObservers(null, "scroll-offset-changed", data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -652,11 +652,7 @@ let ContentScroll = {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "scroll": {
|
case "scroll": {
|
||||||
let doc = aEvent.target;
|
this.sendScroll(aEvent.target);
|
||||||
if (doc != content.document)
|
|
||||||
break;
|
|
||||||
|
|
||||||
this.sendScroll();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,13 +679,35 @@ let ContentScroll = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
sendScroll: function sendScroll() {
|
sendScroll: function sendScroll(target) {
|
||||||
let scrollOffset = this.getScrollOffset(content);
|
let isRoot = false;
|
||||||
if (this._scrollOffset.x == scrollOffset.x && this._scrollOffset.y == scrollOffset.y)
|
if (target instanceof Ci.nsIDOMDocument) {
|
||||||
return;
|
var window = target.defaultView;
|
||||||
|
var scrollOffset = this.getScrollOffset(window);
|
||||||
|
var element = target.documentElement;
|
||||||
|
|
||||||
this._scrollOffset = scrollOffset;
|
if (target == content.document) {
|
||||||
sendAsyncMessage("scroll", scrollOffset);
|
if (this._scrollOffset.x == scrollOffset.x && this._scrollOffset.y == scrollOffset.y) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._scrollOffset = scrollOffset;
|
||||||
|
isRoot = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var window = target.currentDoc.defaultView;
|
||||||
|
var scrollOffset = this.getScrollOffsetForElement(target);
|
||||||
|
var element = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
let utils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||||
|
let presShellId = {};
|
||||||
|
utils.getPresShellId(presShellId);
|
||||||
|
let viewId = utils.getViewId(element);
|
||||||
|
|
||||||
|
sendAsyncMessage("scroll", { presShellId: presShellId.value,
|
||||||
|
viewId: viewId,
|
||||||
|
scrollOffset: scrollOffset,
|
||||||
|
isRoot: isRoot });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -859,9 +859,11 @@
|
|||||||
|
|
||||||
switch (aMessage.name) {
|
switch (aMessage.name) {
|
||||||
case "scroll":
|
case "scroll":
|
||||||
|
if (!json.isRoot)
|
||||||
|
return;
|
||||||
if (!self.scrollSync)
|
if (!self.scrollSync)
|
||||||
return;
|
return;
|
||||||
this.doScroll(json.x, json.y, 0);
|
this.doScroll(json.scrollOffset.x, json.scrollOffset.y, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -23,7 +23,7 @@ Log(const wchar_t *fmt, ...)
|
|||||||
#if !defined(SHOW_CONSOLE)
|
#if !defined(SHOW_CONSOLE)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
va_list a = NULL;
|
va_list a = nullptr;
|
||||||
wchar_t szDebugString[1024];
|
wchar_t szDebugString[1024];
|
||||||
if(!lstrlenW(fmt))
|
if(!lstrlenW(fmt))
|
||||||
return;
|
return;
|
||||||
@ -34,8 +34,8 @@ Log(const wchar_t *fmt, ...)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
DWORD len;
|
DWORD len;
|
||||||
WriteConsoleW(sCon, szDebugString, lstrlenW(szDebugString), &len, NULL);
|
WriteConsoleW(sCon, szDebugString, lstrlenW(szDebugString), &len, nullptr);
|
||||||
WriteConsoleW(sCon, L"\n", 1, &len, NULL);
|
WriteConsoleW(sCon, L"\n", 1, &len, nullptr);
|
||||||
|
|
||||||
if (IsDebuggerPresent()) {
|
if (IsDebuggerPresent()) {
|
||||||
OutputDebugStringW(szDebugString);
|
OutputDebugStringW(szDebugString);
|
||||||
@ -53,7 +53,7 @@ SetupConsole()
|
|||||||
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(sCon), 0);
|
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(sCon), 0);
|
||||||
fp = _fdopen(fd, "w");
|
fp = _fdopen(fd, "w");
|
||||||
*stdout = *fp;
|
*stdout = *fp;
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -104,19 +104,19 @@ IsDX10Available()
|
|||||||
|
|
||||||
CComPtr<ID3D10Device1> device;
|
CComPtr<ID3D10Device1> device;
|
||||||
// Try for DX10.1
|
// Try for DX10.1
|
||||||
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, NULL,
|
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
|
||||||
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
||||||
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||||
D3D10_FEATURE_LEVEL_10_1,
|
D3D10_FEATURE_LEVEL_10_1,
|
||||||
D3D10_1_SDK_VERSION, &device))) {
|
D3D10_1_SDK_VERSION, &device))) {
|
||||||
// Try for DX10
|
// Try for DX10
|
||||||
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, NULL,
|
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
|
||||||
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
||||||
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||||
D3D10_FEATURE_LEVEL_10_0,
|
D3D10_FEATURE_LEVEL_10_0,
|
||||||
D3D10_1_SDK_VERSION, &device))) {
|
D3D10_1_SDK_VERSION, &device))) {
|
||||||
// Try for DX9.3 (we fall back to cairo and cairo has support for D3D 9.3)
|
// Try for DX9.3 (we fall back to cairo and cairo has support for D3D 9.3)
|
||||||
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, NULL,
|
if (FAILED(createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
|
||||||
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
||||||
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||||
D3D10_FEATURE_LEVEL_9_3,
|
D3D10_FEATURE_LEVEL_9_3,
|
||||||
|
@ -49,7 +49,7 @@ static bool GetModulePath(CStringW& aPathBuffer)
|
|||||||
WCHAR buffer[MAX_PATH];
|
WCHAR buffer[MAX_PATH];
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
if (!GetModuleFileName(NULL, buffer, MAX_PATH)) {
|
if (!GetModuleFileName(nullptr, buffer, MAX_PATH)) {
|
||||||
Log(L"GetModuleFileName failed.");
|
Log(L"GetModuleFileName failed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ template <class T>void SafeRelease(T **ppT)
|
|||||||
{
|
{
|
||||||
if (*ppT) {
|
if (*ppT) {
|
||||||
(*ppT)->Release();
|
(*ppT)->Release();
|
||||||
*ppT = NULL;
|
*ppT = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,8 +89,8 @@ public:
|
|||||||
|
|
||||||
CExecuteCommandVerb() :
|
CExecuteCommandVerb() :
|
||||||
mRef(1),
|
mRef(1),
|
||||||
mShellItemArray(NULL),
|
mShellItemArray(nullptr),
|
||||||
mUnkSite(NULL),
|
mUnkSite(nullptr),
|
||||||
mTargetIsFileSystemLink(false),
|
mTargetIsFileSystemLink(false),
|
||||||
mTargetIsDefaultBrowser(false),
|
mTargetIsDefaultBrowser(false),
|
||||||
mTargetIsBrowser(false),
|
mTargetIsBrowser(false),
|
||||||
@ -176,9 +176,9 @@ public:
|
|||||||
#ifdef SHOW_CONSOLE
|
#ifdef SHOW_CONSOLE
|
||||||
Log(L"SetSelection param count: %d", count);
|
Log(L"SetSelection param count: %d", count);
|
||||||
for (DWORD idx = 0; idx < count; idx++) {
|
for (DWORD idx = 0; idx < count; idx++) {
|
||||||
IShellItem* item = NULL;
|
IShellItem* item = nullptr;
|
||||||
if (SUCCEEDED(aArray->GetItemAt(idx, &item))) {
|
if (SUCCEEDED(aArray->GetItemAt(idx, &item))) {
|
||||||
LPWSTR str = NULL;
|
LPWSTR str = nullptr;
|
||||||
if (FAILED(item->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
|
if (FAILED(item->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
|
||||||
if (FAILED(item->GetDisplayName(SIGDN_URL, &str))) {
|
if (FAILED(item->GetDisplayName(SIGDN_URL, &str))) {
|
||||||
Log(L"Failed to get a shell item array item.");
|
Log(L"Failed to get a shell item array item.");
|
||||||
@ -193,7 +193,7 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
IShellItem* item = NULL;
|
IShellItem* item = nullptr;
|
||||||
if (FAILED(aArray->GetItemAt(0, &item))) {
|
if (FAILED(aArray->GetItemAt(0, &item))) {
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ public:
|
|||||||
|
|
||||||
IFACEMETHODIMP GetSelection(REFIID aRefID, void **aInt)
|
IFACEMETHODIMP GetSelection(REFIID aRefID, void **aInt)
|
||||||
{
|
{
|
||||||
*aInt = NULL;
|
*aInt = nullptr;
|
||||||
return mShellItemArray ? mShellItemArray->QueryInterface(aRefID, aInt) : E_FAIL;
|
return mShellItemArray ? mShellItemArray->QueryInterface(aRefID, aInt) : E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ public:
|
|||||||
|
|
||||||
IFACEMETHODIMP GetSite(REFIID aRefID, void **aInt)
|
IFACEMETHODIMP GetSite(REFIID aRefID, void **aInt)
|
||||||
{
|
{
|
||||||
*aInt = NULL;
|
*aInt = nullptr;
|
||||||
return mUnkSite ? mUnkSite->QueryInterface(aRefID, aInt) : E_FAIL;
|
return mUnkSite ? mUnkSite->QueryInterface(aRefID, aInt) : E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,14 +252,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
IServiceProvider* pSvcProvider = NULL;
|
IServiceProvider* pSvcProvider = nullptr;
|
||||||
hr = mUnkSite->QueryInterface(IID_IServiceProvider, (void**)&pSvcProvider);
|
hr = mUnkSite->QueryInterface(IID_IServiceProvider, (void**)&pSvcProvider);
|
||||||
if (!pSvcProvider) {
|
if (!pSvcProvider) {
|
||||||
Log(L"Couldn't get IServiceProvider service from explorer. (%X)", hr);
|
Log(L"Couldn't get IServiceProvider service from explorer. (%X)", hr);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
IExecuteCommandHost* pHost = NULL;
|
IExecuteCommandHost* pHost = nullptr;
|
||||||
// If we can't get this it's a conventional desktop launch
|
// If we can't get this it's a conventional desktop launch
|
||||||
hr = pSvcProvider->QueryService(SID_ExecuteCommandHost,
|
hr = pSvcProvider->QueryService(SID_ExecuteCommandHost,
|
||||||
IID_IExecuteCommandHost, (void**)&pHost);
|
IID_IExecuteCommandHost, (void**)&pHost);
|
||||||
@ -340,7 +340,7 @@ public:
|
|||||||
{
|
{
|
||||||
IApplicationAssociationRegistration* pAAR;
|
IApplicationAssociationRegistration* pAAR;
|
||||||
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
||||||
NULL,
|
nullptr,
|
||||||
CLSCTX_INPROC,
|
CLSCTX_INPROC,
|
||||||
IID_IApplicationAssociationRegistration,
|
IID_IApplicationAssociationRegistration,
|
||||||
(void**)&pAAR);
|
(void**)&pAAR);
|
||||||
@ -416,7 +416,7 @@ static bool GetDefaultBrowserPath(CStringW& aPathBuffer)
|
|||||||
|
|
||||||
if (FAILED(AssocQueryStringW(ASSOCF_NOTRUNCATE | ASSOCF_INIT_IGNOREUNKNOWN,
|
if (FAILED(AssocQueryStringW(ASSOCF_NOTRUNCATE | ASSOCF_INIT_IGNOREUNKNOWN,
|
||||||
ASSOCSTR_EXECUTABLE,
|
ASSOCSTR_EXECUTABLE,
|
||||||
kDefaultMetroBrowserIDPathKey, NULL,
|
kDefaultMetroBrowserIDPathKey, nullptr,
|
||||||
buffer, &length))) {
|
buffer, &length))) {
|
||||||
Log(L"AssocQueryString failed.");
|
Log(L"AssocQueryString failed.");
|
||||||
return false;
|
return false;
|
||||||
@ -451,7 +451,7 @@ static bool GetDefaultBrowserAppModelID(WCHAR* aIDBuffer,
|
|||||||
}
|
}
|
||||||
DWORD len = aCharLength * sizeof(WCHAR);
|
DWORD len = aCharLength * sizeof(WCHAR);
|
||||||
memset(aIDBuffer, 0, len);
|
memset(aIDBuffer, 0, len);
|
||||||
if (RegQueryValueExW(key, L"AppUserModelID", NULL, NULL,
|
if (RegQueryValueExW(key, L"AppUserModelID", nullptr, nullptr,
|
||||||
(LPBYTE)aIDBuffer, &len) != ERROR_SUCCESS || !len) {
|
(LPBYTE)aIDBuffer, &len) != ERROR_SUCCESS || !len) {
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
return false;
|
return false;
|
||||||
@ -513,7 +513,7 @@ bool CExecuteCommandVerb::SetTargetPath(IShellItem* aItem)
|
|||||||
CComPtr<IDataObject> object;
|
CComPtr<IDataObject> object;
|
||||||
// Check the underlying data object first to insure we get
|
// Check the underlying data object first to insure we get
|
||||||
// absolute uri. See chromium bug 157184.
|
// absolute uri. See chromium bug 157184.
|
||||||
if (SUCCEEDED(aItem->BindToHandler(NULL, BHID_DataObject,
|
if (SUCCEEDED(aItem->BindToHandler(nullptr, BHID_DataObject,
|
||||||
IID_IDataObject,
|
IID_IDataObject,
|
||||||
reinterpret_cast<void**>(&object))) &&
|
reinterpret_cast<void**>(&object))) &&
|
||||||
GetPlainText(object, cstrText)) {
|
GetPlainText(object, cstrText)) {
|
||||||
@ -537,7 +537,7 @@ bool CExecuteCommandVerb::SetTargetPath(IShellItem* aItem)
|
|||||||
Log(L"No data object or data object has no text.");
|
Log(L"No data object or data object has no text.");
|
||||||
|
|
||||||
// Use the shell item display name
|
// Use the shell item display name
|
||||||
LPWSTR str = NULL;
|
LPWSTR str = nullptr;
|
||||||
mTargetIsFileSystemLink = true;
|
mTargetIsFileSystemLink = true;
|
||||||
if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
|
if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
|
||||||
mTargetIsFileSystemLink = false;
|
mTargetIsFileSystemLink = false;
|
||||||
@ -596,12 +596,12 @@ void CExecuteCommandVerb::LaunchDesktopBrowser()
|
|||||||
SHELLEXECUTEINFOW seinfo;
|
SHELLEXECUTEINFOW seinfo;
|
||||||
memset(&seinfo, 0, sizeof(seinfo));
|
memset(&seinfo, 0, sizeof(seinfo));
|
||||||
seinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
|
seinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
|
||||||
seinfo.fMask = NULL;
|
seinfo.fMask = 0;
|
||||||
seinfo.hwnd = NULL;
|
seinfo.hwnd = nullptr;
|
||||||
seinfo.lpVerb = NULL;
|
seinfo.lpVerb = nullptr;
|
||||||
seinfo.lpFile = browserPath;
|
seinfo.lpFile = browserPath;
|
||||||
seinfo.lpParameters = params;
|
seinfo.lpParameters = params;
|
||||||
seinfo.lpDirectory = NULL;
|
seinfo.lpDirectory = nullptr;
|
||||||
seinfo.nShow = SW_SHOWNORMAL;
|
seinfo.nShow = SW_SHOWNORMAL;
|
||||||
|
|
||||||
ShellExecuteExW(&seinfo);
|
ShellExecuteExW(&seinfo);
|
||||||
@ -635,9 +635,9 @@ IFACEMETHODIMP CExecuteCommandVerb::Execute()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Launch into Metro
|
// Launch into Metro
|
||||||
IApplicationActivationManager* activateMgr = NULL;
|
IApplicationActivationManager* activateMgr = nullptr;
|
||||||
DWORD processID;
|
DWORD processID;
|
||||||
if (FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, NULL,
|
if (FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, nullptr,
|
||||||
CLSCTX_LOCAL_SERVER,
|
CLSCTX_LOCAL_SERVER,
|
||||||
IID_IApplicationActivationManager,
|
IID_IApplicationActivationManager,
|
||||||
(void**)&activateMgr))) {
|
(void**)&activateMgr))) {
|
||||||
@ -657,7 +657,7 @@ IFACEMETHODIMP CExecuteCommandVerb::Execute()
|
|||||||
|
|
||||||
// Hand off focus rights to the out-of-process activation server. Without
|
// Hand off focus rights to the out-of-process activation server. Without
|
||||||
// this the metro interface won't launch.
|
// this the metro interface won't launch.
|
||||||
hr = CoAllowSetForegroundWindow(activateMgr, NULL);
|
hr = CoAllowSetForegroundWindow(activateMgr, nullptr);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
Log(L"CoAllowSetForegroundWindow result %X", hr);
|
Log(L"CoAllowSetForegroundWindow result %X", hr);
|
||||||
activateMgr->Release();
|
activateMgr->Release();
|
||||||
@ -727,7 +727,7 @@ ClassFactory::Register(CLSCTX aClass, REGCLS aUse)
|
|||||||
STDMETHODIMP
|
STDMETHODIMP
|
||||||
ClassFactory::QueryInterface(REFIID riid, void **ppv)
|
ClassFactory::QueryInterface(REFIID riid, void **ppv)
|
||||||
{
|
{
|
||||||
IUnknown *punk = NULL;
|
IUnknown *punk = nullptr;
|
||||||
if (riid == IID_IUnknown || riid == IID_IClassFactory) {
|
if (riid == IID_IUnknown || riid == IID_IClassFactory) {
|
||||||
punk = static_cast<IClassFactory*>(this);
|
punk = static_cast<IClassFactory*>(this);
|
||||||
}
|
}
|
||||||
@ -743,7 +743,7 @@ ClassFactory::QueryInterface(REFIID riid, void **ppv)
|
|||||||
STDMETHODIMP
|
STDMETHODIMP
|
||||||
ClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
ClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
||||||
{
|
{
|
||||||
*ppv = NULL;
|
*ppv = nullptr;
|
||||||
if (punkOuter)
|
if (punkOuter)
|
||||||
return CLASS_E_NOAGGREGATION;
|
return CLASS_E_NOAGGREGATION;
|
||||||
return mUnkObject->QueryInterface(riid, ppv);
|
return mUnkObject->QueryInterface(riid, ppv);
|
||||||
@ -771,7 +771,7 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR pszCmdLine, int)
|
|||||||
|
|
||||||
if (!wcslen(pszCmdLine) || StrStrI(pszCmdLine, L"-Embedding"))
|
if (!wcslen(pszCmdLine) || StrStrI(pszCmdLine, L"-Embedding"))
|
||||||
{
|
{
|
||||||
CoInitialize(NULL);
|
CoInitialize(nullptr);
|
||||||
|
|
||||||
CExecuteCommandVerb *pHandler = new CExecuteCommandVerb();
|
CExecuteCommandVerb *pHandler = new CExecuteCommandVerb();
|
||||||
if (!pHandler)
|
if (!pHandler)
|
||||||
@ -784,13 +784,13 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR pszCmdLine, int)
|
|||||||
|
|
||||||
ClassFactory classFactory(ppi);
|
ClassFactory classFactory(ppi);
|
||||||
ppi->Release();
|
ppi->Release();
|
||||||
ppi = NULL;
|
ppi = nullptr;
|
||||||
|
|
||||||
// REGCLS_SINGLEUSE insures we only get used once and then discarded.
|
// REGCLS_SINGLEUSE insures we only get used once and then discarded.
|
||||||
if (FAILED(classFactory.Register(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE)))
|
if (FAILED(classFactory.Register(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!SetTimer(NULL, 1, HEARTBEAT_MSEC, NULL)) {
|
if (!SetTimer(nullptr, 1, HEARTBEAT_MSEC, nullptr)) {
|
||||||
Log(L"Failed to set timer, can't process request.");
|
Log(L"Failed to set timer, can't process request.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,13 @@ HRESULT
|
|||||||
SetShortcutProps(LPCWSTR aShortcutPath, LPCWSTR aAppModelID, bool aSetID, bool aSetMode)
|
SetShortcutProps(LPCWSTR aShortcutPath, LPCWSTR aAppModelID, bool aSetID, bool aSetMode)
|
||||||
{
|
{
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
::CoInitialize(NULL);
|
::CoInitialize(nullptr);
|
||||||
|
|
||||||
IPropertyStore *m_pps = NULL;
|
IPropertyStore *m_pps = nullptr;
|
||||||
if (FAILED(hres = SHGetPropertyStoreFromParsingName(aShortcutPath, NULL, GPS_READWRITE, IID_PPV_ARGS(&m_pps)))) {
|
if (FAILED(hres = SHGetPropertyStoreFromParsingName(aShortcutPath,
|
||||||
|
nullptr,
|
||||||
|
GPS_READWRITE,
|
||||||
|
IID_PPV_ARGS(&m_pps)))) {
|
||||||
printf("SHGetPropertyStoreFromParsingName failed\n");
|
printf("SHGetPropertyStoreFromParsingName failed\n");
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
@ -79,10 +82,13 @@ HRESULT
|
|||||||
PrintShortcutProps(LPCWSTR aTargetPath)
|
PrintShortcutProps(LPCWSTR aTargetPath)
|
||||||
{
|
{
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
::CoInitialize(NULL);
|
::CoInitialize(nullptr);
|
||||||
|
|
||||||
IPropertyStore *m_pps = NULL;
|
IPropertyStore *m_pps = nullptr;
|
||||||
if (FAILED(hres = SHGetPropertyStoreFromParsingName(aTargetPath, NULL, GPS_READWRITE, IID_PPV_ARGS(&m_pps)))) {
|
if (FAILED(hres = SHGetPropertyStoreFromParsingName(aTargetPath,
|
||||||
|
nullptr,
|
||||||
|
GPS_READWRITE,
|
||||||
|
IID_PPV_ARGS(&m_pps)))) {
|
||||||
printf("SHGetPropertyStoreFromParsingName failed\n");
|
printf("SHGetPropertyStoreFromParsingName failed\n");
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
@ -125,9 +131,9 @@ CreateLink(LPCWSTR aTargetPath, LPCWSTR aShortcutPath, LPCWSTR aDescription)
|
|||||||
|
|
||||||
wprintf(L"creating shortcut: '%s'\n", aShortcutPath);
|
wprintf(L"creating shortcut: '%s'\n", aShortcutPath);
|
||||||
|
|
||||||
CoInitialize(NULL);
|
CoInitialize(nullptr);
|
||||||
|
|
||||||
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
|
||||||
IID_IShellLink, (LPVOID*)&psl);
|
IID_IShellLink, (LPVOID*)&psl);
|
||||||
if (FAILED(hres)) {
|
if (FAILED(hres)) {
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
@ -140,7 +146,7 @@ CreateLink(LPCWSTR aTargetPath, LPCWSTR aShortcutPath, LPCWSTR aDescription)
|
|||||||
psl->SetDescription(L"");
|
psl->SetDescription(L"");
|
||||||
}
|
}
|
||||||
|
|
||||||
IPersistFile* ppf = NULL;
|
IPersistFile* ppf = nullptr;
|
||||||
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
|
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
|
||||||
|
|
||||||
if (SUCCEEDED(hres)) {
|
if (SUCCEEDED(hres)) {
|
||||||
@ -261,7 +267,9 @@ int wmain(int argc, WCHAR* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (createShortcutFound) {
|
if (createShortcutFound) {
|
||||||
if (FAILED(hres = CreateLink(targetPathStr, shortcutPathStr, (descriptionFound ? descriptionStr : NULL)))) {
|
if (FAILED(hres = CreateLink(targetPathStr,
|
||||||
|
shortcutPathStr,
|
||||||
|
(descriptionFound ? descriptionStr : nullptr)))) {
|
||||||
printf("failed creating shortcut HRESULT=%X\n", hres);
|
printf("failed creating shortcut HRESULT=%X\n", hres);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -275,7 +283,9 @@ int wmain(int argc, WCHAR* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (appModelIDFound || modeFound) {
|
if (appModelIDFound || modeFound) {
|
||||||
if (FAILED(hres = SetShortcutProps(target, (appModelIDFound ? appModelIDStr : NULL), appModelIDFound, modeFound))) {
|
if (FAILED(hres = SetShortcutProps(target,
|
||||||
|
(appModelIDFound ? appModelIDStr : nullptr),
|
||||||
|
appModelIDFound, modeFound))) {
|
||||||
printf("failed adding property HRESULT=%X\n", hres);
|
printf("failed adding property HRESULT=%X\n", hres);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ CString sFirefoxPath;
|
|||||||
|
|
||||||
static void Log(const wchar_t *fmt, ...)
|
static void Log(const wchar_t *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list a = NULL;
|
va_list a = nullptr;
|
||||||
wchar_t szDebugString[1024];
|
wchar_t szDebugString[1024];
|
||||||
if(!lstrlenW(fmt))
|
if(!lstrlenW(fmt))
|
||||||
return;
|
return;
|
||||||
@ -66,7 +66,7 @@ static void Log(const wchar_t *fmt, ...)
|
|||||||
|
|
||||||
static void Fail(bool aRequestRetry, const wchar_t *fmt, ...)
|
static void Fail(bool aRequestRetry, const wchar_t *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list a = NULL;
|
va_list a = nullptr;
|
||||||
wchar_t szDebugString[1024];
|
wchar_t szDebugString[1024];
|
||||||
if(!lstrlenW(fmt))
|
if(!lstrlenW(fmt))
|
||||||
return;
|
return;
|
||||||
@ -93,7 +93,7 @@ static bool GetModulePath(CStringW& aPathBuffer)
|
|||||||
WCHAR buffer[MAX_PATH];
|
WCHAR buffer[MAX_PATH];
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
if (!GetModuleFileName(NULL, buffer, MAX_PATH)) {
|
if (!GetModuleFileName(nullptr, buffer, MAX_PATH)) {
|
||||||
Fail(false, L"GetModuleFileName failed.");
|
Fail(false, L"GetModuleFileName failed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ static bool GetDefaultBrowserAppModelID(WCHAR* aIDBuffer,
|
|||||||
}
|
}
|
||||||
DWORD len = aCharLength * sizeof(WCHAR);
|
DWORD len = aCharLength * sizeof(WCHAR);
|
||||||
memset(aIDBuffer, 0, len);
|
memset(aIDBuffer, 0, len);
|
||||||
if (RegQueryValueExW(key, L"AppUserModelID", NULL, NULL,
|
if (RegQueryValueExW(key, L"AppUserModelID", nullptr, nullptr,
|
||||||
(LPBYTE)aIDBuffer, &len) != ERROR_SUCCESS || !len) {
|
(LPBYTE)aIDBuffer, &len) != ERROR_SUCCESS || !len) {
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
return false;
|
return false;
|
||||||
@ -174,7 +174,7 @@ static bool SetupTestOutputPipe()
|
|||||||
SECURITY_ATTRIBUTES saAttr;
|
SECURITY_ATTRIBUTES saAttr;
|
||||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
saAttr.bInheritHandle = TRUE;
|
saAttr.bInheritHandle = TRUE;
|
||||||
saAttr.lpSecurityDescriptor = NULL;
|
saAttr.lpSecurityDescriptor = nullptr;
|
||||||
|
|
||||||
gTestOutputPipe =
|
gTestOutputPipe =
|
||||||
CreateNamedPipeW(L"\\\\.\\pipe\\metrotestharness",
|
CreateNamedPipeW(L"\\\\.\\pipe\\metrotestharness",
|
||||||
@ -182,7 +182,7 @@ static bool SetupTestOutputPipe()
|
|||||||
PIPE_TYPE_BYTE|PIPE_WAIT,
|
PIPE_TYPE_BYTE|PIPE_WAIT,
|
||||||
1,
|
1,
|
||||||
PIPE_BUFFER_SIZE,
|
PIPE_BUFFER_SIZE,
|
||||||
PIPE_BUFFER_SIZE, 0, NULL);
|
PIPE_BUFFER_SIZE, 0, nullptr);
|
||||||
|
|
||||||
if (gTestOutputPipe == INVALID_HANDLE_VALUE) {
|
if (gTestOutputPipe == INVALID_HANDLE_VALUE) {
|
||||||
Log(L"Failed to create named logging pipe.");
|
Log(L"Failed to create named logging pipe.");
|
||||||
@ -194,7 +194,8 @@ static bool SetupTestOutputPipe()
|
|||||||
static void ReadPipe()
|
static void ReadPipe()
|
||||||
{
|
{
|
||||||
DWORD numBytesRead;
|
DWORD numBytesRead;
|
||||||
while (ReadFile(gTestOutputPipe, buffer, PIPE_BUFFER_SIZE, &numBytesRead, NULL) &&
|
while (ReadFile(gTestOutputPipe, buffer, PIPE_BUFFER_SIZE,
|
||||||
|
&numBytesRead, nullptr) &&
|
||||||
numBytesRead) {
|
numBytesRead) {
|
||||||
buffer[numBytesRead] = '\0';
|
buffer[numBytesRead] = '\0';
|
||||||
printf("%s", buffer);
|
printf("%s", buffer);
|
||||||
@ -209,7 +210,7 @@ static int Launch()
|
|||||||
|
|
||||||
// The interface that allows us to activate the browser
|
// The interface that allows us to activate the browser
|
||||||
CComPtr<IApplicationActivationManager> activateMgr;
|
CComPtr<IApplicationActivationManager> activateMgr;
|
||||||
if (FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, NULL,
|
if (FAILED(CoCreateInstance(CLSID_ApplicationActivationManager, nullptr,
|
||||||
CLSCTX_LOCAL_SERVER,
|
CLSCTX_LOCAL_SERVER,
|
||||||
IID_IApplicationActivationManager,
|
IID_IApplicationActivationManager,
|
||||||
(void**)&activateMgr))) {
|
(void**)&activateMgr))) {
|
||||||
@ -229,7 +230,7 @@ static int Launch()
|
|||||||
// Hand off focus rights if the terminal has focus to the out-of-process
|
// Hand off focus rights if the terminal has focus to the out-of-process
|
||||||
// activation server (explorer.exe). Without this the metro interface
|
// activation server (explorer.exe). Without this the metro interface
|
||||||
// won't launch.
|
// won't launch.
|
||||||
hr = CoAllowSetForegroundWindow(activateMgr, NULL);
|
hr = CoAllowSetForegroundWindow(activateMgr, nullptr);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
// Log but don't fail. This has happened on vms with certain terminals run by
|
// Log but don't fail. This has happened on vms with certain terminals run by
|
||||||
// QA during mozmill testing.
|
// QA during mozmill testing.
|
||||||
@ -264,7 +265,7 @@ static int Launch()
|
|||||||
} else {
|
} else {
|
||||||
// Use the module path
|
// Use the module path
|
||||||
char path[MAX_PATH];
|
char path[MAX_PATH];
|
||||||
if (!GetModuleFileNameA(NULL, path, MAX_PATH)) {
|
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
|
||||||
Fail(false, L"GetModuleFileNameA errorno=%d", GetLastError());
|
Fail(false, L"GetModuleFileNameA errorno=%d", GetLastError());
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
@ -289,9 +290,9 @@ static int Launch()
|
|||||||
|
|
||||||
Log(L"Writing out tests.ini to: '%s'", CStringW(testFilePath));
|
Log(L"Writing out tests.ini to: '%s'", CStringW(testFilePath));
|
||||||
HANDLE hTestFile = CreateFileA(testFilePath, GENERIC_WRITE,
|
HANDLE hTestFile = CreateFileA(testFilePath, GENERIC_WRITE,
|
||||||
0, NULL, CREATE_ALWAYS,
|
0, nullptr, CREATE_ALWAYS,
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
NULL);
|
nullptr);
|
||||||
if (hTestFile == INVALID_HANDLE_VALUE) {
|
if (hTestFile == INVALID_HANDLE_VALUE) {
|
||||||
Fail(false, L"CreateFileA errorno=%d", GetLastError());
|
Fail(false, L"CreateFileA errorno=%d", GetLastError());
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
@ -306,7 +307,8 @@ static int Launch()
|
|||||||
asciiParams += sAppParams;
|
asciiParams += sAppParams;
|
||||||
asciiParams.Trim();
|
asciiParams.Trim();
|
||||||
Log(L"Browser command line args: '%s'", CString(asciiParams));
|
Log(L"Browser command line args: '%s'", CString(asciiParams));
|
||||||
if (!WriteFile(hTestFile, asciiParams, asciiParams.GetLength(), NULL, 0)) {
|
if (!WriteFile(hTestFile, asciiParams, asciiParams.GetLength(),
|
||||||
|
nullptr, 0)) {
|
||||||
CloseHandle(hTestFile);
|
CloseHandle(hTestFile);
|
||||||
Fail(false, L"WriteFile errorno=%d", GetLastError());
|
Fail(false, L"WriteFile errorno=%d", GetLastError());
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
@ -347,7 +349,7 @@ static int Launch()
|
|||||||
} else if (waitResult == WAIT_OBJECT_0 + 1) {
|
} else if (waitResult == WAIT_OBJECT_0 + 1) {
|
||||||
ReadPipe();
|
ReadPipe();
|
||||||
} else if (waitResult == WAIT_OBJECT_0 + 2 &&
|
} else if (waitResult == WAIT_OBJECT_0 + 2 &&
|
||||||
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
@ -363,7 +365,7 @@ static int Launch()
|
|||||||
|
|
||||||
int wmain(int argc, WCHAR* argv[])
|
int wmain(int argc, WCHAR* argv[])
|
||||||
{
|
{
|
||||||
CoInitialize(NULL);
|
CoInitialize(nullptr);
|
||||||
|
|
||||||
int idx;
|
int idx;
|
||||||
bool firefoxParam = false;
|
bool firefoxParam = false;
|
||||||
|
@ -91,6 +91,11 @@ this.Social = {
|
|||||||
providers: [],
|
providers: [],
|
||||||
_disabledForSafeMode: false,
|
_disabledForSafeMode: false,
|
||||||
|
|
||||||
|
get allowMultipleWorkers() {
|
||||||
|
return Services.prefs.prefHasUserValue("social.allowMultipleWorkers") &&
|
||||||
|
Services.prefs.getBoolPref("social.allowMultipleWorkers");
|
||||||
|
},
|
||||||
|
|
||||||
get _currentProviderPref() {
|
get _currentProviderPref() {
|
||||||
try {
|
try {
|
||||||
return Services.prefs.getComplexValue("social.provider.current",
|
return Services.prefs.getComplexValue("social.provider.current",
|
||||||
@ -114,15 +119,14 @@ this.Social = {
|
|||||||
this._setProvider(val);
|
this._setProvider(val);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sets the current provider and enables it. Also disables the
|
// Sets the current provider and notifies observers of the change.
|
||||||
// previously set provider, and notifies observers of the change.
|
|
||||||
_setProvider: function (provider) {
|
_setProvider: function (provider) {
|
||||||
if (this._provider == provider)
|
if (this._provider == provider)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Disable the previous provider, if any, since we want only one provider to
|
// Disable the previous provider, if we are not allowing multiple workers,
|
||||||
// be enabled at once.
|
// since we want only one provider to be enabled at once.
|
||||||
if (this._provider)
|
if (this._provider && !Social.allowMultipleWorkers)
|
||||||
this._provider.enabled = false;
|
this._provider.enabled = false;
|
||||||
|
|
||||||
this._provider = provider;
|
this._provider = provider;
|
||||||
@ -134,7 +138,6 @@ this.Social = {
|
|||||||
let enabled = !!provider;
|
let enabled = !!provider;
|
||||||
if (enabled != SocialService.enabled) {
|
if (enabled != SocialService.enabled) {
|
||||||
SocialService.enabled = enabled;
|
SocialService.enabled = enabled;
|
||||||
Services.prefs.setBoolPref("social.enabled", enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let origin = this._provider && this._provider.origin;
|
let origin = this._provider && this._provider.origin;
|
||||||
@ -159,31 +162,40 @@ this.Social = {
|
|||||||
if (SocialService.enabled) {
|
if (SocialService.enabled) {
|
||||||
// Retrieve the current set of providers, and set the current provider.
|
// Retrieve the current set of providers, and set the current provider.
|
||||||
SocialService.getOrderedProviderList(function (providers) {
|
SocialService.getOrderedProviderList(function (providers) {
|
||||||
this._updateProviderCache(providers);
|
Social._updateProviderCache(providers);
|
||||||
}.bind(this));
|
Social._updateWorkerState(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register an observer for changes to the provider list
|
// Register an observer for changes to the provider list
|
||||||
SocialService.registerProviderListener(function providerListener(topic, data) {
|
SocialService.registerProviderListener(function providerListener(topic, data) {
|
||||||
// An engine change caused by adding/removing a provider should notify
|
// An engine change caused by adding/removing a provider should notify.
|
||||||
|
// any providers we receive are enabled in the AddonsManager
|
||||||
if (topic == "provider-added" || topic == "provider-removed") {
|
if (topic == "provider-added" || topic == "provider-removed") {
|
||||||
this._updateProviderCache(data);
|
Social._updateProviderCache(data);
|
||||||
|
Social._updateWorkerState(true);
|
||||||
Services.obs.notifyObservers(null, "social:providers-changed", null);
|
Services.obs.notifyObservers(null, "social:providers-changed", null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (topic == "provider-update") {
|
if (topic == "provider-update") {
|
||||||
// a provider has self-updated its manifest, we need to update our
|
// a provider has self-updated its manifest, we need to update our cache
|
||||||
// cache and possibly reload if it was the current provider.
|
// and reload the provider.
|
||||||
let provider = data;
|
let provider = data;
|
||||||
// if we need a reload, do it now
|
SocialService.getOrderedProviderList(function(providers) {
|
||||||
if (provider.enabled) {
|
Social._updateProviderCache(providers);
|
||||||
Social.enabled = false;
|
provider.reload();
|
||||||
Services.tm.mainThread.dispatch(function() {
|
Services.obs.notifyObservers(null, "social:providers-changed", null);
|
||||||
Social.enabled = true;
|
});
|
||||||
}, Components.interfaces.nsIThread.DISPATCH_NORMAL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.bind(this));
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateWorkerState: function(enable) {
|
||||||
|
// ensure that our providers are all disabled, and enabled if we allow
|
||||||
|
// multiple workers
|
||||||
|
if (enable && !Social.allowMultipleWorkers)
|
||||||
|
return;
|
||||||
|
[p.enabled = enable for (p of Social.providers) if (p.enabled != enable)];
|
||||||
},
|
},
|
||||||
|
|
||||||
// Called to update our cache of providers and set the current provider
|
// Called to update our cache of providers and set the current provider
|
||||||
@ -203,6 +215,9 @@ this.Social = {
|
|||||||
set enabled(val) {
|
set enabled(val) {
|
||||||
// Setting .enabled is just a shortcut for setting the provider to either
|
// Setting .enabled is just a shortcut for setting the provider to either
|
||||||
// the default provider or null...
|
// the default provider or null...
|
||||||
|
|
||||||
|
this._updateWorkerState(val);
|
||||||
|
|
||||||
if (val) {
|
if (val) {
|
||||||
if (!this.provider)
|
if (!this.provider)
|
||||||
this.provider = this.defaultProvider;
|
this.provider = this.defaultProvider;
|
||||||
@ -210,6 +225,7 @@ this.Social = {
|
|||||||
this.provider = null;
|
this.provider = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get enabled() {
|
get enabled() {
|
||||||
return this.provider != null;
|
return this.provider != null;
|
||||||
},
|
},
|
||||||
@ -229,10 +245,6 @@ this.Social = {
|
|||||||
Services.prefs.setBoolPref("social.toast-notifications.enabled", !prefValue);
|
Services.prefs.setBoolPref("social.toast-notifications.enabled", !prefValue);
|
||||||
},
|
},
|
||||||
|
|
||||||
haveLoggedInUser: function () {
|
|
||||||
return !!(this.provider && this.provider.profile && this.provider.profile.userName);
|
|
||||||
},
|
|
||||||
|
|
||||||
setProviderByOrigin: function (origin) {
|
setProviderByOrigin: function (origin) {
|
||||||
this.provider = this._getProviderFromOrigin(origin);
|
this.provider = this._getProviderFromOrigin(origin);
|
||||||
},
|
},
|
||||||
|
@ -2076,7 +2076,10 @@ ia64*-hpux*)
|
|||||||
XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
||||||
LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
||||||
MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)'
|
MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)'
|
||||||
LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT -RELEASE"
|
LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT"
|
||||||
|
if test -z "$DEVELOPER_OPTIONS"; then
|
||||||
|
LDFLAGS="$LDFLAGS -RELEASE"
|
||||||
|
fi
|
||||||
dnl For profile-guided optimization
|
dnl For profile-guided optimization
|
||||||
PROFILE_GEN_CFLAGS="-GL"
|
PROFILE_GEN_CFLAGS="-GL"
|
||||||
PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
|
PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
|
||||||
|
@ -1808,7 +1808,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify that newContent has no parent.
|
// Verify that newContent has no parent.
|
||||||
if (newContent->GetParent()) {
|
if (newContent->GetParentNode()) {
|
||||||
aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
|
aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1885,7 +1885,7 @@ nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
|
|||||||
|
|
||||||
// Verify that all the things in fragChildren have no parent.
|
// Verify that all the things in fragChildren have no parent.
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
if (fragChildren.ref().ElementAt(i)->GetParent()) {
|
if (fragChildren.ref().ElementAt(i)->GetParentNode()) {
|
||||||
aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
|
aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2643,12 +2643,6 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
|
|||||||
nsIScrollableFrame* frameToScroll =
|
nsIScrollableFrame* frameToScroll =
|
||||||
lastScrollFrame->GetScrollTargetFrame();
|
lastScrollFrame->GetScrollTargetFrame();
|
||||||
if (frameToScroll) {
|
if (frameToScroll) {
|
||||||
nsIFrame* activeRootFrame = nsLayoutUtils::GetActiveScrolledRootFor(
|
|
||||||
lastScrollFrame, nullptr);
|
|
||||||
if (!nsLayoutUtils::GetCrossDocParentFrame(activeRootFrame)) {
|
|
||||||
// Record the fact that the scroll occurred on the top-level page.
|
|
||||||
aEvent->viewPortIsScrollTargetParent = true;
|
|
||||||
}
|
|
||||||
return frameToScroll;
|
return frameToScroll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2714,14 +2708,7 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
|
|||||||
aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
|
aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
|
||||||
aOptions =
|
aOptions =
|
||||||
static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
|
static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
|
||||||
if (newFrame) {
|
return newFrame ? ComputeScrollTarget(newFrame, aEvent, aOptions) : nullptr;
|
||||||
return ComputeScrollTarget(newFrame, aEvent, aOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the fact that the scroll occurred past the bounds of the top-level
|
|
||||||
// page.
|
|
||||||
aEvent->viewPortIsScrollTargetParent = true;
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSize
|
nsSize
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "nsMappedAttributes.h"
|
#include "nsMappedAttributes.h"
|
||||||
#include "nsSize.h"
|
#include "nsSize.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
|
#include "nsIDOMMutationEvent.h"
|
||||||
#include "nsIScriptContext.h"
|
#include "nsIScriptContext.h"
|
||||||
#include "nsIURL.h"
|
#include "nsIURL.h"
|
||||||
#include "nsIIOService.h"
|
#include "nsIIOService.h"
|
||||||
@ -251,6 +252,11 @@ HTMLImageElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
|||||||
if (aAttribute == nsGkAtoms::usemap ||
|
if (aAttribute == nsGkAtoms::usemap ||
|
||||||
aAttribute == nsGkAtoms::ismap) {
|
aAttribute == nsGkAtoms::ismap) {
|
||||||
NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
|
NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
|
||||||
|
} else if (aAttribute == nsGkAtoms::alt) {
|
||||||
|
if (aModType == nsIDOMMutationEvent::ADDITION ||
|
||||||
|
aModType == nsIDOMMutationEvent::REMOVAL) {
|
||||||
|
NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ MOCHITEST_FILES = \
|
|||||||
test_bug448534.html \
|
test_bug448534.html \
|
||||||
test_bug463162.xhtml \
|
test_bug463162.xhtml \
|
||||||
test_decoder_disable.html \
|
test_decoder_disable.html \
|
||||||
|
test_mediarecorder_record_no_timeslice.html \
|
||||||
test_mediarecorder_reload_crash.html \
|
test_mediarecorder_reload_crash.html \
|
||||||
test_media_selection.html \
|
test_media_selection.html \
|
||||||
test_playback.html \
|
test_playback.html \
|
||||||
|
117
content/media/test/test_mediarecorder_record_no_timeslice.html
Normal file
117
content/media/test/test_mediarecorder_record_no_timeslice.html
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test MediaRecorder Record No Timeslice</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
<script type="text/javascript" src="manifest.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="test">
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
var manager = new MediaTestManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a test on every media recorder file included to check that a
|
||||||
|
* stream derived from the file can be recorded with no time slice provided.
|
||||||
|
*/
|
||||||
|
function startTest(test, token) {
|
||||||
|
var element = document.createElement('audio');
|
||||||
|
var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
|
||||||
|
|
||||||
|
element.token = token;
|
||||||
|
manager.started(token);
|
||||||
|
|
||||||
|
element.src = test.name;
|
||||||
|
element.test = test;
|
||||||
|
element.stream = element.mozCaptureStream();
|
||||||
|
|
||||||
|
var mediaRecorder = new MediaRecorder(element.stream);
|
||||||
|
var onStopFired = false;
|
||||||
|
var onDataAvailableFired = false;
|
||||||
|
|
||||||
|
mediaRecorder.onerror = function () {
|
||||||
|
ok(false, 'Unexpected onerror callback fired');
|
||||||
|
};
|
||||||
|
|
||||||
|
mediaRecorder.onwarning = function () {
|
||||||
|
ok(false, 'Unexpected onwarning callback fired');
|
||||||
|
};
|
||||||
|
|
||||||
|
// This handler verifies that only a single onstop event handler is fired.
|
||||||
|
mediaRecorder.onstop = function () {
|
||||||
|
if (onStopFired) {
|
||||||
|
ok(false, 'onstop unexpectedly fired more than once');
|
||||||
|
} else {
|
||||||
|
onStopFired = true;
|
||||||
|
|
||||||
|
// ondataavailable should always fire before onstop
|
||||||
|
if (onDataAvailableFired) {
|
||||||
|
manager.finished(token);
|
||||||
|
} else {
|
||||||
|
ok(false, 'onstop fired without an ondataavailable event first');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This handler verifies that only a single ondataavailable event handler
|
||||||
|
// is fired with the blob generated having greater than zero size
|
||||||
|
// and a correct mime type.
|
||||||
|
mediaRecorder.ondataavailable = function (evt) {
|
||||||
|
if (onDataAvailableFired) {
|
||||||
|
ok(false, 'ondataavailable unexpectedly fired more than once');
|
||||||
|
} else {
|
||||||
|
onDataAvailableFired = true;
|
||||||
|
|
||||||
|
ok(evt instanceof BlobEvent,
|
||||||
|
'Events fired from ondataavailable should be BlobEvent');
|
||||||
|
is(evt.type, 'dataavailable',
|
||||||
|
'Event type should dataavailable');
|
||||||
|
ok(evt.data.size > 0,
|
||||||
|
'Blob data received should be greater than zero');
|
||||||
|
is(evt.data.type, expectedMimeType,
|
||||||
|
'Blob data received should have type = ' + expectedMimeType);
|
||||||
|
|
||||||
|
is(mediaRecorder.mimeType, expectedMimeType,
|
||||||
|
'Mime type in ondataavailable = ' + expectedMimeType);
|
||||||
|
|
||||||
|
// onstop should not have fired before ondataavailable
|
||||||
|
if (onStopFired) {
|
||||||
|
ok(false, 'ondataavailable unexpectedly fired later than onstop');
|
||||||
|
manager.finished(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
element.oncanplaythrough = function () {
|
||||||
|
// If content has ended, skip the test
|
||||||
|
if (element.ended) {
|
||||||
|
ok(true, 'ended fired before canplaythrough, skipping test');
|
||||||
|
manager.finished(token);
|
||||||
|
} else {
|
||||||
|
// If content hasn't ended, start recording
|
||||||
|
mediaRecorder.start();
|
||||||
|
is(mediaRecorder.state, 'recording',
|
||||||
|
'Media recorder should be recording');
|
||||||
|
is(mediaRecorder.stream, element.stream,
|
||||||
|
'Media recorder stream = element stream at the start of recording');
|
||||||
|
|
||||||
|
// When ended fires, stop recording
|
||||||
|
element.onended = function () {
|
||||||
|
mediaRecorder.stop();
|
||||||
|
is(mediaRecorder.state, 'inactive',
|
||||||
|
'Media recorder is inactive afer being stopped');
|
||||||
|
is(mediaRecorder.stream, element.stream,
|
||||||
|
'Media recorder stream = element stream post recording');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.runTests(gMediaRecorderTests, startTest);
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1694,6 +1694,16 @@ nsDOMWindowUtils::FindElementWithViewId(nsViewID aID,
|
|||||||
return content ? CallQueryInterface(content, aResult) : NS_OK;
|
return content ? CallQueryInterface(content, aResult) : NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsDOMWindowUtils::GetViewId(nsIDOMElement* aElement, nsViewID* aResult)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
||||||
|
if (content && nsLayoutUtils::FindIDFor(content, aResult)) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::GetScreenPixelsPerCSSPixel(float* aScreenPixels)
|
nsDOMWindowUtils::GetScreenPixelsPerCSSPixel(float* aScreenPixels)
|
||||||
{
|
{
|
||||||
|
@ -108,10 +108,6 @@ EXPORTS_GENERATED_DEST := $(DIST)/include/$(binding_include_path)
|
|||||||
EXPORTS_GENERATED_TARGET := export
|
EXPORTS_GENERATED_TARGET := export
|
||||||
INSTALL_TARGETS += EXPORTS_GENERATED
|
INSTALL_TARGETS += EXPORTS_GENERATED
|
||||||
|
|
||||||
ifdef GNU_CC
|
|
||||||
CXXFLAGS += -Wno-uninitialized
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Install auto-generated GlobalGen files. The rules for the install must
|
# Install auto-generated GlobalGen files. The rules for the install must
|
||||||
# be in the same target/subtier as GlobalGen.py, otherwise the files will not
|
# be in the same target/subtier as GlobalGen.py, otherwise the files will not
|
||||||
# get installed into the appropriate location as they are generated.
|
# get installed into the appropriate location as they are generated.
|
||||||
@ -128,6 +124,10 @@ INSTALL_TARGETS += globalgen_headers
|
|||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||||
|
|
||||||
|
ifdef GNU_CC
|
||||||
|
CXXFLAGS += -Wno-uninitialized
|
||||||
|
endif
|
||||||
|
|
||||||
# If you change bindinggen_dependencies here, change it in
|
# If you change bindinggen_dependencies here, change it in
|
||||||
# dom/bindings/test/Makefile.in too.
|
# dom/bindings/test/Makefile.in too.
|
||||||
bindinggen_dependencies := \
|
bindinggen_dependencies := \
|
||||||
|
@ -42,7 +42,7 @@ interface nsIURI;
|
|||||||
interface nsIDOMEventTarget;
|
interface nsIDOMEventTarget;
|
||||||
interface nsIRunnable;
|
interface nsIRunnable;
|
||||||
|
|
||||||
[scriptable, uuid(ff1cec22-b183-40d3-8b42-b81a2f0ba4e6)]
|
[scriptable, uuid(d6e733ef-492b-4e67-b723-28571c2959f0)]
|
||||||
interface nsIDOMWindowUtils : nsISupports {
|
interface nsIDOMWindowUtils : nsISupports {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1177,6 +1177,12 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||||||
*/
|
*/
|
||||||
nsIDOMElement findElementWithViewId(in nsViewID aId);
|
nsIDOMElement findElementWithViewId(in nsViewID aId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the view ID for a given element. This is the reverse of
|
||||||
|
* findElementWithViewId().
|
||||||
|
*/
|
||||||
|
nsViewID getViewId(in nsIDOMElement aElement);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the layer tree for this window and returns true
|
* Checks the layer tree for this window and returns true
|
||||||
* if all layers have transforms that are translations by integers,
|
* if all layers have transforms that are translations by integers,
|
||||||
|
@ -129,6 +129,10 @@ expandAction = expanded
|
|||||||
activateAction = activated
|
activateAction = activated
|
||||||
cycleAction = cycled
|
cycleAction = cycled
|
||||||
|
|
||||||
|
# Live regions
|
||||||
|
# 'hidden' will be spoken when something disappears in a live region.
|
||||||
|
hidden = hidden
|
||||||
|
|
||||||
# Tab states
|
# Tab states
|
||||||
tabLoading = loading
|
tabLoading = loading
|
||||||
tabLoaded = loaded
|
tabLoaded = loaded
|
||||||
|
@ -1147,30 +1147,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
|||||||
bool isDefault = mFrameMetrics.IsDefault();
|
bool isDefault = mFrameMetrics.IsDefault();
|
||||||
mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
|
mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
|
||||||
|
|
||||||
// TODO: Once a mechanism for calling UpdateScrollOffset() when content does
|
|
||||||
// a scrollTo() is implemented for metro (bug 898580), this block can be removed.
|
|
||||||
#ifdef MOZ_METRO
|
|
||||||
if (!mPaintThrottler.IsOutstanding()) {
|
|
||||||
// No paint was requested, but we got one anyways. One possible cause of this
|
|
||||||
// is that content could have fired a scrollTo(). In this case, we should take
|
|
||||||
// the new scroll offset. Document/viewport changes are handled elsewhere.
|
|
||||||
// Also note that, since NotifyLayersUpdated() is called whenever there's a
|
|
||||||
// layers update, we didn't necessarily get a new scroll offset, but we're
|
|
||||||
// updating our local copy of it anyways just in case.
|
|
||||||
switch (mState) {
|
|
||||||
case NOTHING:
|
|
||||||
case FLING:
|
|
||||||
case TOUCHING:
|
|
||||||
case WAITING_LISTENERS:
|
|
||||||
mFrameMetrics.mScrollOffset = aLayerMetrics.mScrollOffset;
|
|
||||||
break;
|
|
||||||
// Don't clobber if we're in other states.
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mPaintThrottler.TaskComplete(GetFrameTime());
|
mPaintThrottler.TaskComplete(GetFrameTime());
|
||||||
bool needContentRepaint = false;
|
bool needContentRepaint = false;
|
||||||
if (aLayerMetrics.mCompositionBounds.width == mFrameMetrics.mCompositionBounds.width &&
|
if (aLayerMetrics.mCompositionBounds.width == mFrameMetrics.mCompositionBounds.width &&
|
||||||
|
@ -78,7 +78,7 @@ nsUTF16ToUnicodeBase::UTF16ConvertToUnicode(const char * aSrc,
|
|||||||
// previous run while the 2nd byte has to come from |*src|.
|
// previous run while the 2nd byte has to come from |*src|.
|
||||||
mState = STATE_NORMAL;
|
mState = STATE_NORMAL;
|
||||||
#ifdef IS_BIG_ENDIAN
|
#ifdef IS_BIG_ENDIAN
|
||||||
u = (mOddByte << 8) | *src++; // safe, we know we have at least one byte.
|
u = (mOddByte << 8) | uint8_t(*src++); // safe, we know we have at least one byte.
|
||||||
#else
|
#else
|
||||||
u = (*src++ << 8) | mOddByte; // safe, we know we have at least one byte.
|
u = (*src++ << 8) | mOddByte; // safe, we know we have at least one byte.
|
||||||
#endif
|
#endif
|
||||||
|
@ -1629,7 +1629,10 @@ ia64*-hpux*)
|
|||||||
XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
||||||
LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
LIBXUL_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xul.lib $(LIBXUL_DIST)/lib/mozalloc.lib'
|
||||||
MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)'
|
MOZ_COMPONENT_NSPR_LIBS='$(NSPR_LIBS)'
|
||||||
LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT -RELEASE"
|
LDFLAGS="$LDFLAGS -LARGEADDRESSAWARE -NXCOMPAT"
|
||||||
|
if test -z "$DEVELOPER_OPTIONS"; then
|
||||||
|
LDFLAGS="$LDFLAGS -RELEASE"
|
||||||
|
fi
|
||||||
dnl For profile-guided optimization
|
dnl For profile-guided optimization
|
||||||
PROFILE_GEN_CFLAGS="-GL"
|
PROFILE_GEN_CFLAGS="-GL"
|
||||||
PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
|
PROFILE_GEN_LDFLAGS="-LTCG:PGINSTRUMENT"
|
||||||
|
@ -69,7 +69,7 @@ CheckArgumentsWithinEval(JSContext *cx, Parser<FullParseHandler> &parser, Handle
|
|||||||
}
|
}
|
||||||
|
|
||||||
// It's an error to use |arguments| in a legacy generator expression.
|
// It's an error to use |arguments| in a legacy generator expression.
|
||||||
if (script->isGeneratorExp && script->isLegacyGenerator) {
|
if (script->isGeneratorExp && script->isLegacyGenerator()) {
|
||||||
parser.report(ParseError, false, NULL, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
|
parser.report(ParseError, false, NULL, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -294,7 +294,8 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
|
|||||||
*/
|
*/
|
||||||
JSFunction *fun = evalCaller->functionOrCallerFunction();
|
JSFunction *fun = evalCaller->functionOrCallerFunction();
|
||||||
Directives directives(/* strict = */ fun->strict());
|
Directives directives(/* strict = */ fun->strict());
|
||||||
ObjectBox *funbox = parser.newFunctionBox(/* fn = */ NULL, fun, pc.addr(), directives);
|
ObjectBox *funbox = parser.newFunctionBox(/* fn = */ NULL, fun, pc.addr(),
|
||||||
|
directives, fun->generatorKind());
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return NULL;
|
return NULL;
|
||||||
bce.objectList.add(funbox);
|
bce.objectList.add(funbox);
|
||||||
@ -414,7 +415,9 @@ frontend::CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *cha
|
|||||||
uint32_t staticLevel = lazy->staticLevel(cx);
|
uint32_t staticLevel = lazy->staticLevel(cx);
|
||||||
|
|
||||||
Rooted<JSFunction*> fun(cx, lazy->function());
|
Rooted<JSFunction*> fun(cx, lazy->function());
|
||||||
ParseNode *pn = parser.standaloneLazyFunction(fun, staticLevel, lazy->strict());
|
JS_ASSERT(!lazy->isLegacyGenerator());
|
||||||
|
ParseNode *pn = parser.standaloneLazyFunction(fun, staticLevel, lazy->strict(),
|
||||||
|
lazy->generatorKind());
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -518,7 +521,7 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
|
|||||||
ParseNode *fn;
|
ParseNode *fn;
|
||||||
while (true) {
|
while (true) {
|
||||||
Directives newDirectives = directives;
|
Directives newDirectives = directives;
|
||||||
fn = parser.standaloneFunctionBody(fun, formals, directives, &newDirectives);
|
fn = parser.standaloneFunctionBody(fun, formals, NotGenerator, directives, &newDirectives);
|
||||||
if (fn)
|
if (fn)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -384,9 +384,9 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
|
|||||||
if (pn->getKind() == PNK_MODULE) {
|
if (pn->getKind() == PNK_MODULE) {
|
||||||
MOZ_ASSUME_UNREACHABLE("module nodes cannot be cloned");
|
MOZ_ASSUME_UNREACHABLE("module nodes cannot be cloned");
|
||||||
}
|
}
|
||||||
NULLCHECK(pn->pn_funbox =
|
NULLCHECK(pn->pn_funbox = newFunctionBox(pn, opn->pn_funbox->function(), pc,
|
||||||
newFunctionBox(pn, opn->pn_funbox->function(), pc,
|
Directives(/* strict = */ opn->pn_funbox->strict),
|
||||||
Directives(/* strict = */ opn->pn_funbox->strict)));
|
opn->pn_funbox->generatorKind()));
|
||||||
NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body));
|
NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body));
|
||||||
pn->pn_cookie = opn->pn_cookie;
|
pn->pn_cookie = opn->pn_cookie;
|
||||||
pn->pn_dflags = opn->pn_dflags;
|
pn->pn_dflags = opn->pn_dflags;
|
||||||
|
@ -56,7 +56,6 @@ namespace frontend {
|
|||||||
typedef Rooted<StaticBlockObject*> RootedStaticBlockObject;
|
typedef Rooted<StaticBlockObject*> RootedStaticBlockObject;
|
||||||
typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
|
typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
|
||||||
|
|
||||||
typedef MutableHandle<PropertyName*> MutableHandlePropertyName;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insist that the next token be of type tt, or report errno and return null.
|
* Insist that the next token be of type tt, or report errno and return null.
|
||||||
@ -466,13 +465,14 @@ Parser<ParseHandler>::newObjectBox(JSObject *obj)
|
|||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
|
FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
|
||||||
ParseContext<ParseHandler> *outerpc, Directives directives,
|
ParseContext<ParseHandler> *outerpc, Directives directives,
|
||||||
bool extraWarnings)
|
bool extraWarnings, GeneratorKind generatorKind)
|
||||||
: ObjectBox(fun, traceListHead),
|
: ObjectBox(fun, traceListHead),
|
||||||
SharedContext(cx, directives, extraWarnings),
|
SharedContext(cx, directives, extraWarnings),
|
||||||
bindings(),
|
bindings(),
|
||||||
bufStart(0),
|
bufStart(0),
|
||||||
bufEnd(0),
|
bufEnd(0),
|
||||||
ndefaults(0),
|
ndefaults(0),
|
||||||
|
generatorKindBits_(GeneratorKindAsBits(generatorKind)),
|
||||||
inWith(false), // initialized below
|
inWith(false), // initialized below
|
||||||
inGenexpLambda(false),
|
inGenexpLambda(false),
|
||||||
hasDestructuringArgs(false),
|
hasDestructuringArgs(false),
|
||||||
@ -533,7 +533,7 @@ FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunct
|
|||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
FunctionBox *
|
FunctionBox *
|
||||||
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *outerpc,
|
Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *outerpc,
|
||||||
Directives inheritedDirectives)
|
Directives inheritedDirectives, GeneratorKind generatorKind)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fun && !IsPoisonedPtr(fun));
|
JS_ASSERT(fun && !IsPoisonedPtr(fun));
|
||||||
|
|
||||||
@ -546,7 +546,8 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction *fun, ParseContext<Pars
|
|||||||
*/
|
*/
|
||||||
FunctionBox *funbox =
|
FunctionBox *funbox =
|
||||||
alloc.new_<FunctionBox>(context, traceListHead, fun, outerpc,
|
alloc.new_<FunctionBox>(context, traceListHead, fun, outerpc,
|
||||||
inheritedDirectives, options().extraWarningsOption);
|
inheritedDirectives, options().extraWarningsOption,
|
||||||
|
generatorKind);
|
||||||
if (!funbox) {
|
if (!funbox) {
|
||||||
js_ReportOutOfMemory(context);
|
js_ReportOutOfMemory(context);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -863,6 +864,7 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName *name, Node pn)
|
|||||||
template <>
|
template <>
|
||||||
ParseNode *
|
ParseNode *
|
||||||
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
|
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
|
||||||
|
GeneratorKind generatorKind,
|
||||||
Directives inheritedDirectives,
|
Directives inheritedDirectives,
|
||||||
Directives *newDirectives)
|
Directives *newDirectives)
|
||||||
{
|
{
|
||||||
@ -877,7 +879,8 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
|
|||||||
argsbody->makeEmpty();
|
argsbody->makeEmpty();
|
||||||
fn->pn_body = argsbody;
|
fn->pn_body = argsbody;
|
||||||
|
|
||||||
FunctionBox *funbox = newFunctionBox(fn, fun, /* outerpc = */ NULL, inheritedDirectives);
|
FunctionBox *funbox = newFunctionBox(fn, fun, /* outerpc = */ NULL, inheritedDirectives,
|
||||||
|
generatorKind);
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return null();
|
return null();
|
||||||
handler.setFunctionBox(fn, funbox);
|
handler.setFunctionBox(fn, funbox);
|
||||||
@ -1062,7 +1065,9 @@ Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ
|
|||||||
JS_ASSERT(pc->sc->isFunctionBox());
|
JS_ASSERT(pc->sc->isFunctionBox());
|
||||||
JS_ASSERT(!pc->funHasReturnExpr && !pc->funHasReturnVoid);
|
JS_ASSERT(!pc->funHasReturnExpr && !pc->funHasReturnVoid);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
uint32_t startYieldOffset = pc->lastYieldOffset;
|
uint32_t startYieldOffset = pc->lastYieldOffset;
|
||||||
|
#endif
|
||||||
|
|
||||||
Node pn;
|
Node pn;
|
||||||
if (type == StatementListBody) {
|
if (type == StatementListBody) {
|
||||||
@ -1082,8 +1087,14 @@ Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ
|
|||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pc->lastYieldOffset != startYieldOffset) {
|
switch (pc->generatorKind()) {
|
||||||
JS_ASSERT(pc->isLegacyGenerator());
|
case NotGenerator:
|
||||||
|
JS_ASSERT(pc->lastYieldOffset == startYieldOffset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LegacyGenerator:
|
||||||
|
// FIXME: Catch these errors eagerly, in yieldExpression().
|
||||||
|
JS_ASSERT(pc->lastYieldOffset != startYieldOffset);
|
||||||
if (kind == Arrow) {
|
if (kind == Arrow) {
|
||||||
reportWithOffset(ParseError, false, pc->lastYieldOffset,
|
reportWithOffset(ParseError, false, pc->lastYieldOffset,
|
||||||
JSMSG_YIELD_IN_ARROW, js_yield_str);
|
JSMSG_YIELD_IN_ARROW, js_yield_str);
|
||||||
@ -1095,9 +1106,12 @@ Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ
|
|||||||
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
pc->sc->asFunctionBox()->setIsLegacyGenerator();
|
break;
|
||||||
} else {
|
|
||||||
JS_ASSERT(!pc->isLegacyGenerator());
|
case StarGenerator:
|
||||||
|
JS_ASSERT(kind != Arrow);
|
||||||
|
JS_ASSERT(type == StatementListBody);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for falling off the end of a function that returns a value. */
|
/* Check for falling off the end of a function that returns a value. */
|
||||||
@ -1627,6 +1641,11 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
|
|||||||
}
|
}
|
||||||
#endif /* JS_HAS_DESTRUCTURING */
|
#endif /* JS_HAS_DESTRUCTURING */
|
||||||
|
|
||||||
|
case TOK_YIELD:
|
||||||
|
if (!checkYieldNameValidity(JSMSG_MISSING_FORMAL))
|
||||||
|
return false;
|
||||||
|
goto TOK_NAME;
|
||||||
|
|
||||||
case TOK_TRIPLEDOT:
|
case TOK_TRIPLEDOT:
|
||||||
{
|
{
|
||||||
hasRest = true;
|
hasRest = true;
|
||||||
@ -1636,15 +1655,16 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
|
|||||||
report(ParseError, false, null(), JSMSG_NO_REST_NAME);
|
report(ParseError, false, null(), JSMSG_NO_REST_NAME);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Fall through */
|
goto TOK_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOK_NAME:
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
{
|
{
|
||||||
if (parenFreeArrow)
|
if (parenFreeArrow)
|
||||||
funbox->setStart(tokenStream);
|
funbox->setStart(tokenStream);
|
||||||
|
|
||||||
RootedPropertyName name(context, tokenStream.currentToken().name());
|
RootedPropertyName name(context, tokenStream.currentName());
|
||||||
bool disallowDuplicateArgs = funbox->hasDestructuringArgs || hasDefaults;
|
bool disallowDuplicateArgs = funbox->hasDestructuringArgs || hasDefaults;
|
||||||
if (!defineArg(funcpn, name, disallowDuplicateArgs, &duplicatedArg))
|
if (!defineArg(funcpn, name, disallowDuplicateArgs, &duplicatedArg))
|
||||||
return false;
|
return false;
|
||||||
@ -1695,6 +1715,20 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ParseHandler>
|
||||||
|
bool
|
||||||
|
Parser<ParseHandler>::checkFunctionName(HandlePropertyName funName)
|
||||||
|
{
|
||||||
|
if (pc->isStarGenerator() && funName == context->names().yield) {
|
||||||
|
// The name of a named function expression is specified to be bound in
|
||||||
|
// the outer context as if via "let". In an ES6 generator, "yield" is
|
||||||
|
// not a valid name for a let-bound variable.
|
||||||
|
report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool
|
bool
|
||||||
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
||||||
@ -1707,6 +1741,9 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
|||||||
/* Function statements add a binding to the enclosing scope. */
|
/* Function statements add a binding to the enclosing scope. */
|
||||||
bool bodyLevel = pc->atBodyLevel();
|
bool bodyLevel = pc->atBodyLevel();
|
||||||
|
|
||||||
|
if (!checkFunctionName(funName))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (kind == Statement) {
|
if (kind == Statement) {
|
||||||
/*
|
/*
|
||||||
* Handle redeclaration and optimize cases where we can statically bind the
|
* Handle redeclaration and optimize cases where we can statically bind the
|
||||||
@ -1820,7 +1857,9 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
|||||||
// so we can skip over them after accounting for their free variables.
|
// so we can skip over them after accounting for their free variables.
|
||||||
if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
|
if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
|
||||||
JSFunction *fun = handler.nextLazyInnerFunction();
|
JSFunction *fun = handler.nextLazyInnerFunction();
|
||||||
FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false));
|
JS_ASSERT(!fun->isLegacyGenerator());
|
||||||
|
FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false),
|
||||||
|
fun->generatorKind());
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1896,6 +1935,9 @@ Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
|||||||
/* Function statements add a binding to the enclosing scope. */
|
/* Function statements add a binding to the enclosing scope. */
|
||||||
bool bodyLevel = pc->atBodyLevel();
|
bool bodyLevel = pc->atBodyLevel();
|
||||||
|
|
||||||
|
if (!checkFunctionName(funName))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (kind == Statement) {
|
if (kind == Statement) {
|
||||||
/*
|
/*
|
||||||
* Handle redeclaration and optimize cases where we can statically bind the
|
* Handle redeclaration and optimize cases where we can statically bind the
|
||||||
@ -1934,7 +1976,8 @@ Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
|||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream::Position &start,
|
Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream::Position &start,
|
||||||
FunctionType type, FunctionSyntaxKind kind)
|
FunctionType type, FunctionSyntaxKind kind,
|
||||||
|
GeneratorKind generatorKind)
|
||||||
{
|
{
|
||||||
JS_ASSERT_IF(kind == Statement, funName);
|
JS_ASSERT_IF(kind == Statement, funName);
|
||||||
|
|
||||||
@ -1962,7 +2005,7 @@ Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream:
|
|||||||
Directives newDirectives = directives;
|
Directives newDirectives = directives;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (functionArgsAndBody(pn, fun, type, kind, directives, &newDirectives))
|
if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives))
|
||||||
break;
|
break;
|
||||||
if (tokenStream.hadError() || directives == newDirectives)
|
if (tokenStream.hadError() || directives == newDirectives)
|
||||||
return null();
|
return null();
|
||||||
@ -2066,6 +2109,7 @@ Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox *funbo
|
|||||||
|
|
||||||
if (pc->sc->strict)
|
if (pc->sc->strict)
|
||||||
lazy->setStrict();
|
lazy->setStrict();
|
||||||
|
lazy->setGeneratorKind(funbox->generatorKind());
|
||||||
if (funbox->usesArguments && funbox->usesApply)
|
if (funbox->usesArguments && funbox->usesApply)
|
||||||
lazy->setUsesArgumentsAndApply();
|
lazy->setUsesArgumentsAndApply();
|
||||||
PropagateTransitiveParseFlags(funbox, lazy);
|
PropagateTransitiveParseFlags(funbox, lazy);
|
||||||
@ -2078,13 +2122,14 @@ template <>
|
|||||||
bool
|
bool
|
||||||
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
||||||
FunctionType type, FunctionSyntaxKind kind,
|
FunctionType type, FunctionSyntaxKind kind,
|
||||||
|
GeneratorKind generatorKind,
|
||||||
Directives inheritedDirectives,
|
Directives inheritedDirectives,
|
||||||
Directives *newDirectives)
|
Directives *newDirectives)
|
||||||
{
|
{
|
||||||
ParseContext<FullParseHandler> *outerpc = pc;
|
ParseContext<FullParseHandler> *outerpc = pc;
|
||||||
|
|
||||||
// Create box for fun->object early to protect against last-ditch GC.
|
// Create box for fun->object early to protect against last-ditch GC.
|
||||||
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives);
|
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -2160,13 +2205,14 @@ template <>
|
|||||||
bool
|
bool
|
||||||
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
|
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
|
||||||
FunctionType type, FunctionSyntaxKind kind,
|
FunctionType type, FunctionSyntaxKind kind,
|
||||||
|
GeneratorKind generatorKind,
|
||||||
Directives inheritedDirectives,
|
Directives inheritedDirectives,
|
||||||
Directives *newDirectives)
|
Directives *newDirectives)
|
||||||
{
|
{
|
||||||
ParseContext<SyntaxParseHandler> *outerpc = pc;
|
ParseContext<SyntaxParseHandler> *outerpc = pc;
|
||||||
|
|
||||||
// Create box for fun->object early to protect against last-ditch GC.
|
// Create box for fun->object early to protect against last-ditch GC.
|
||||||
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives);
|
FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -2192,14 +2238,15 @@ Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
|
|||||||
template <>
|
template <>
|
||||||
ParseNode *
|
ParseNode *
|
||||||
Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned staticLevel,
|
Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned staticLevel,
|
||||||
bool strict)
|
bool strict, GeneratorKind generatorKind)
|
||||||
{
|
{
|
||||||
Node pn = handler.newFunctionDefinition();
|
Node pn = handler.newFunctionDefinition();
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
Directives directives(/* strict = */ strict);
|
Directives directives(/* strict = */ strict);
|
||||||
FunctionBox *funbox = newFunctionBox(pn, fun, /* outerpc = */ NULL, directives);
|
FunctionBox *funbox = newFunctionBox(pn, fun, /* outerpc = */ NULL, directives,
|
||||||
|
generatorKind);
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
@ -2273,6 +2320,10 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, Fu
|
|||||||
// Parse the function body.
|
// Parse the function body.
|
||||||
FunctionBodyType bodyType = StatementListBody;
|
FunctionBodyType bodyType = StatementListBody;
|
||||||
if (tokenStream.getToken(TokenStream::Operand) != TOK_LC) {
|
if (tokenStream.getToken(TokenStream::Operand) != TOK_LC) {
|
||||||
|
if (funbox->isStarGenerator()) {
|
||||||
|
report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
tokenStream.ungetToken();
|
tokenStream.ungetToken();
|
||||||
bodyType = ExpressionBody;
|
bodyType = ExpressionBody;
|
||||||
fun->setIsExprClosure();
|
fun->setIsExprClosure();
|
||||||
@ -2310,7 +2361,7 @@ template <>
|
|||||||
ParseNode *
|
ParseNode *
|
||||||
Parser<FullParseHandler>::moduleDecl()
|
Parser<FullParseHandler>::moduleDecl()
|
||||||
{
|
{
|
||||||
JS_ASSERT(tokenStream.currentToken().name() == context->names().module);
|
JS_ASSERT(tokenStream.currentName() == context->names().module);
|
||||||
if (!((pc->sc->isGlobalSharedContext() || pc->sc->isModuleBox()) && pc->atBodyLevel()))
|
if (!((pc->sc->isGlobalSharedContext() || pc->sc->isModuleBox()) && pc->atBodyLevel()))
|
||||||
{
|
{
|
||||||
report(ParseError, false, NULL, JSMSG_MODULE_STATEMENT);
|
report(ParseError, false, NULL, JSMSG_MODULE_STATEMENT);
|
||||||
@ -2352,18 +2403,44 @@ Parser<SyntaxParseHandler>::moduleDecl()
|
|||||||
return SyntaxParseHandler::NodeFailure;
|
return SyntaxParseHandler::NodeFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ParseHandler>
|
||||||
|
bool
|
||||||
|
Parser<ParseHandler>::checkYieldNameValidity(unsigned errorNumber)
|
||||||
|
{
|
||||||
|
// In star generators and in JS >= 1.7, yield is a keyword.
|
||||||
|
if (pc->isStarGenerator() || versionNumber() >= JSVERSION_1_7) {
|
||||||
|
report(ParseError, false, null(), errorNumber);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Otherwise in strict mode, yield is a future reserved word.
|
||||||
|
if (pc->sc->strict) {
|
||||||
|
report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::functionStmt()
|
Parser<ParseHandler>::functionStmt()
|
||||||
{
|
{
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_FUNCTION);
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||||
|
|
||||||
TokenStream::Position start(keepAtoms);
|
TokenStream::Position start(keepAtoms);
|
||||||
tokenStream.tell(&start);
|
tokenStream.tell(&start);
|
||||||
|
|
||||||
RootedPropertyName name(context);
|
RootedPropertyName name(context);
|
||||||
if (tokenStream.getToken(TokenStream::KeywordIsName) == TOK_NAME) {
|
GeneratorKind generatorKind = NotGenerator;
|
||||||
name = tokenStream.currentToken().name();
|
TokenKind tt = tokenStream.getToken(TokenStream::KeywordIsName);
|
||||||
|
|
||||||
|
if (tt == TOK_MUL) {
|
||||||
|
tokenStream.tell(&start);
|
||||||
|
tt = tokenStream.getToken(TokenStream::KeywordIsName);
|
||||||
|
generatorKind = StarGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tt == TOK_NAME) {
|
||||||
|
name = tokenStream.currentName();
|
||||||
} else {
|
} else {
|
||||||
/* Unnamed function expressions are forbidden in statement context. */
|
/* Unnamed function expressions are forbidden in statement context. */
|
||||||
report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT);
|
report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT);
|
||||||
@ -2375,22 +2452,34 @@ Parser<ParseHandler>::functionStmt()
|
|||||||
!report(ParseStrictError, pc->sc->strict, null(), JSMSG_STRICT_FUNCTION_STATEMENT))
|
!report(ParseStrictError, pc->sc->strict, null(), JSMSG_STRICT_FUNCTION_STATEMENT))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
return functionDef(name, start, Normal, Statement);
|
return functionDef(name, start, Normal, Statement, generatorKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::functionExpr()
|
Parser<ParseHandler>::functionExpr()
|
||||||
{
|
{
|
||||||
RootedPropertyName name(context);
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_FUNCTION);
|
|
||||||
TokenStream::Position start(keepAtoms);
|
TokenStream::Position start(keepAtoms);
|
||||||
tokenStream.tell(&start);
|
tokenStream.tell(&start);
|
||||||
if (tokenStream.getToken(TokenStream::KeywordIsName) == TOK_NAME)
|
|
||||||
name = tokenStream.currentToken().name();
|
RootedPropertyName name(context);
|
||||||
|
GeneratorKind generatorKind = NotGenerator;
|
||||||
|
TokenKind tt = tokenStream.getToken(TokenStream::KeywordIsName);
|
||||||
|
|
||||||
|
if (tt == TOK_MUL) {
|
||||||
|
tokenStream.tell(&start);
|
||||||
|
tt = tokenStream.getToken(TokenStream::KeywordIsName);
|
||||||
|
generatorKind = StarGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tt == TOK_NAME)
|
||||||
|
name = tokenStream.currentName();
|
||||||
else
|
else
|
||||||
tokenStream.ungetToken();
|
tokenStream.ungetToken();
|
||||||
return functionDef(name, start, Normal, Expression);
|
|
||||||
|
return functionDef(name, start, Normal, Expression, generatorKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2524,7 +2613,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool *cont)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (directive == context->names().useAsm) {
|
} else if (directive == context->names().useAsm) {
|
||||||
if (pc->sc->isFunctionBox())
|
if (pc->sc->isFunctionBox() && !pc->isGenerator())
|
||||||
return asmJS(list);
|
return asmJS(list);
|
||||||
return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL);
|
return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL);
|
||||||
}
|
}
|
||||||
@ -2606,15 +2695,21 @@ Parser<ParseHandler>::condition()
|
|||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
template <typename ParseHandler>
|
||||||
MatchLabel(TokenStream &ts, MutableHandlePropertyName label)
|
bool
|
||||||
|
Parser<ParseHandler>::matchLabel(MutableHandle<PropertyName*> label)
|
||||||
{
|
{
|
||||||
TokenKind tt = ts.peekTokenSameLine(TokenStream::Operand);
|
TokenKind tt = tokenStream.peekTokenSameLine(TokenStream::Operand);
|
||||||
if (tt == TOK_ERROR)
|
if (tt == TOK_ERROR)
|
||||||
return false;
|
return false;
|
||||||
if (tt == TOK_NAME) {
|
if (tt == TOK_NAME) {
|
||||||
(void) ts.getToken();
|
tokenStream.consumeKnownToken(TOK_NAME);
|
||||||
label.set(ts.currentToken().name());
|
label.set(tokenStream.currentName());
|
||||||
|
} else if (tt == TOK_YIELD) {
|
||||||
|
tokenStream.consumeKnownToken(TOK_YIELD);
|
||||||
|
if (!checkYieldNameValidity())
|
||||||
|
return false;
|
||||||
|
label.set(tokenStream.currentName());
|
||||||
} else {
|
} else {
|
||||||
label.set(NULL);
|
label.set(NULL);
|
||||||
}
|
}
|
||||||
@ -3240,7 +3335,7 @@ template <typename ParseHandler>
|
|||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::letBlock(LetContext letContext)
|
Parser<ParseHandler>::letBlock(LetContext letContext)
|
||||||
{
|
{
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_LET);
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LET));
|
||||||
|
|
||||||
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
|
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
|
||||||
if (!blockObj)
|
if (!blockObj)
|
||||||
@ -3330,7 +3425,7 @@ template <typename ParseHandler>
|
|||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::blockStatement()
|
Parser<ParseHandler>::blockStatement()
|
||||||
{
|
{
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_LC);
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
|
||||||
|
|
||||||
StmtInfoPC stmtInfo(context);
|
StmtInfoPC stmtInfo(context);
|
||||||
if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, pc))
|
if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, pc))
|
||||||
@ -3372,7 +3467,6 @@ Parser<ParseHandler>::newBindingNode(PropertyName *name, bool functionScope, Var
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make a new node for this declarator name (or destructuring pattern). */
|
/* Make a new node for this declarator name (or destructuring pattern). */
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_NAME);
|
|
||||||
return newName(name);
|
return newName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3461,12 +3555,17 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
|
|||||||
#endif /* JS_HAS_DESTRUCTURING */
|
#endif /* JS_HAS_DESTRUCTURING */
|
||||||
|
|
||||||
if (tt != TOK_NAME) {
|
if (tt != TOK_NAME) {
|
||||||
if (tt != TOK_ERROR)
|
if (tt == TOK_YIELD) {
|
||||||
report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
|
if (!checkYieldNameValidity(JSMSG_NO_VARIABLE_NAME))
|
||||||
return null();
|
return null();
|
||||||
|
} else {
|
||||||
|
if (tt != TOK_ERROR)
|
||||||
|
report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedPropertyName name(context, tokenStream.currentToken().name());
|
RootedPropertyName name(context, tokenStream.currentName());
|
||||||
pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext);
|
pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext);
|
||||||
if (!pn2)
|
if (!pn2)
|
||||||
return null();
|
return null();
|
||||||
@ -4123,9 +4222,14 @@ Parser<SyntaxParseHandler>::forStatement()
|
|||||||
PushStatementPC(pc, &forStmt, STMT_FOR_LOOP);
|
PushStatementPC(pc, &forStmt, STMT_FOR_LOOP);
|
||||||
|
|
||||||
/* Don't parse 'for each' loops. */
|
/* Don't parse 'for each' loops. */
|
||||||
if (allowsForEachIn() && tokenStream.peekToken() == TOK_NAME) {
|
if (allowsForEachIn()) {
|
||||||
JS_ALWAYS_FALSE(abortIfSyntaxParser());
|
TokenKind tt = tokenStream.peekToken();
|
||||||
return null();
|
// Not all "yield" tokens are names, but the ones that aren't names are
|
||||||
|
// invalid in this context anyway.
|
||||||
|
if (tt == TOK_NAME || tt == TOK_YIELD) {
|
||||||
|
JS_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||||
|
return null();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||||
@ -4327,7 +4431,7 @@ Parser<ParseHandler>::continueStatement()
|
|||||||
uint32_t begin = pos().begin;
|
uint32_t begin = pos().begin;
|
||||||
|
|
||||||
RootedPropertyName label(context);
|
RootedPropertyName label(context);
|
||||||
if (!MatchLabel(tokenStream, &label))
|
if (!matchLabel(&label))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
StmtInfoPC *stmt = pc->topStmt;
|
StmtInfoPC *stmt = pc->topStmt;
|
||||||
@ -4374,7 +4478,7 @@ Parser<ParseHandler>::breakStatement()
|
|||||||
uint32_t begin = pos().begin;
|
uint32_t begin = pos().begin;
|
||||||
|
|
||||||
RootedPropertyName label(context);
|
RootedPropertyName label(context);
|
||||||
if (!MatchLabel(tokenStream, &label))
|
if (!matchLabel(&label))
|
||||||
return null();
|
return null();
|
||||||
StmtInfoPC *stmt = pc->topStmt;
|
StmtInfoPC *stmt = pc->topStmt;
|
||||||
if (label) {
|
if (label) {
|
||||||
@ -4405,98 +4509,45 @@ Parser<ParseHandler>::breakStatement()
|
|||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::returnStatementOrYieldExpression()
|
Parser<ParseHandler>::returnStatement()
|
||||||
{
|
{
|
||||||
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_RETURN) ||
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_RETURN));
|
||||||
tokenStream.isCurrentTokenType(TOK_YIELD));
|
|
||||||
bool isYield = tokenStream.isCurrentTokenType(TOK_YIELD);
|
|
||||||
uint32_t begin = pos().begin;
|
uint32_t begin = pos().begin;
|
||||||
|
|
||||||
if (!pc->sc->isFunctionBox()) {
|
if (!pc->sc->isFunctionBox()) {
|
||||||
report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD,
|
report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
|
||||||
isYield ? js_yield_str : js_return_str);
|
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legacy generators are identified by the presence of "yield" in their
|
|
||||||
// bodies. We only see "yield" as TOK_YIELD in JS 1.7+.
|
|
||||||
if (isYield) {
|
|
||||||
JS_ASSERT(tokenStream.versionNumber() >= JSVERSION_1_7);
|
|
||||||
if (!abortIfSyntaxParser())
|
|
||||||
return null();
|
|
||||||
|
|
||||||
if (pc->isLegacyGenerator()) {
|
|
||||||
// We are in a legacy generator: a function that has already seen a
|
|
||||||
// yield.
|
|
||||||
JS_ASSERT(pc->sc->isFunctionBox());
|
|
||||||
JS_ASSERT(pc->lastYieldOffset != ParseContext<ParseHandler>::NoYieldOffset);
|
|
||||||
} else {
|
|
||||||
// We are in a code that has not seen a yield, and in JS 1.8 so
|
|
||||||
// "yield" parsed as TOK_YIELD. Try to transition to being a legacy
|
|
||||||
// generator.
|
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_YIELD);
|
|
||||||
JS_ASSERT(pc->lastYieldOffset == ParseContext<ParseHandler>::NoYieldOffset);
|
|
||||||
|
|
||||||
if (!pc->sc->isFunctionBox()) {
|
|
||||||
report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
|
|
||||||
return null();
|
|
||||||
}
|
|
||||||
|
|
||||||
pc->generatorParseMode = ParseContext<ParseHandler>::LegacyGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pc->lastYieldOffset = begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse an optional operand.
|
// Parse an optional operand.
|
||||||
//
|
//
|
||||||
// Checking whether yield has an operand is especially wonky since
|
// This is ugly, but we don't want to require a semicolon.
|
||||||
// there is not a mandatory semicolon.
|
|
||||||
//
|
|
||||||
// ES6 does not permit yield without an operand. We will have to sunset
|
|
||||||
// this extension in order to conform to the ES6 syntax, which treats
|
|
||||||
// "yield \n expr;" as a single ExpressionStatement.
|
|
||||||
Node exprNode;
|
Node exprNode;
|
||||||
TokenKind next = tokenStream.peekTokenSameLine(TokenStream::Operand);
|
switch (tokenStream.peekTokenSameLine(TokenStream::Operand)) {
|
||||||
if (next == TOK_ERROR)
|
case TOK_ERROR:
|
||||||
return null();
|
return null();
|
||||||
if (next == TOK_EOF || next == TOK_EOL || next == TOK_SEMI || next == TOK_RC ||
|
case TOK_EOF:
|
||||||
(isYield && (next == TOK_RB || next == TOK_RP || next == TOK_COLON || next == TOK_COMMA)))
|
case TOK_EOL:
|
||||||
{
|
case TOK_SEMI:
|
||||||
if (isYield) {
|
case TOK_RC:
|
||||||
if (!reportWithOffset(ParseWarning, false, pos().begin, JSMSG_YIELD_WITHOUT_OPERAND))
|
|
||||||
return null();
|
|
||||||
}
|
|
||||||
|
|
||||||
exprNode = null();
|
exprNode = null();
|
||||||
if (!isYield)
|
pc->funHasReturnVoid = true;
|
||||||
pc->funHasReturnVoid = true;
|
break;
|
||||||
} else {
|
default: {
|
||||||
exprNode = isYield ? assignExpr() : expr();
|
exprNode = expr();
|
||||||
if (!exprNode)
|
if (!exprNode)
|
||||||
return null();
|
return null();
|
||||||
if (!isYield)
|
pc->funHasReturnExpr = true;
|
||||||
pc->funHasReturnExpr = true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isYield) {
|
if (!MatchOrInsertSemicolon(tokenStream))
|
||||||
if (!MatchOrInsertSemicolon(tokenStream))
|
return null();
|
||||||
return null();
|
|
||||||
}
|
|
||||||
|
|
||||||
Node pn = isYield
|
Node pn = handler.newReturnStatement(exprNode, TokenPos(begin, pos().end));
|
||||||
? handler.newUnary(PNK_YIELD, JSOP_YIELD, begin, exprNode)
|
|
||||||
: handler.newReturnStatement(exprNode, TokenPos(begin, pos().end));
|
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
if (pc->funHasReturnExpr && pc->isLegacyGenerator()) {
|
|
||||||
/* As in Python (see PEP-255), disallow return v; in generators. */
|
|
||||||
reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN,
|
|
||||||
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
|
||||||
return null();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options().extraWarningsOption && pc->funHasReturnExpr && pc->funHasReturnVoid &&
|
if (options().extraWarningsOption && pc->funHasReturnExpr && pc->funHasReturnVoid &&
|
||||||
!reportBadReturn(pn, ParseExtraWarning,
|
!reportBadReturn(pn, ParseExtraWarning,
|
||||||
JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE))
|
JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE))
|
||||||
@ -4504,9 +4555,108 @@ Parser<ParseHandler>::returnStatementOrYieldExpression()
|
|||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pc->isLegacyGenerator() && exprNode) {
|
||||||
|
/* Disallow "return v;" in legacy generators. */
|
||||||
|
reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN,
|
||||||
|
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ParseHandler>
|
||||||
|
typename ParseHandler::Node
|
||||||
|
Parser<ParseHandler>::yieldExpression()
|
||||||
|
{
|
||||||
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_YIELD));
|
||||||
|
uint32_t begin = pos().begin;
|
||||||
|
|
||||||
|
switch (pc->generatorKind()) {
|
||||||
|
case StarGenerator:
|
||||||
|
{
|
||||||
|
JS_ASSERT(pc->sc->isFunctionBox());
|
||||||
|
|
||||||
|
pc->lastYieldOffset = begin;
|
||||||
|
|
||||||
|
bool isDelegatingYield = tokenStream.matchToken(TOK_MUL);
|
||||||
|
|
||||||
|
// ES6 generators require a value.
|
||||||
|
Node exprNode = assignExpr();
|
||||||
|
if (!exprNode)
|
||||||
|
return null();
|
||||||
|
|
||||||
|
// FIXME: Plumb isDelegatingYield appropriately.
|
||||||
|
(void) isDelegatingYield;
|
||||||
|
return handler.newUnary(PNK_YIELD, JSOP_YIELD, begin, exprNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
case NotGenerator:
|
||||||
|
// We are in code that has not seen a yield, but we are in JS 1.7 or
|
||||||
|
// later. Try to transition to being a legacy generator.
|
||||||
|
JS_ASSERT(tokenStream.versionNumber() >= JSVERSION_1_7);
|
||||||
|
JS_ASSERT(pc->lastYieldOffset == ParseContext<ParseHandler>::NoYieldOffset);
|
||||||
|
|
||||||
|
if (!abortIfSyntaxParser())
|
||||||
|
return null();
|
||||||
|
|
||||||
|
if (!pc->sc->isFunctionBox()) {
|
||||||
|
report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
|
pc->sc->asFunctionBox()->setGeneratorKind(LegacyGenerator);
|
||||||
|
|
||||||
|
if (pc->funHasReturnExpr) {
|
||||||
|
/* As in Python (see PEP-255), disallow return v; in generators. */
|
||||||
|
reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN,
|
||||||
|
JSMSG_BAD_ANON_GENERATOR_RETURN);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
// Fall through.
|
||||||
|
|
||||||
|
case LegacyGenerator:
|
||||||
|
{
|
||||||
|
// We are in a legacy generator: a function that has already seen a
|
||||||
|
// yield, or in a legacy generator comprehension.
|
||||||
|
JS_ASSERT(pc->sc->isFunctionBox());
|
||||||
|
|
||||||
|
pc->lastYieldOffset = begin;
|
||||||
|
|
||||||
|
// Legacy generators do not require a value.
|
||||||
|
Node exprNode;
|
||||||
|
switch (tokenStream.peekTokenSameLine(TokenStream::Operand)) {
|
||||||
|
case TOK_ERROR:
|
||||||
|
return null();
|
||||||
|
case TOK_EOF:
|
||||||
|
case TOK_EOL:
|
||||||
|
case TOK_SEMI:
|
||||||
|
case TOK_RC:
|
||||||
|
case TOK_RB:
|
||||||
|
case TOK_RP:
|
||||||
|
case TOK_COLON:
|
||||||
|
case TOK_COMMA:
|
||||||
|
// No value.
|
||||||
|
exprNode = null();
|
||||||
|
// ES6 does not permit yield without an operand. We should
|
||||||
|
// encourage users of yield expressions of this kind to pass an
|
||||||
|
// operand, to bring users closer to standard syntax.
|
||||||
|
if (!reportWithOffset(ParseWarning, false, pos().begin, JSMSG_YIELD_WITHOUT_OPERAND))
|
||||||
|
return null();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exprNode = assignExpr();
|
||||||
|
if (!exprNode)
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.newUnary(PNK_YIELD, JSOP_YIELD, begin, exprNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSUME_UNREACHABLE("yieldExpr");
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
ParseNode *
|
ParseNode *
|
||||||
Parser<FullParseHandler>::withStatement()
|
Parser<FullParseHandler>::withStatement()
|
||||||
@ -4576,7 +4726,7 @@ typename ParseHandler::Node
|
|||||||
Parser<ParseHandler>::labeledStatement()
|
Parser<ParseHandler>::labeledStatement()
|
||||||
{
|
{
|
||||||
uint32_t begin = pos().begin;
|
uint32_t begin = pos().begin;
|
||||||
RootedPropertyName label(context, tokenStream.currentToken().name());
|
RootedPropertyName label(context, tokenStream.currentName());
|
||||||
for (StmtInfoPC *stmt = pc->topStmt; stmt; stmt = stmt->down) {
|
for (StmtInfoPC *stmt = pc->topStmt; stmt; stmt = stmt->down) {
|
||||||
if (stmt->type == STMT_LABEL && stmt->label == label) {
|
if (stmt->type == STMT_LABEL && stmt->label == label) {
|
||||||
report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL);
|
report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL);
|
||||||
@ -4717,9 +4867,13 @@ Parser<ParseHandler>::tryStatement()
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
case TOK_YIELD:
|
||||||
|
if (!checkYieldNameValidity(JSMSG_CATCH_IDENTIFIER))
|
||||||
|
return null();
|
||||||
|
// Fall through.
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
{
|
{
|
||||||
RootedPropertyName label(context, tokenStream.currentToken().name());
|
RootedPropertyName label(context, tokenStream.currentName());
|
||||||
catchName = newBindingNode(label, false);
|
catchName = newBindingNode(label, false);
|
||||||
if (!catchName)
|
if (!catchName)
|
||||||
return null();
|
return null();
|
||||||
@ -4855,7 +5009,7 @@ Parser<ParseHandler>::statement(bool canHaveDirectives)
|
|||||||
case TOK_BREAK:
|
case TOK_BREAK:
|
||||||
return breakStatement();
|
return breakStatement();
|
||||||
case TOK_RETURN:
|
case TOK_RETURN:
|
||||||
return returnStatementOrYieldExpression();
|
return returnStatement();
|
||||||
case TOK_WITH:
|
case TOK_WITH:
|
||||||
return withStatement();
|
return withStatement();
|
||||||
case TOK_THROW:
|
case TOK_THROW:
|
||||||
@ -4886,10 +5040,18 @@ Parser<ParseHandler>::statement(bool canHaveDirectives)
|
|||||||
}
|
}
|
||||||
return expressionStatement();
|
return expressionStatement();
|
||||||
|
|
||||||
|
case TOK_YIELD:
|
||||||
|
if (tokenStream.peekToken() == TOK_COLON) {
|
||||||
|
if (!checkYieldNameValidity())
|
||||||
|
return null();
|
||||||
|
return labeledStatement();
|
||||||
|
}
|
||||||
|
return expressionStatement();
|
||||||
|
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
if (tokenStream.peekToken() == TOK_COLON)
|
if (tokenStream.peekToken() == TOK_COLON)
|
||||||
return labeledStatement();
|
return labeledStatement();
|
||||||
if (tokenStream.currentToken().name() == context->names().module
|
if (tokenStream.currentName() == context->names().module
|
||||||
&& tokenStream.peekTokenSameLine() == TOK_STRING)
|
&& tokenStream.peekTokenSameLine() == TOK_STRING)
|
||||||
{
|
{
|
||||||
return moduleDecl();
|
return moduleDecl();
|
||||||
@ -5202,8 +5364,8 @@ Parser<ParseHandler>::assignExpr()
|
|||||||
if (tt == TOK_STRING && tokenStream.nextTokenEndsExpr())
|
if (tt == TOK_STRING && tokenStream.nextTokenEndsExpr())
|
||||||
return stringLiteral();
|
return stringLiteral();
|
||||||
|
|
||||||
if (tt == TOK_YIELD)
|
if (tt == TOK_YIELD && (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()))
|
||||||
return returnStatementOrYieldExpression();
|
return yieldExpression();
|
||||||
|
|
||||||
tokenStream.ungetToken();
|
tokenStream.ungetToken();
|
||||||
|
|
||||||
@ -5241,7 +5403,7 @@ Parser<ParseHandler>::assignExpr()
|
|||||||
return null();
|
return null();
|
||||||
tokenStream.ungetToken();
|
tokenStream.ungetToken();
|
||||||
|
|
||||||
return functionDef(NullPtr(), start, Normal, Arrow);
|
return functionDef(NullPtr(), start, Normal, Arrow, NotGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -5662,7 +5824,7 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
|
|||||||
BindData<FullParseHandler> data(context);
|
BindData<FullParseHandler> data(context);
|
||||||
TokenKind tt;
|
TokenKind tt;
|
||||||
|
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_FOR);
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
|
||||||
|
|
||||||
if (kind == PNK_SEMI) {
|
if (kind == PNK_SEMI) {
|
||||||
/*
|
/*
|
||||||
@ -5747,7 +5909,7 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
name = tokenStream.currentToken().name();
|
name = tokenStream.currentName();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a name node with pn_op JSOP_NAME. We can't set pn_op to
|
* Create a name node with pn_op JSOP_NAME. We can't set pn_op to
|
||||||
@ -5955,7 +6117,8 @@ Parser<FullParseHandler>::generatorExpr(ParseNode *kid)
|
|||||||
|
|
||||||
/* Create box for fun->object early to protect against last-ditch GC. */
|
/* Create box for fun->object early to protect against last-ditch GC. */
|
||||||
Directives directives(/* strict = */ outerpc->sc->strict);
|
Directives directives(/* strict = */ outerpc->sc->strict);
|
||||||
FunctionBox *genFunbox = newFunctionBox(genfn, fun, outerpc, directives);
|
FunctionBox *genFunbox = newFunctionBox(genfn, fun, outerpc, directives,
|
||||||
|
LegacyGenerator);
|
||||||
if (!genFunbox)
|
if (!genFunbox)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
@ -5975,7 +6138,7 @@ Parser<FullParseHandler>::generatorExpr(ParseNode *kid)
|
|||||||
if (outerpc->sc->isFunctionBox())
|
if (outerpc->sc->isFunctionBox())
|
||||||
genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags;
|
genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags;
|
||||||
|
|
||||||
genFunbox->setIsLegacyGenerator();
|
JS_ASSERT(genFunbox->isLegacyGenerator());
|
||||||
genFunbox->inGenexpLambda = true;
|
genFunbox->inGenexpLambda = true;
|
||||||
genfn->pn_blockid = genpc.bodyid;
|
genfn->pn_blockid = genpc.bodyid;
|
||||||
|
|
||||||
@ -6116,7 +6279,7 @@ Parser<ParseHandler>::memberExpr(TokenKind tt, bool allowCallSyntax)
|
|||||||
if (tt == TOK_ERROR)
|
if (tt == TOK_ERROR)
|
||||||
return null();
|
return null();
|
||||||
if (tt == TOK_NAME) {
|
if (tt == TOK_NAME) {
|
||||||
PropertyName *field = tokenStream.currentToken().name();
|
PropertyName *field = tokenStream.currentName();
|
||||||
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
|
nextMember = handler.newPropertyAccess(lhs, field, pos().end);
|
||||||
if (!nextMember)
|
if (!nextMember)
|
||||||
return null();
|
return null();
|
||||||
@ -6191,9 +6354,7 @@ template <typename ParseHandler>
|
|||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::identifierName()
|
Parser<ParseHandler>::identifierName()
|
||||||
{
|
{
|
||||||
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
|
RootedPropertyName name(context, tokenStream.currentName());
|
||||||
|
|
||||||
RootedPropertyName name(context, tokenStream.currentToken().name());
|
|
||||||
Node pn = newName(name);
|
Node pn = newName(name);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
@ -6395,7 +6556,7 @@ Parser<ParseHandler>::objectLiteral()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_NAME: {
|
case TOK_NAME: {
|
||||||
atom = tokenStream.currentToken().name();
|
atom = tokenStream.currentName();
|
||||||
if (atom == context->names().get) {
|
if (atom == context->names().get) {
|
||||||
op = JSOP_INITPROP_GETTER;
|
op = JSOP_INITPROP_GETTER;
|
||||||
} else if (atom == context->names().set) {
|
} else if (atom == context->names().set) {
|
||||||
@ -6411,7 +6572,7 @@ Parser<ParseHandler>::objectLiteral()
|
|||||||
// name next.
|
// name next.
|
||||||
TokenKind tt = tokenStream.getToken(TokenStream::KeywordIsName);
|
TokenKind tt = tokenStream.getToken(TokenStream::KeywordIsName);
|
||||||
if (tt == TOK_NAME) {
|
if (tt == TOK_NAME) {
|
||||||
atom = tokenStream.currentToken().name();
|
atom = tokenStream.currentName();
|
||||||
propname = newName(atom->asPropertyName());
|
propname = newName(atom->asPropertyName());
|
||||||
if (!propname)
|
if (!propname)
|
||||||
return null();
|
return null();
|
||||||
@ -6527,7 +6688,7 @@ Parser<ParseHandler>::objectLiteral()
|
|||||||
TokenStream::Position start(keepAtoms);
|
TokenStream::Position start(keepAtoms);
|
||||||
tokenStream.tell(&start);
|
tokenStream.tell(&start);
|
||||||
Node accessor = functionDef(funName, start, op == JSOP_INITPROP_GETTER ? Getter : Setter,
|
Node accessor = functionDef(funName, start, op == JSOP_INITPROP_GETTER ? Getter : Setter,
|
||||||
Expression);
|
Expression, NotGenerator);
|
||||||
if (!accessor)
|
if (!accessor)
|
||||||
return null();
|
return null();
|
||||||
if (!handler.addAccessorPropertyDefinition(literal, propname, accessor, op))
|
if (!handler.addAccessorPropertyDefinition(literal, propname, accessor, op))
|
||||||
@ -6628,6 +6789,10 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt)
|
|||||||
case TOK_STRING:
|
case TOK_STRING:
|
||||||
return stringLiteral();
|
return stringLiteral();
|
||||||
|
|
||||||
|
case TOK_YIELD:
|
||||||
|
if (!checkYieldNameValidity())
|
||||||
|
return null();
|
||||||
|
// Fall through.
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
return identifierName();
|
return identifierName();
|
||||||
|
|
||||||
@ -6689,7 +6854,7 @@ template <typename ParseHandler>
|
|||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::parenExpr(bool *genexp)
|
Parser<ParseHandler>::parenExpr(bool *genexp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(tokenStream.currentToken().type == TOK_LP);
|
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
|
||||||
uint32_t begin = pos().begin;
|
uint32_t begin = pos().begin;
|
||||||
|
|
||||||
if (genexp)
|
if (genexp)
|
||||||
|
@ -104,18 +104,20 @@ struct ParseContext : public GenericParseContext
|
|||||||
|
|
||||||
const unsigned staticLevel; /* static compilation unit nesting level */
|
const unsigned staticLevel; /* static compilation unit nesting level */
|
||||||
|
|
||||||
// Functions start off being parsed as NotGenerator.
|
|
||||||
// NotGenerator transitions to LegacyGenerator on parsing "yield" in JS 1.7.
|
|
||||||
enum GeneratorParseMode { NotGenerator, LegacyGenerator };
|
|
||||||
GeneratorParseMode generatorParseMode;
|
|
||||||
|
|
||||||
// lastYieldOffset stores the offset of the last yield that was parsed.
|
// lastYieldOffset stores the offset of the last yield that was parsed.
|
||||||
// NoYieldOffset is its initial value.
|
// NoYieldOffset is its initial value.
|
||||||
static const uint32_t NoYieldOffset = UINT32_MAX;
|
static const uint32_t NoYieldOffset = UINT32_MAX;
|
||||||
uint32_t lastYieldOffset;
|
uint32_t lastYieldOffset;
|
||||||
|
|
||||||
bool isGenerator() const { return generatorParseMode != NotGenerator; }
|
// Most functions start off being parsed as non-generators.
|
||||||
bool isLegacyGenerator() const { return generatorParseMode == LegacyGenerator; }
|
// Non-generators transition to LegacyGenerator on parsing "yield" in JS 1.7.
|
||||||
|
// An ES6 generator is marked as a "star generator" before its body is parsed.
|
||||||
|
GeneratorKind generatorKind() const {
|
||||||
|
return sc->isFunctionBox() ? sc->asFunctionBox()->generatorKind() : NotGenerator;
|
||||||
|
}
|
||||||
|
bool isGenerator() const { return generatorKind() != NotGenerator; }
|
||||||
|
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
|
||||||
|
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
|
||||||
|
|
||||||
Node blockNode; /* parse node for a block with let declarations
|
Node blockNode; /* parse node for a block with let declarations
|
||||||
(block with its own lexical scope) */
|
(block with its own lexical scope) */
|
||||||
@ -249,7 +251,6 @@ struct ParseContext : public GenericParseContext
|
|||||||
blockChain(prs->context),
|
blockChain(prs->context),
|
||||||
maybeFunction(maybeFunction),
|
maybeFunction(maybeFunction),
|
||||||
staticLevel(staticLevel),
|
staticLevel(staticLevel),
|
||||||
generatorParseMode(NotGenerator),
|
|
||||||
lastYieldOffset(NoYieldOffset),
|
lastYieldOffset(NoYieldOffset),
|
||||||
blockNode(ParseHandler::null()),
|
blockNode(ParseHandler::null()),
|
||||||
decls_(prs->context, prs->alloc),
|
decls_(prs->context, prs->alloc),
|
||||||
@ -400,7 +401,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||||||
ObjectBox *newObjectBox(JSObject *obj);
|
ObjectBox *newObjectBox(JSObject *obj);
|
||||||
ModuleBox *newModuleBox(Module *module, ParseContext<ParseHandler> *pc);
|
ModuleBox *newModuleBox(Module *module, ParseContext<ParseHandler> *pc);
|
||||||
FunctionBox *newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *pc,
|
FunctionBox *newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *pc,
|
||||||
Directives directives);
|
Directives directives, GeneratorKind generatorKind);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new function object given parse context (pc) and a name (which
|
* Create a new function object given parse context (pc) and a name (which
|
||||||
@ -433,13 +434,16 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||||||
Node statement(bool canHaveDirectives = false);
|
Node statement(bool canHaveDirectives = false);
|
||||||
bool maybeParseDirective(Node list, Node pn, bool *cont);
|
bool maybeParseDirective(Node list, Node pn, bool *cont);
|
||||||
|
|
||||||
// Parse a function, given only its body. Used for the Function constructor.
|
// Parse a function, given only its body. Used for the Function and
|
||||||
|
// Generator constructors.
|
||||||
Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
|
Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
|
||||||
|
GeneratorKind generatorKind,
|
||||||
Directives inheritedDirectives, Directives *newDirectives);
|
Directives inheritedDirectives, Directives *newDirectives);
|
||||||
|
|
||||||
// Parse a function, given only its arguments and body. Used for lazily
|
// Parse a function, given only its arguments and body. Used for lazily
|
||||||
// parsed functions.
|
// parsed functions.
|
||||||
Node standaloneLazyFunction(HandleFunction fun, unsigned staticLevel, bool strict);
|
Node standaloneLazyFunction(HandleFunction fun, unsigned staticLevel, bool strict,
|
||||||
|
GeneratorKind generatorKind);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a function body. Pass StatementListBody if the body is a list of
|
* Parse a function body. Pass StatementListBody if the body is a list of
|
||||||
@ -487,7 +491,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||||||
Node switchStatement();
|
Node switchStatement();
|
||||||
Node continueStatement();
|
Node continueStatement();
|
||||||
Node breakStatement();
|
Node breakStatement();
|
||||||
Node returnStatementOrYieldExpression();
|
Node returnStatement();
|
||||||
Node withStatement();
|
Node withStatement();
|
||||||
Node labeledStatement();
|
Node labeledStatement();
|
||||||
Node throwStatement();
|
Node throwStatement();
|
||||||
@ -504,6 +508,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||||||
Node expr();
|
Node expr();
|
||||||
Node assignExpr();
|
Node assignExpr();
|
||||||
Node assignExprWithoutYield(unsigned err);
|
Node assignExprWithoutYield(unsigned err);
|
||||||
|
Node yieldExpression();
|
||||||
Node condExpr1();
|
Node condExpr1();
|
||||||
Node orExpr1();
|
Node orExpr1();
|
||||||
Node unaryExpr();
|
Node unaryExpr();
|
||||||
@ -517,9 +522,10 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||||||
bool functionArguments(FunctionSyntaxKind kind, Node *list, Node funcpn, bool &hasRest);
|
bool functionArguments(FunctionSyntaxKind kind, Node *list, Node funcpn, bool &hasRest);
|
||||||
|
|
||||||
Node functionDef(HandlePropertyName name, const TokenStream::Position &start,
|
Node functionDef(HandlePropertyName name, const TokenStream::Position &start,
|
||||||
FunctionType type, FunctionSyntaxKind kind);
|
FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind);
|
||||||
bool functionArgsAndBody(Node pn, HandleFunction fun,
|
bool functionArgsAndBody(Node pn, HandleFunction fun,
|
||||||
FunctionType type, FunctionSyntaxKind kind,
|
FunctionType type, FunctionSyntaxKind kind,
|
||||||
|
GeneratorKind generatorKind,
|
||||||
Directives inheritedDirectives, Directives *newDirectives);
|
Directives inheritedDirectives, Directives *newDirectives);
|
||||||
|
|
||||||
Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
|
Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
|
||||||
@ -536,6 +542,9 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||||||
|
|
||||||
Node identifierName();
|
Node identifierName();
|
||||||
|
|
||||||
|
bool matchLabel(MutableHandle<PropertyName*> label);
|
||||||
|
bool checkYieldNameValidity(unsigned errorNumber = JSMSG_SYNTAX_ERROR);
|
||||||
|
|
||||||
bool allowsForEachIn() {
|
bool allowsForEachIn() {
|
||||||
#if !JS_HAS_FOR_EACH_IN
|
#if !JS_HAS_FOR_EACH_IN
|
||||||
return false;
|
return false;
|
||||||
@ -556,6 +565,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||||||
|
|
||||||
bool checkFunctionArguments();
|
bool checkFunctionArguments();
|
||||||
bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom);
|
bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom);
|
||||||
|
bool checkFunctionName(HandlePropertyName funName);
|
||||||
bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind,
|
bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind,
|
||||||
bool *pbodyProcessed);
|
bool *pbodyProcessed);
|
||||||
bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body);
|
bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body);
|
||||||
|
@ -72,10 +72,6 @@ class FunctionContextFlags
|
|||||||
// This class's data is all private and so only visible to these friends.
|
// This class's data is all private and so only visible to these friends.
|
||||||
friend class FunctionBox;
|
friend class FunctionBox;
|
||||||
|
|
||||||
// We parsed a yield statement in the function, which can happen in JS1.7+
|
|
||||||
// mode.
|
|
||||||
bool isLegacyGenerator:1;
|
|
||||||
|
|
||||||
// The function or a function that encloses it may define new local names
|
// The function or a function that encloses it may define new local names
|
||||||
// at runtime through means other than calling eval.
|
// at runtime through means other than calling eval.
|
||||||
bool mightAliasLocals:1;
|
bool mightAliasLocals:1;
|
||||||
@ -129,8 +125,7 @@ class FunctionContextFlags
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FunctionContextFlags()
|
FunctionContextFlags()
|
||||||
: isLegacyGenerator(false),
|
: mightAliasLocals(false),
|
||||||
mightAliasLocals(false),
|
|
||||||
hasExtensibleScope(false),
|
hasExtensibleScope(false),
|
||||||
needsDeclEnvObject(false),
|
needsDeclEnvObject(false),
|
||||||
argumentsHasLocalBinding(false),
|
argumentsHasLocalBinding(false),
|
||||||
@ -264,6 +259,8 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||||||
uint32_t startLine;
|
uint32_t startLine;
|
||||||
uint32_t startColumn;
|
uint32_t startColumn;
|
||||||
uint16_t ndefaults;
|
uint16_t ndefaults;
|
||||||
|
|
||||||
|
uint8_t generatorKindBits_; /* The GeneratorKind of this function. */
|
||||||
bool inWith:1; /* some enclosing scope is a with-statement */
|
bool inWith:1; /* some enclosing scope is a with-statement */
|
||||||
bool inGenexpLambda:1; /* lambda from generator expression */
|
bool inGenexpLambda:1; /* lambda from generator expression */
|
||||||
bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */
|
bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */
|
||||||
@ -279,21 +276,30 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
|
FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
|
||||||
ParseContext<ParseHandler> *pc, Directives directives,
|
ParseContext<ParseHandler> *pc, Directives directives,
|
||||||
bool extraWarnings);
|
bool extraWarnings, GeneratorKind generatorKind);
|
||||||
|
|
||||||
ObjectBox *toObjectBox() { return this; }
|
ObjectBox *toObjectBox() { return this; }
|
||||||
JSFunction *function() const { return &object->as<JSFunction>(); }
|
JSFunction *function() const { return &object->as<JSFunction>(); }
|
||||||
|
|
||||||
// In the future, isGenerator will also return true for ES6 generators.
|
GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
|
||||||
bool isGenerator() const { return isLegacyGenerator(); }
|
bool isGenerator() const { return generatorKind() != NotGenerator; }
|
||||||
bool isLegacyGenerator() const { return funCxFlags.isLegacyGenerator; }
|
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
|
||||||
|
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
|
||||||
|
|
||||||
|
void setGeneratorKind(GeneratorKind kind) {
|
||||||
|
// A generator kind can be set at initialization, or when "yield" is
|
||||||
|
// first seen. In both cases the transition can only happen from
|
||||||
|
// NotGenerator.
|
||||||
|
JS_ASSERT(!isGenerator());
|
||||||
|
generatorKindBits_ = GeneratorKindAsBits(kind);
|
||||||
|
}
|
||||||
|
|
||||||
bool mightAliasLocals() const { return funCxFlags.mightAliasLocals; }
|
bool mightAliasLocals() const { return funCxFlags.mightAliasLocals; }
|
||||||
bool hasExtensibleScope() const { return funCxFlags.hasExtensibleScope; }
|
bool hasExtensibleScope() const { return funCxFlags.hasExtensibleScope; }
|
||||||
bool needsDeclEnvObject() const { return funCxFlags.needsDeclEnvObject; }
|
bool needsDeclEnvObject() const { return funCxFlags.needsDeclEnvObject; }
|
||||||
bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
|
bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
|
||||||
bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
|
bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
|
||||||
|
|
||||||
void setIsLegacyGenerator() { funCxFlags.isLegacyGenerator = true; }
|
|
||||||
void setMightAliasLocals() { funCxFlags.mightAliasLocals = true; }
|
void setMightAliasLocals() { funCxFlags.mightAliasLocals = true; }
|
||||||
void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
|
void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
|
||||||
void setNeedsDeclEnvObject() { funCxFlags.needsDeclEnvObject = true; }
|
void setNeedsDeclEnvObject() { funCxFlags.needsDeclEnvObject = true; }
|
||||||
|
@ -937,10 +937,10 @@ TokenStream::checkForKeyword(const jschar *s, size_t length, TokenKind *ttp)
|
|||||||
return reportError(JSMSG_RESERVED_ID, kw->chars);
|
return reportError(JSMSG_RESERVED_ID, kw->chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The keyword is not in this version. Treat it as an identifier,
|
// The keyword is not in this version. Treat it as an identifier, unless
|
||||||
// unless it is let or yield which we treat as TOK_STRICT_RESERVED by
|
// it is let which we treat as TOK_STRICT_RESERVED by falling through to
|
||||||
// falling through to the code below (ES5 forbids them in strict mode).
|
// the code below (ES5 forbids it in strict mode).
|
||||||
if (kw->tokentype != TOK_LET && kw->tokentype != TOK_YIELD)
|
if (kw->tokentype != TOK_LET)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +407,13 @@ class MOZ_STACK_CLASS TokenStream
|
|||||||
JSVersion versionNumber() const { return VersionNumber(options().version); }
|
JSVersion versionNumber() const { return VersionNumber(options().version); }
|
||||||
JSVersion versionWithFlags() const { return options().version; }
|
JSVersion versionWithFlags() const { return options().version; }
|
||||||
|
|
||||||
|
PropertyName *currentName() const {
|
||||||
|
if (isCurrentTokenType(TOK_YIELD))
|
||||||
|
return cx->names().yield;
|
||||||
|
JS_ASSERT(isCurrentTokenType(TOK_NAME));
|
||||||
|
return currentToken().name();
|
||||||
|
}
|
||||||
|
|
||||||
bool isCurrentTokenAssignment() const {
|
bool isCurrentTokenAssignment() const {
|
||||||
return TokenKindIsAssignment(currentToken().type);
|
return TokenKindIsAssignment(currentToken().type);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
import os, shlex, subprocess, sys, traceback
|
import os, posixpath, shlex, subprocess, sys, traceback
|
||||||
|
|
||||||
def add_libdir_to_path():
|
def add_libdir_to_path():
|
||||||
from os.path import dirname, exists, join, realpath
|
from os.path import dirname, exists, join, realpath
|
||||||
@ -74,6 +74,23 @@ def main(argv):
|
|||||||
help='Run tests with all IonMonkey option combinations (ignores --jitflags)')
|
help='Run tests with all IonMonkey option combinations (ignores --jitflags)')
|
||||||
op.add_option('-j', '--worker-count', dest='max_jobs', type=int, default=max_jobs_default,
|
op.add_option('-j', '--worker-count', dest='max_jobs', type=int, default=max_jobs_default,
|
||||||
help='Number of tests to run in parallel (default %default)')
|
help='Number of tests to run in parallel (default %default)')
|
||||||
|
op.add_option('--remote', action='store_true',
|
||||||
|
help='Run tests on a remote device')
|
||||||
|
op.add_option('--deviceIP', action='store',
|
||||||
|
type='string', dest='device_ip',
|
||||||
|
help='IP address of remote device to test')
|
||||||
|
op.add_option('--devicePort', action='store',
|
||||||
|
type=int, dest='device_port', default=20701,
|
||||||
|
help='port of remote device to test')
|
||||||
|
op.add_option('--deviceTransport', action='store',
|
||||||
|
type='string', dest='device_transport', default='sut',
|
||||||
|
help='The transport to use to communicate with device: [adb|sut]; default=sut')
|
||||||
|
op.add_option('--remoteTestRoot', dest='remote_test_root', action='store',
|
||||||
|
type='string', default='/data/local/tests',
|
||||||
|
help='The remote directory to use as test root (eg. /data/local/tests)')
|
||||||
|
op.add_option('--localLib', dest='local_lib', action='store',
|
||||||
|
type='string',
|
||||||
|
help='The location of libraries to push -- preferably stripped')
|
||||||
|
|
||||||
options, args = op.parse_args(argv)
|
options, args = op.parse_args(argv)
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
@ -171,7 +188,11 @@ def main(argv):
|
|||||||
job_list.append(new_test)
|
job_list.append(new_test)
|
||||||
|
|
||||||
prefix = [os.path.abspath(args[0])] + shlex.split(options.shell_args)
|
prefix = [os.path.abspath(args[0])] + shlex.split(options.shell_args)
|
||||||
prefix += ['-f', os.path.join(jittests.LIB_DIR, 'prolog.js')]
|
prolog = os.path.join(jittests.LIB_DIR, 'prolog.js')
|
||||||
|
if options.remote:
|
||||||
|
prolog = posixpath.join(options.remote_test_root, 'jit-tests/lib/prolog.js')
|
||||||
|
|
||||||
|
prefix += ['-f', prolog]
|
||||||
if options.debug:
|
if options.debug:
|
||||||
if len(job_list) > 1:
|
if len(job_list) > 1:
|
||||||
print 'Multiple tests match command line arguments, debugger can only run one'
|
print 'Multiple tests match command line arguments, debugger can only run one'
|
||||||
@ -186,7 +207,9 @@ def main(argv):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
ok = None
|
ok = None
|
||||||
if options.max_jobs > 1 and jittests.HAVE_MULTIPROCESSING:
|
if options.remote:
|
||||||
|
ok = jittests.run_tests_remote(job_list, prefix, options)
|
||||||
|
elif options.max_jobs > 1 and jittests.HAVE_MULTIPROCESSING:
|
||||||
ok = jittests.run_tests_parallel(job_list, prefix, options)
|
ok = jittests.run_tests_parallel(job_list, prefix, options)
|
||||||
else:
|
else:
|
||||||
ok = jittests.run_tests(job_list, prefix, options)
|
ok = jittests.run_tests(job_list, prefix, options)
|
||||||
|
38
js/src/jit-test/tests/generators/es6-syntax.js
Normal file
38
js/src/jit-test/tests/generators/es6-syntax.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Test interactions between ES6 generators and not-yet-standard
|
||||||
|
// features.
|
||||||
|
|
||||||
|
function assertSyntaxError(str) {
|
||||||
|
var msg;
|
||||||
|
var evil = eval;
|
||||||
|
try {
|
||||||
|
// Non-direct eval.
|
||||||
|
evil(str);
|
||||||
|
} catch (exc) {
|
||||||
|
if (exc instanceof SyntaxError)
|
||||||
|
return;
|
||||||
|
msg = "Assertion failed: expected SyntaxError, got " + exc;
|
||||||
|
}
|
||||||
|
if (msg === undefined)
|
||||||
|
msg = "Assertion failed: expected SyntaxError, but no exception thrown";
|
||||||
|
throw new Error(msg + " - " + str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructuring binding.
|
||||||
|
assertSyntaxError("function* f(x = yield) {}");
|
||||||
|
assertSyntaxError("function* f(x = yield 17) {}");
|
||||||
|
assertSyntaxError("function* f([yield]) {}");
|
||||||
|
assertSyntaxError("function* f({ yield }) {}");
|
||||||
|
assertSyntaxError("function* f(...yield) {}");
|
||||||
|
|
||||||
|
// For each.
|
||||||
|
assertSyntaxError("for yield");
|
||||||
|
assertSyntaxError("for yield (;;) {}");
|
||||||
|
assertSyntaxError("for yield (x of y) {}");
|
||||||
|
assertSyntaxError("for yield (var i in o) {}");
|
||||||
|
|
||||||
|
// Expression bodies.
|
||||||
|
assertSyntaxError("function* f() yield 7");
|
||||||
|
|
||||||
|
// Asm.js.
|
||||||
|
load(libdir + "asm.js");
|
||||||
|
assertAsmDirectiveFail("function* f() { 'use asm'; function g() { return 0; } return g; })()")
|
@ -4607,7 +4607,7 @@ ParseFunction(ModuleCompiler &m, ParseNode **fnOut)
|
|||||||
AsmJSParseContext *outerpc = m.parser().pc;
|
AsmJSParseContext *outerpc = m.parser().pc;
|
||||||
|
|
||||||
Directives directives(outerpc);
|
Directives directives(outerpc);
|
||||||
FunctionBox *funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives);
|
FunctionBox *funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator);
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -409,3 +409,4 @@ MSG_DEF(JSMSG_BINARYDATA_NOT_BINARYSTRUCT, 355, 1, JSEXN_TYPEERR, "{0} is not
|
|||||||
MSG_DEF(JSMSG_BINARYDATA_SUBARRAY_INTEGER_ARG, 356, 1, JSEXN_ERR, "argument {0} must be an integer")
|
MSG_DEF(JSMSG_BINARYDATA_SUBARRAY_INTEGER_ARG, 356, 1, JSEXN_ERR, "argument {0} must be an integer")
|
||||||
MSG_DEF(JSMSG_BINARYDATA_STRUCTTYPE_EMPTY_DESCRIPTOR, 357, 0, JSEXN_ERR, "field descriptor cannot be empty")
|
MSG_DEF(JSMSG_BINARYDATA_STRUCTTYPE_EMPTY_DESCRIPTOR, 357, 0, JSEXN_ERR, "field descriptor cannot be empty")
|
||||||
MSG_DEF(JSMSG_BINARYDATA_STRUCTTYPE_BAD_FIELD, 358, 1, JSEXN_ERR, "field {0} is not a valid BinaryData Type descriptor")
|
MSG_DEF(JSMSG_BINARYDATA_STRUCTTYPE_BAD_FIELD, 358, 1, JSEXN_ERR, "field {0} is not a valid BinaryData Type descriptor")
|
||||||
|
MSG_DEF(JSMSG_ES6_UNIMPLEMENTED, 359, 0, JSEXN_ERR, "ES6 functionality not yet implemented")
|
||||||
|
@ -1749,7 +1749,7 @@ ScriptAnalysis::needsArgsObj(JSContext *cx)
|
|||||||
*
|
*
|
||||||
* FIXME: Don't build arguments for ES6 generator expressions.
|
* FIXME: Don't build arguments for ES6 generator expressions.
|
||||||
*/
|
*/
|
||||||
if (cx->compartment()->debugMode() || script_->isGenerator)
|
if (cx->compartment()->debugMode() || script_->isGenerator())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -104,7 +104,6 @@ const char js_typeof_str[] = "typeof";
|
|||||||
const char js_void_str[] = "void";
|
const char js_void_str[] = "void";
|
||||||
const char js_while_str[] = "while";
|
const char js_while_str[] = "while";
|
||||||
const char js_with_str[] = "with";
|
const char js_with_str[] = "with";
|
||||||
const char js_yield_str[] = "yield";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For a browser build from 2007-08-09 after the browser starts up there are
|
* For a browser build from 2007-08-09 after the browser starts up there are
|
||||||
|
@ -153,7 +153,6 @@ extern const char js_typeof_str[];
|
|||||||
extern const char js_void_str[];
|
extern const char js_void_str[];
|
||||||
extern const char js_while_str[];
|
extern const char js_while_str[];
|
||||||
extern const char js_with_str[];
|
extern const char js_with_str[];
|
||||||
extern const char js_yield_str[];
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
@ -526,6 +526,7 @@ FindBody(JSContext *cx, HandleFunction fun, StableCharPtr chars, size_t length,
|
|||||||
do {
|
do {
|
||||||
switch (ts.getToken()) {
|
switch (ts.getToken()) {
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
|
case TOK_YIELD:
|
||||||
if (nest == 0)
|
if (nest == 0)
|
||||||
onward = false;
|
onward = false;
|
||||||
break;
|
break;
|
||||||
@ -1228,14 +1229,7 @@ fun_isGenerator(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = false;
|
JS_SET_RVAL(cx, vp, BooleanValue(fun->isGenerator()));
|
||||||
if (fun->hasScript()) {
|
|
||||||
JSScript *script = fun->nonLazyScript();
|
|
||||||
JS_ASSERT(script->length != 0);
|
|
||||||
result = script->isGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_SET_RVAL(cx, vp, BooleanValue(result));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1456,10 +1450,15 @@ js::Function(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tt == TOK_YIELD && ts.versionNumber() < JSVERSION_1_7)
|
||||||
|
tt = TOK_NAME;
|
||||||
|
|
||||||
if (tt != TOK_NAME) {
|
if (tt != TOK_NAME) {
|
||||||
if (tt == TOK_TRIPLEDOT) {
|
if (tt == TOK_TRIPLEDOT) {
|
||||||
hasRest = true;
|
hasRest = true;
|
||||||
tt = ts.getToken();
|
tt = ts.getToken();
|
||||||
|
if (tt == TOK_YIELD && ts.versionNumber() < JSVERSION_1_7)
|
||||||
|
tt = TOK_NAME;
|
||||||
if (tt != TOK_NAME) {
|
if (tt != TOK_NAME) {
|
||||||
if (tt != TOK_ERROR)
|
if (tt != TOK_ERROR)
|
||||||
ts.reportError(JSMSG_NO_REST_NAME);
|
ts.reportError(JSMSG_NO_REST_NAME);
|
||||||
@ -1470,7 +1469,7 @@ js::Function(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!formals.append(ts.currentToken().name()))
|
if (!formals.append(ts.currentName()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -284,6 +284,18 @@ class JSFunction : public JSObject
|
|||||||
return u.i.s.lazy_;
|
return u.i.s.lazy_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
js::GeneratorKind generatorKind() const {
|
||||||
|
if (!isInterpreted())
|
||||||
|
return js::NotGenerator;
|
||||||
|
return hasScript() ? nonLazyScript()->generatorKind() : lazyScript()->generatorKind();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isGenerator() const { return generatorKind() != js::NotGenerator; }
|
||||||
|
|
||||||
|
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
|
||||||
|
|
||||||
|
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
|
||||||
|
|
||||||
inline void setScript(JSScript *script_);
|
inline void setScript(JSScript *script_);
|
||||||
inline void initScript(JSScript *script_);
|
inline void initScript(JSScript *script_);
|
||||||
void initLazyScript(js::LazyScript *lazy) {
|
void initLazyScript(js::LazyScript *lazy) {
|
||||||
|
@ -1475,6 +1475,13 @@ js_NewGenerator(JSContext *cx, const FrameRegs &stackRegs)
|
|||||||
JS_ASSERT(stackRegs.stackDepth() == 0);
|
JS_ASSERT(stackRegs.stackDepth() == 0);
|
||||||
StackFrame *stackfp = stackRegs.fp();
|
StackFrame *stackfp = stackRegs.fp();
|
||||||
|
|
||||||
|
JS_ASSERT(stackfp->script()->isGenerator());
|
||||||
|
|
||||||
|
if (stackfp->script()->isStarGenerator()) {
|
||||||
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ES6_UNIMPLEMENTED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Rooted<GlobalObject*> global(cx, &stackfp->global());
|
Rooted<GlobalObject*> global(cx, &stackfp->global());
|
||||||
RootedObject obj(cx);
|
RootedObject obj(cx);
|
||||||
{
|
{
|
||||||
|
@ -2787,6 +2787,7 @@ ASTSerializer::function(ParseNode *pn, ASTType type, MutableHandleValue dst)
|
|||||||
{
|
{
|
||||||
RootedFunction func(cx, pn->pn_funbox->function());
|
RootedFunction func(cx, pn->pn_funbox->function());
|
||||||
|
|
||||||
|
// FIXME: Provide more information (legacy generator vs star generator).
|
||||||
bool isGenerator = pn->pn_funbox->isGenerator();
|
bool isGenerator = pn->pn_funbox->isGenerator();
|
||||||
|
|
||||||
bool isExpression =
|
bool isExpression =
|
||||||
|
@ -408,9 +408,9 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
|||||||
FunHasAnyAliasedFormal,
|
FunHasAnyAliasedFormal,
|
||||||
ArgumentsHasVarBinding,
|
ArgumentsHasVarBinding,
|
||||||
NeedsArgsObj,
|
NeedsArgsObj,
|
||||||
IsGenerator,
|
|
||||||
IsGeneratorExp,
|
IsGeneratorExp,
|
||||||
IsLegacyGenerator,
|
IsLegacyGenerator,
|
||||||
|
IsStarGenerator,
|
||||||
OwnSource,
|
OwnSource,
|
||||||
ExplicitUseStrict,
|
ExplicitUseStrict,
|
||||||
SelfHosted
|
SelfHosted
|
||||||
@ -497,12 +497,12 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
|||||||
scriptBits |= (1 << NeedsArgsObj);
|
scriptBits |= (1 << NeedsArgsObj);
|
||||||
if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource())
|
if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource())
|
||||||
scriptBits |= (1 << OwnSource);
|
scriptBits |= (1 << OwnSource);
|
||||||
if (script->isGenerator)
|
|
||||||
scriptBits |= (1 << IsGenerator);
|
|
||||||
if (script->isGeneratorExp)
|
if (script->isGeneratorExp)
|
||||||
scriptBits |= (1 << IsGeneratorExp);
|
scriptBits |= (1 << IsGeneratorExp);
|
||||||
if (script->isLegacyGenerator)
|
if (script->isLegacyGenerator())
|
||||||
scriptBits |= (1 << IsLegacyGenerator);
|
scriptBits |= (1 << IsLegacyGenerator);
|
||||||
|
if (script->isStarGenerator())
|
||||||
|
scriptBits |= (1 << IsStarGenerator);
|
||||||
|
|
||||||
JS_ASSERT(!script->compileAndGo);
|
JS_ASSERT(!script->compileAndGo);
|
||||||
JS_ASSERT(!script->hasSingletons);
|
JS_ASSERT(!script->hasSingletons);
|
||||||
@ -597,12 +597,14 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
|||||||
script->setArgumentsHasVarBinding();
|
script->setArgumentsHasVarBinding();
|
||||||
if (scriptBits & (1 << NeedsArgsObj))
|
if (scriptBits & (1 << NeedsArgsObj))
|
||||||
script->setNeedsArgsObj(true);
|
script->setNeedsArgsObj(true);
|
||||||
if (scriptBits & (1 << IsGenerator))
|
|
||||||
script->isGenerator = true;
|
|
||||||
if (scriptBits & (1 << IsGeneratorExp))
|
if (scriptBits & (1 << IsGeneratorExp))
|
||||||
script->isGeneratorExp = true;
|
script->isGeneratorExp = true;
|
||||||
if (scriptBits & (1 << IsLegacyGenerator))
|
|
||||||
script->isLegacyGenerator = true;
|
if (scriptBits & (1 << IsLegacyGenerator)) {
|
||||||
|
JS_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
|
||||||
|
script->setGeneratorKind(LegacyGenerator);
|
||||||
|
} else if (scriptBits & (1 << IsStarGenerator))
|
||||||
|
script->setGeneratorKind(StarGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
|
JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
|
||||||
@ -1974,9 +1976,8 @@ JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, Byteco
|
|||||||
RootedFunction fun(cx, NULL);
|
RootedFunction fun(cx, NULL);
|
||||||
if (funbox) {
|
if (funbox) {
|
||||||
JS_ASSERT(!bce->script->noScriptRval);
|
JS_ASSERT(!bce->script->noScriptRval);
|
||||||
script->isGenerator = funbox->isGenerator();
|
|
||||||
script->isGeneratorExp = funbox->inGenexpLambda;
|
script->isGeneratorExp = funbox->inGenexpLambda;
|
||||||
script->isLegacyGenerator = funbox->isLegacyGenerator();
|
script->setGeneratorKind(funbox->generatorKind());
|
||||||
script->setFunction(funbox->function());
|
script->setFunction(funbox->function());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2477,8 +2478,8 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
|||||||
dst->funHasAnyAliasedFormal = src->funHasAnyAliasedFormal;
|
dst->funHasAnyAliasedFormal = src->funHasAnyAliasedFormal;
|
||||||
dst->hasSingletons = src->hasSingletons;
|
dst->hasSingletons = src->hasSingletons;
|
||||||
dst->treatAsRunOnce = src->treatAsRunOnce;
|
dst->treatAsRunOnce = src->treatAsRunOnce;
|
||||||
dst->isGenerator = src->isGenerator;
|
|
||||||
dst->isGeneratorExp = src->isGeneratorExp;
|
dst->isGeneratorExp = src->isGeneratorExp;
|
||||||
|
dst->setGeneratorKind(src->generatorKind());
|
||||||
|
|
||||||
/* Copy over hints. */
|
/* Copy over hints. */
|
||||||
dst->shouldInline = src->shouldInline;
|
dst->shouldInline = src->shouldInline;
|
||||||
@ -2919,7 +2920,7 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
|
|||||||
if (script->needsArgsObj())
|
if (script->needsArgsObj())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
JS_ASSERT(!script->isGenerator);
|
JS_ASSERT(!script->isGenerator());
|
||||||
|
|
||||||
script->needsArgsObj_ = true;
|
script->needsArgsObj_ = true;
|
||||||
|
|
||||||
@ -3011,6 +3012,7 @@ LazyScript::LazyScript(JSFunction *fun, void *table, uint32_t numFreeVariables,
|
|||||||
version_(version),
|
version_(version),
|
||||||
numFreeVariables_(numFreeVariables),
|
numFreeVariables_(numFreeVariables),
|
||||||
numInnerFunctions_(numInnerFunctions),
|
numInnerFunctions_(numInnerFunctions),
|
||||||
|
generatorKindBits_(GeneratorKindAsBits(NotGenerator)),
|
||||||
strict_(false),
|
strict_(false),
|
||||||
bindingsAccessedDynamically_(false),
|
bindingsAccessedDynamically_(false),
|
||||||
hasDebuggerStatement_(false),
|
hasDebuggerStatement_(false),
|
||||||
|
@ -414,6 +414,19 @@ class ScriptSourceObject : public JSObject
|
|||||||
static const uint32_t SOURCE_SLOT = 0;
|
static const uint32_t SOURCE_SLOT = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
GeneratorKindAsBits(GeneratorKind generatorKind) {
|
||||||
|
return static_cast<unsigned>(generatorKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GeneratorKind
|
||||||
|
GeneratorKindFromBits(unsigned val) {
|
||||||
|
JS_ASSERT(val <= StarGenerator);
|
||||||
|
return static_cast<GeneratorKind>(val);
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
class JSScript : public js::gc::Cell
|
class JSScript : public js::gc::Cell
|
||||||
@ -519,7 +532,7 @@ class JSScript : public js::gc::Cell
|
|||||||
uint16_t nslots; /* vars plus maximum stack depth */
|
uint16_t nslots; /* vars plus maximum stack depth */
|
||||||
uint16_t staticLevel;/* static level for display maintenance */
|
uint16_t staticLevel;/* static level for display maintenance */
|
||||||
|
|
||||||
// 8-bit fields.
|
// 4-bit fields.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// The kinds of the optional arrays.
|
// The kinds of the optional arrays.
|
||||||
@ -528,15 +541,16 @@ class JSScript : public js::gc::Cell
|
|||||||
OBJECTS,
|
OBJECTS,
|
||||||
REGEXPS,
|
REGEXPS,
|
||||||
TRYNOTES,
|
TRYNOTES,
|
||||||
LIMIT
|
ARRAY_KIND_BITS
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef uint8_t ArrayBitsT;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The bits in this field indicate the presence/non-presence of several
|
// The bits in this field indicate the presence/non-presence of several
|
||||||
// optional arrays in |data|. See the comments above Create() for details.
|
// optional arrays in |data|. See the comments above Create() for details.
|
||||||
ArrayBitsT hasArrayBits;
|
uint8_t hasArrayBits:4;
|
||||||
|
|
||||||
|
// The GeneratorKind of the script.
|
||||||
|
uint8_t generatorKindBits_:4;
|
||||||
|
|
||||||
// 1-bit fields.
|
// 1-bit fields.
|
||||||
|
|
||||||
@ -589,14 +603,9 @@ class JSScript : public js::gc::Cell
|
|||||||
#endif
|
#endif
|
||||||
bool invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */
|
bool invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */
|
||||||
|
|
||||||
// All generators have isGenerator set to true.
|
|
||||||
bool isGenerator:1;
|
|
||||||
// If the generator was created implicitly via a generator expression,
|
// If the generator was created implicitly via a generator expression,
|
||||||
// isGeneratorExp will be true.
|
// isGeneratorExp will be true.
|
||||||
bool isGeneratorExp:1;
|
bool isGeneratorExp:1;
|
||||||
// Generators are either legacy-style (JS 1.7+ starless generators with
|
|
||||||
// StopIteration), or ES6-style (function* with boxed return values).
|
|
||||||
bool isLegacyGenerator:1;
|
|
||||||
|
|
||||||
bool hasScriptCounts:1;/* script has an entry in
|
bool hasScriptCounts:1;/* script has an entry in
|
||||||
JSCompartment::scriptCountsMap */
|
JSCompartment::scriptCountsMap */
|
||||||
@ -647,6 +656,19 @@ class JSScript : public js::gc::Cell
|
|||||||
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
|
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
|
||||||
void setArgumentsHasVarBinding();
|
void setArgumentsHasVarBinding();
|
||||||
|
|
||||||
|
js::GeneratorKind generatorKind() const {
|
||||||
|
return js::GeneratorKindFromBits(generatorKindBits_);
|
||||||
|
}
|
||||||
|
bool isGenerator() const { return generatorKind() != js::NotGenerator; }
|
||||||
|
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
|
||||||
|
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
|
||||||
|
void setGeneratorKind(js::GeneratorKind kind) {
|
||||||
|
// A script only gets its generator kind set as part of initialization,
|
||||||
|
// so it can only transition from not being a generator.
|
||||||
|
JS_ASSERT(!isGenerator());
|
||||||
|
generatorKindBits_ = GeneratorKindAsBits(kind);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As an optimization, even when argsHasLocalBinding, the function prologue
|
* As an optimization, even when argsHasLocalBinding, the function prologue
|
||||||
* may not need to create an arguments object. This is determined by
|
* may not need to create an arguments object. This is determined by
|
||||||
@ -1038,7 +1060,8 @@ class JSScript : public js::gc::Cell
|
|||||||
void markChildren(JSTracer *trc);
|
void markChildren(JSTracer *trc);
|
||||||
};
|
};
|
||||||
|
|
||||||
JS_STATIC_ASSERT(sizeof(JSScript::ArrayBitsT) * 8 >= JSScript::LIMIT);
|
/* The array kind flags are stored in a 4-bit field; make sure they fit. */
|
||||||
|
JS_STATIC_ASSERT(JSScript::ARRAY_KIND_BITS <= 4);
|
||||||
|
|
||||||
/* If this fails, add/remove padding within JSScript. */
|
/* If this fails, add/remove padding within JSScript. */
|
||||||
JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::CellSize == 0);
|
JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::CellSize == 0);
|
||||||
@ -1145,7 +1168,9 @@ class LazyScript : public js::gc::Cell
|
|||||||
uint32_t version_ : 8;
|
uint32_t version_ : 8;
|
||||||
|
|
||||||
uint32_t numFreeVariables_ : 24;
|
uint32_t numFreeVariables_ : 24;
|
||||||
uint32_t numInnerFunctions_ : 26;
|
uint32_t numInnerFunctions_ : 24;
|
||||||
|
|
||||||
|
uint32_t generatorKindBits_:2;
|
||||||
|
|
||||||
// N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
|
// N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
|
||||||
uint32_t strict_ : 1;
|
uint32_t strict_ : 1;
|
||||||
@ -1211,6 +1236,23 @@ class LazyScript : public js::gc::Cell
|
|||||||
return (HeapPtrFunction *)&freeVariables()[numFreeVariables()];
|
return (HeapPtrFunction *)&freeVariables()[numFreeVariables()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
|
||||||
|
|
||||||
|
bool isGenerator() const { return generatorKind() != NotGenerator; }
|
||||||
|
|
||||||
|
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
|
||||||
|
|
||||||
|
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
|
||||||
|
|
||||||
|
void setGeneratorKind(GeneratorKind kind) {
|
||||||
|
// A script only gets its generator kind set as part of initialization,
|
||||||
|
// so it can only transition from NotGenerator.
|
||||||
|
JS_ASSERT(!isGenerator());
|
||||||
|
// Legacy generators cannot currently be lazy.
|
||||||
|
JS_ASSERT(kind != LegacyGenerator);
|
||||||
|
generatorKindBits_ = GeneratorKindAsBits(kind);
|
||||||
|
}
|
||||||
|
|
||||||
bool strict() const {
|
bool strict() const {
|
||||||
return strict_;
|
return strict_;
|
||||||
}
|
}
|
||||||
|
0
js/src/tests/ecma_6/Generators/shell.js
Normal file
0
js/src/tests/ecma_6/Generators/shell.js
Normal file
97
js/src/tests/ecma_6/Generators/syntax.js
Normal file
97
js/src/tests/ecma_6/Generators/syntax.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// This file was written by Andy Wingo <wingo@igalia.com> and originally
|
||||||
|
// contributed to V8 as generators-parsing.js, available here:
|
||||||
|
//
|
||||||
|
// http://code.google.com/p/v8/source/browse/branches/bleeding_edge/test/mjsunit/harmony/generators-parsing.js
|
||||||
|
|
||||||
|
function assertSyntaxError(str) {
|
||||||
|
var msg;
|
||||||
|
var evil = eval;
|
||||||
|
try {
|
||||||
|
// Non-direct eval.
|
||||||
|
evil(str);
|
||||||
|
} catch (exc) {
|
||||||
|
if (exc instanceof SyntaxError)
|
||||||
|
return;
|
||||||
|
msg = "Assertion failed: expected SyntaxError, got " + exc;
|
||||||
|
}
|
||||||
|
if (msg === undefined)
|
||||||
|
msg = "Assertion failed: expected SyntaxError, but no exception thrown";
|
||||||
|
throw new Error(msg + " - " + str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yield statements.
|
||||||
|
function* g() { yield 3; yield 4; }
|
||||||
|
|
||||||
|
// Yield expressions.
|
||||||
|
function* g() { (yield 3) + (yield 4); }
|
||||||
|
|
||||||
|
// You can have a generator in strict mode.
|
||||||
|
function* g() { "use strict"; yield 3; yield 4; }
|
||||||
|
|
||||||
|
// Generators can have return statements also, which internally parse to a kind
|
||||||
|
// of yield expression.
|
||||||
|
function* g() { yield 1; return; }
|
||||||
|
function* g() { yield 1; return 2; }
|
||||||
|
function* g() { yield 1; return 2; yield "dead"; }
|
||||||
|
|
||||||
|
// Generator expression.
|
||||||
|
(function* () { yield 3; });
|
||||||
|
|
||||||
|
// Named generator expression.
|
||||||
|
(function* g() { yield 3; });
|
||||||
|
|
||||||
|
// Generators do not have to contain yield expressions.
|
||||||
|
function* g() { }
|
||||||
|
|
||||||
|
// YieldExpressions can occur in the RHS of a YieldExpression.
|
||||||
|
function* g() { yield yield 1; }
|
||||||
|
function* g() { yield 3 + (yield 4); }
|
||||||
|
|
||||||
|
// Generator definitions with a name of "yield" are not specifically ruled out
|
||||||
|
// by the spec, as the `yield' name is outside the generator itself. However,
|
||||||
|
// in strict-mode, "yield" is an invalid identifier.
|
||||||
|
function* yield() { (yield 3) + (yield 4); }
|
||||||
|
assertSyntaxError("function* yield() { 'use strict'; (yield 3) + (yield 4); }");
|
||||||
|
|
||||||
|
// In classic mode, yield is a normal identifier, outside of generators.
|
||||||
|
function yield(yield) { yield: yield (yield + yield (0)); }
|
||||||
|
|
||||||
|
// Yield is always valid as a key in an object literal.
|
||||||
|
({ yield: 1 });
|
||||||
|
function* g() { yield ({ yield: 1 }) }
|
||||||
|
function* g() { yield ({ get yield() { return 1; }}) }
|
||||||
|
|
||||||
|
// Yield is a valid property name.
|
||||||
|
function* g(obj) { yield obj.yield; }
|
||||||
|
|
||||||
|
// Checks that yield is a valid label in classic mode, but not valid in a strict
|
||||||
|
// mode or in generators.
|
||||||
|
function f() { yield: 1 }
|
||||||
|
assertSyntaxError("function f() { 'use strict'; yield: 1 }")
|
||||||
|
assertSyntaxError("function* g() { yield: 1 }")
|
||||||
|
|
||||||
|
// Yield is only a keyword in the body of the generator, not in nested
|
||||||
|
// functions.
|
||||||
|
function* g() { function f(yield) { yield (yield + yield (0)); } }
|
||||||
|
|
||||||
|
// Yield needs a RHS.
|
||||||
|
assertSyntaxError("function* g() { yield; }");
|
||||||
|
|
||||||
|
// Yield in a generator is not an identifier.
|
||||||
|
assertSyntaxError("function* g() { yield = 10; }");
|
||||||
|
|
||||||
|
// Yield binds very loosely, so this parses as "yield (3 + yield 4)", which is
|
||||||
|
// invalid.
|
||||||
|
assertSyntaxError("function* g() { yield 3 + yield 4; }");
|
||||||
|
|
||||||
|
// Yield is still a future-reserved-word in strict mode
|
||||||
|
assertSyntaxError("function f() { 'use strict'; var yield = 13; }");
|
||||||
|
|
||||||
|
// The name of the NFE is let-bound in G, so is invalid.
|
||||||
|
assertSyntaxError("function* g() { yield (function yield() {}); }");
|
||||||
|
|
||||||
|
// In generators, yield is invalid as a formal argument name.
|
||||||
|
assertSyntaxError("function* g(yield) { yield (10); }");
|
||||||
|
|
||||||
|
if (typeof reportCompare == "function")
|
||||||
|
reportCompare(true, true);
|
@ -7,11 +7,12 @@
|
|||||||
# jit_test.py -- Python harness for JavaScript trace tests.
|
# jit_test.py -- Python harness for JavaScript trace tests.
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import os, sys, tempfile, traceback, time
|
import os, posixpath, sys, tempfile, traceback, time
|
||||||
import subprocess
|
import subprocess
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import signal
|
import signal
|
||||||
|
import StringIO
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from multiprocessing import Process, Manager, cpu_count
|
from multiprocessing import Process, Manager, cpu_count
|
||||||
@ -152,15 +153,29 @@ class Test:
|
|||||||
|
|
||||||
return test
|
return test
|
||||||
|
|
||||||
def command(self, prefix):
|
def command(self, prefix, libdir, remote_prefix=None):
|
||||||
scriptdir_var = os.path.dirname(self.path);
|
path = self.path
|
||||||
|
if remote_prefix:
|
||||||
|
path = self.path.replace(TEST_DIR, remote_prefix)
|
||||||
|
|
||||||
|
scriptdir_var = os.path.dirname(path);
|
||||||
if not scriptdir_var.endswith('/'):
|
if not scriptdir_var.endswith('/'):
|
||||||
scriptdir_var += '/'
|
scriptdir_var += '/'
|
||||||
expr = ("const platform=%r; const libdir=%r; const scriptdir=%r"
|
|
||||||
% (sys.platform, LIB_DIR, scriptdir_var))
|
# Platforms where subprocess immediately invokes exec do not care
|
||||||
|
# whether we use double or single quotes. On windows and when using
|
||||||
|
# a remote device, however, we have to be careful to use the quote
|
||||||
|
# style that is the opposite of what the exec wrapper uses.
|
||||||
|
# This uses %r to get single quotes on windows and special cases
|
||||||
|
# the remote device.
|
||||||
|
fmt = 'const platform=%r; const libdir=%r; const scriptdir=%r'
|
||||||
|
if remote_prefix:
|
||||||
|
fmt = 'const platform="%s"; const libdir="%s"; const scriptdir="%s"'
|
||||||
|
expr = fmt % (sys.platform, libdir, scriptdir_var)
|
||||||
|
|
||||||
# We may have specified '-a' or '-d' twice: once via --jitflags, once
|
# We may have specified '-a' or '-d' twice: once via --jitflags, once
|
||||||
# via the "|jit-test|" line. Remove dups because they are toggles.
|
# via the "|jit-test|" line. Remove dups because they are toggles.
|
||||||
cmd = prefix + list(set(self.jitflags)) + ['-e', expr, '-f', self.path]
|
cmd = prefix + list(set(self.jitflags)) + ['-e', expr, '-f', path]
|
||||||
if self.valgrind:
|
if self.valgrind:
|
||||||
cmd = self.VALGRIND_CMD + cmd
|
cmd = self.VALGRIND_CMD + cmd
|
||||||
return cmd
|
return cmd
|
||||||
@ -268,7 +283,7 @@ def run_cmd_avoid_stdio(cmdline, env, timeout):
|
|||||||
return read_and_unlink(stdoutPath), read_and_unlink(stderrPath), code
|
return read_and_unlink(stdoutPath), read_and_unlink(stderrPath), code
|
||||||
|
|
||||||
def run_test(test, prefix, options):
|
def run_test(test, prefix, options):
|
||||||
cmd = test.command(prefix)
|
cmd = test.command(prefix, LIB_DIR)
|
||||||
if options.show_cmd:
|
if options.show_cmd:
|
||||||
print(subprocess.list2cmdline(cmd))
|
print(subprocess.list2cmdline(cmd))
|
||||||
|
|
||||||
@ -284,6 +299,26 @@ def run_test(test, prefix, options):
|
|||||||
out, err, code, timed_out = run(cmd, env, options.timeout)
|
out, err, code, timed_out = run(cmd, env, options.timeout)
|
||||||
return TestOutput(test, cmd, out, err, code, None, timed_out)
|
return TestOutput(test, cmd, out, err, code, None, timed_out)
|
||||||
|
|
||||||
|
def run_test_remote(test, device, prefix, options):
|
||||||
|
cmd = test.command(prefix, posixpath.join(options.remote_test_root, 'lib/'), posixpath.join(options.remote_test_root, 'tests'))
|
||||||
|
if options.show_cmd:
|
||||||
|
print(subprocess.list2cmdline(cmd))
|
||||||
|
|
||||||
|
env = {}
|
||||||
|
if test.tz_pacific:
|
||||||
|
env['TZ'] = 'PST8PDT'
|
||||||
|
|
||||||
|
env['LD_LIBRARY_PATH'] = options.remote_test_root
|
||||||
|
|
||||||
|
buf = StringIO.StringIO()
|
||||||
|
returncode = device.shell(cmd, buf, env=env, cwd=options.remote_test_root,
|
||||||
|
timeout=int(options.timeout))
|
||||||
|
|
||||||
|
out = buf.getvalue()
|
||||||
|
# We can't distinguish between stdout and stderr so we pass
|
||||||
|
# the same buffer to both.
|
||||||
|
return TestOutput(test, cmd, out, out, returncode, None, False)
|
||||||
|
|
||||||
def check_output(out, err, rc, test):
|
def check_output(out, err, rc, test):
|
||||||
if test.expect_error:
|
if test.expect_error:
|
||||||
# The shell exits with code 3 on uncaught exceptions.
|
# The shell exits with code 3 on uncaught exceptions.
|
||||||
@ -541,6 +576,58 @@ def run_tests(tests, prefix, options):
|
|||||||
ok = process_test_results(gen, len(tests), options)
|
ok = process_test_results(gen, len(tests), options)
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
|
def get_remote_results(tests, device, prefix, options):
|
||||||
|
for test in tests:
|
||||||
|
yield run_test_remote(test, device, prefix, options)
|
||||||
|
|
||||||
|
def push_libs(options, device):
|
||||||
|
# This saves considerable time in pushing unnecessary libraries
|
||||||
|
# to the device but needs to be updated if the dependencies change.
|
||||||
|
required_libs = ['libnss3.so', 'libmozglue.so']
|
||||||
|
|
||||||
|
for file in os.listdir(options.local_lib):
|
||||||
|
if file in required_libs:
|
||||||
|
remote_file = posixpath.join(options.remote_test_root, file)
|
||||||
|
device.pushFile(os.path.join(options.local_lib, file), remote_file)
|
||||||
|
|
||||||
|
def push_progs(options, device, progs):
|
||||||
|
for local_file in progs:
|
||||||
|
remote_file = posixpath.join(options.remote_test_root, os.path.basename(local_file))
|
||||||
|
device.pushFile(local_file, remote_file)
|
||||||
|
|
||||||
|
def run_tests_remote(tests, prefix, options):
|
||||||
|
# Setup device with everything needed to run our tests.
|
||||||
|
from mozdevice import devicemanager, devicemanagerADB, devicemanagerSUT
|
||||||
|
|
||||||
|
if options.device_transport == 'adb':
|
||||||
|
if options.device_ip:
|
||||||
|
dm = devicemanagerADB.DeviceManagerADB(options.device_ip, options.devicePort, packageName=None, deviceRoot=options.remoteTestRoot)
|
||||||
|
else:
|
||||||
|
dm = devicemanagerADB.DeviceManagerADB(packageName=None, deviceRoot=options.remote_test_root)
|
||||||
|
else:
|
||||||
|
dm = devicemanagerSUT.DeviceManagerSUT(options.device_ip, options.device_port, deviceRoot=options.remote_test_root)
|
||||||
|
if options.device_ip == None:
|
||||||
|
print('Error: you must provide a device IP to connect to via the --device option')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Update the test root to point to our test directory.
|
||||||
|
options.remote_test_root = posixpath.join(options.remote_test_root, 'jit-tests')
|
||||||
|
|
||||||
|
# Push js shell and libraries.
|
||||||
|
if dm.dirExists(options.remote_test_root):
|
||||||
|
dm.removeDir(options.remote_test_root)
|
||||||
|
dm.mkDir(options.remote_test_root)
|
||||||
|
push_libs(options, dm)
|
||||||
|
push_progs(options, dm, [prefix[0]])
|
||||||
|
dm.chmodDir(options.remote_test_root)
|
||||||
|
dm.pushDir(os.path.dirname(TEST_DIR), options.remote_test_root)
|
||||||
|
prefix[0] = os.path.join(options.remote_test_root, 'js')
|
||||||
|
|
||||||
|
# Run all tests.
|
||||||
|
gen = get_remote_results(tests, dm, prefix, options)
|
||||||
|
ok = process_test_results(gen, len(tests), options)
|
||||||
|
return ok
|
||||||
|
|
||||||
def parse_jitflags(options):
|
def parse_jitflags(options):
|
||||||
jitflags = [ [ '-' + flag for flag in flags ]
|
jitflags = [ [ '-' + flag for flag in flags ]
|
||||||
for flags in options.jitflags.split(',') ]
|
for flags in options.jitflags.split(',') ]
|
||||||
|
@ -152,6 +152,7 @@
|
|||||||
macro(void0, void0, "(void 0)") \
|
macro(void0, void0, "(void 0)") \
|
||||||
macro(watch, watch, "watch") \
|
macro(watch, watch, "watch") \
|
||||||
macro(writable, writable, "writable") \
|
macro(writable, writable, "writable") \
|
||||||
|
macro(yield, yield, "yield") \
|
||||||
/* Type names must be contiguous and ordered; see js::TypeName. */ \
|
/* Type names must be contiguous and ordered; see js::TypeName. */ \
|
||||||
macro(undefined, undefined, "undefined") \
|
macro(undefined, undefined, "undefined") \
|
||||||
macro(object, object, "object") \
|
macro(object, object, "object") \
|
||||||
|
@ -72,8 +72,12 @@
|
|||||||
macro(protected, protected_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
macro(protected, protected_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||||
macro(public, public_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
macro(public, public_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||||
macro(static, static_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
macro(static, static_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||||
/* ES5 future reserved keyword in strict mode, keyword in JS1.7 even when not strict. */ \
|
/* \
|
||||||
macro(yield, yield, TOK_YIELD, JSVERSION_1_7) \
|
* ES5 future reserved keyword in strict mode, keyword in JS1.7 even when \
|
||||||
|
* not strict, keyword inside function* in all versions. Punt logic to \
|
||||||
|
* parser. \
|
||||||
|
*/ \
|
||||||
|
macro(yield, yield, TOK_YIELD, JSVERSION_DEFAULT) \
|
||||||
/* Various conditional keywords. */ \
|
/* Various conditional keywords. */ \
|
||||||
FOR_CONST_KEYWORD(macro) \
|
FOR_CONST_KEYWORD(macro) \
|
||||||
FOR_LET_KEYWORD(macro)
|
FOR_LET_KEYWORD(macro)
|
||||||
|
@ -118,7 +118,6 @@ if (!isWindows) {
|
|||||||
tests.push([ 'bug240933-2.html' , 'bug240933-1-ref.html' ]); // bug 681162
|
tests.push([ 'bug240933-2.html' , 'bug240933-1-ref.html' ]); // bug 681162
|
||||||
tests.push([ 'bug389321-1.html' , 'bug389321-1-ref.html' ]); // bug 683163
|
tests.push([ 'bug389321-1.html' , 'bug389321-1-ref.html' ]); // bug 683163
|
||||||
tests.push([ 'bug482484.html' , 'bug482484-ref.html' ]); // bug 688575
|
tests.push([ 'bug482484.html' , 'bug482484-ref.html' ]); // bug 688575
|
||||||
tests.push([ 'bug512295-1.html' , 'bug512295-1-ref.html' ]); // bug 681152
|
|
||||||
tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]); // bug 681331
|
tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]); // bug 681331
|
||||||
tests.push([ 'bug597519-1.html' , 'bug597519-1-ref.html' ]); // bug 680579
|
tests.push([ 'bug597519-1.html' , 'bug597519-1-ref.html' ]); // bug 680579
|
||||||
tests.push([ 'bug602141-1.html' , 'bug602141-1-ref.html' ]); // bug 681334
|
tests.push([ 'bug602141-1.html' , 'bug602141-1-ref.html' ]); // bug 681334
|
||||||
@ -142,6 +141,7 @@ if (!isWindows) {
|
|||||||
if (!isWindows && !isOSXMtnLion) {
|
if (!isWindows && !isOSXMtnLion) {
|
||||||
tests.push([ 'bug106855-1.html' , 'bug106855-1-ref.html' ]); // bug 682837
|
tests.push([ 'bug106855-1.html' , 'bug106855-1-ref.html' ]); // bug 682837
|
||||||
tests.push([ 'bug106855-2.html' , 'bug106855-1-ref.html?' ]); // bug 681138
|
tests.push([ 'bug106855-2.html' , 'bug106855-1-ref.html?' ]); // bug 681138
|
||||||
|
tests.push([ 'bug512295-1.html' , 'bug512295-1-ref.html' ]); // bug 681152
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -129,8 +129,6 @@ struct CachedOffsetForFrame {
|
|||||||
bool mCanCacheFrameOffset; // cached frame offset is valid?
|
bool mCanCacheFrameOffset; // cached frame offset is valid?
|
||||||
};
|
};
|
||||||
|
|
||||||
static RangeData sEmptyData(nullptr);
|
|
||||||
|
|
||||||
// Stack-class to turn on/off selection batching for table selection
|
// Stack-class to turn on/off selection batching for table selection
|
||||||
class MOZ_STACK_CLASS nsSelectionBatcher MOZ_FINAL
|
class MOZ_STACK_CLASS nsSelectionBatcher MOZ_FINAL
|
||||||
{
|
{
|
||||||
@ -4525,7 +4523,8 @@ Selection::GetRangeCount(int32_t* aRangeCount)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
Selection::GetRangeAt(int32_t aIndex, nsIDOMRange** aReturn)
|
Selection::GetRangeAt(int32_t aIndex, nsIDOMRange** aReturn)
|
||||||
{
|
{
|
||||||
*aReturn = mRanges.SafeElementAt(aIndex, sEmptyData).mRange;
|
RangeData empty(nullptr);
|
||||||
|
*aReturn = mRanges.SafeElementAt(aIndex, empty).mRange;
|
||||||
if (!*aReturn) {
|
if (!*aReturn) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
@ -4538,7 +4537,8 @@ Selection::GetRangeAt(int32_t aIndex, nsIDOMRange** aReturn)
|
|||||||
nsRange*
|
nsRange*
|
||||||
Selection::GetRangeAt(int32_t aIndex)
|
Selection::GetRangeAt(int32_t aIndex)
|
||||||
{
|
{
|
||||||
return mRanges.SafeElementAt(aIndex, sEmptyData).mRange;
|
RangeData empty(nullptr);
|
||||||
|
return mRanges.SafeElementAt(aIndex, empty).mRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
7
layout/reftests/bugs/897491-1-ref.html
Normal file
7
layout/reftests/bugs/897491-1-ref.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<img id="img1" src="about:blank" alt="alt1">
|
||||||
|
<img id="img2" src="about:blank">
|
||||||
|
</body>
|
||||||
|
</html>
|
15
layout/reftests/bugs/897491-1.html
Normal file
15
layout/reftests/bugs/897491-1.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<body>
|
||||||
|
<img id="img1" src="about:blank">
|
||||||
|
<img id="img2" src="about:blank" alt="alt2">
|
||||||
|
<script>
|
||||||
|
function doTest() {
|
||||||
|
document.getElementById("img1").setAttribute("alt", "alt1");
|
||||||
|
document.getElementById("img2").removeAttribute("alt");
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
window.addEventListener("load", doTest, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
layout/reftests/bugs/897491-2-ref.html
Normal file
7
layout/reftests/bugs/897491-2-ref.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<!--quirks mode test-->
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<img id="img1" src="about:blank" alt="alt1">
|
||||||
|
<img id="img2" src="about:blank">
|
||||||
|
</body>
|
||||||
|
</html>
|
15
layout/reftests/bugs/897491-2.html
Normal file
15
layout/reftests/bugs/897491-2.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!--quirks mode test-->
|
||||||
|
<html class="reftest-wait">
|
||||||
|
<body>
|
||||||
|
<img id="img1" src="about:blank">
|
||||||
|
<img id="img2" src="about:blank" alt="alt2">
|
||||||
|
<script>
|
||||||
|
function doTest() {
|
||||||
|
document.getElementById("img1").setAttribute("alt", "alt1");
|
||||||
|
document.getElementById("img2").removeAttribute("alt");
|
||||||
|
document.documentElement.removeAttribute("class");
|
||||||
|
}
|
||||||
|
window.addEventListener("load", doTest, false);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1772,3 +1772,5 @@ test-pref(layout.css.flexbox.enabled,true) == 849407-1.html 849407-1-ref.html
|
|||||||
== 883987-1f.html 883987-1-ref.html
|
== 883987-1f.html 883987-1-ref.html
|
||||||
== 890495-1.html 890495-1-ref.html
|
== 890495-1.html 890495-1-ref.html
|
||||||
== 894931-1.html 894931-1-ref.html
|
== 894931-1.html 894931-1-ref.html
|
||||||
|
== 897491-1.html 897491-1-ref.html
|
||||||
|
== 897491-2.html 897491-2-ref.html
|
||||||
|
@ -25,8 +25,8 @@ skip-if(B2G) asserts-if(cocoaWidget,0-2) == size-change-1.html size-change-1-ref
|
|||||||
== text-ltr-alignment-test.html text-ltr-alignment-ref.html
|
== text-ltr-alignment-test.html text-ltr-alignment-ref.html
|
||||||
== text-rtl-alignment-test.html text-rtl-alignment-ref.html
|
== text-rtl-alignment-test.html text-rtl-alignment-ref.html
|
||||||
|
|
||||||
== text-horzline-with-bottom.html text-horzline.html
|
fuzzy-if(B2G&&azureSkiaGL,1,256) == text-horzline-with-bottom.html text-horzline.html
|
||||||
== text-horzline-with-top.html text-horzline.html
|
fuzzy-if(B2G&&azureSkiaGL,1,256) == text-horzline-with-top.html text-horzline.html
|
||||||
|
|
||||||
!= text-big-stroke.html text-blank.html
|
!= text-big-stroke.html text-blank.html
|
||||||
!= text-big-stroke.html text-big-fill.html
|
!= text-big-stroke.html text-big-fill.html
|
||||||
|
@ -200,7 +200,7 @@ pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-04.svg m
|
|||||||
== nested-viewBox-01.svg pass.svg
|
== nested-viewBox-01.svg pass.svg
|
||||||
== nesting-invalid-01.svg nesting-invalid-01-ref.svg
|
== nesting-invalid-01.svg nesting-invalid-01-ref.svg
|
||||||
== non-scaling-stroke-01.svg non-scaling-stroke-01-ref.svg
|
== non-scaling-stroke-01.svg non-scaling-stroke-01-ref.svg
|
||||||
fuzzy-if(Android,1,99) fuzzy-if(!contentSameGfxBackendAsCanvas,9,99) == non-scaling-stroke-02.svg non-scaling-stroke-02-ref.svg
|
fuzzy-if(Android||B2G,1,99) fuzzy-if(!contentSameGfxBackendAsCanvas,9,99) == non-scaling-stroke-02.svg non-scaling-stroke-02-ref.svg
|
||||||
== non-scaling-stroke-03.svg non-scaling-stroke-03-ref.svg
|
== non-scaling-stroke-03.svg non-scaling-stroke-03-ref.svg
|
||||||
== objectBoundingBox-and-clipPath.svg pass.svg
|
== objectBoundingBox-and-clipPath.svg pass.svg
|
||||||
# Bug 588684
|
# Bug 588684
|
||||||
|
@ -538,14 +538,6 @@ function BuildConditionSandbox(aURL) {
|
|||||||
sandbox.smallScreen = true;
|
sandbox.smallScreen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if REFTEST_B2G
|
|
||||||
// XXX nsIGfxInfo isn't available in B2G
|
|
||||||
sandbox.d2d = false;
|
|
||||||
sandbox.azureQuartz = false;
|
|
||||||
sandbox.azureSkia = false;
|
|
||||||
sandbox.azureSkiaGL = false;
|
|
||||||
sandbox.contentSameGfxBackendAsCanvas = false;
|
|
||||||
#else
|
|
||||||
var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
|
var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
|
||||||
try {
|
try {
|
||||||
sandbox.d2d = gfxInfo.D2DEnabled;
|
sandbox.d2d = gfxInfo.D2DEnabled;
|
||||||
@ -559,7 +551,6 @@ function BuildConditionSandbox(aURL) {
|
|||||||
// true if we are using the same Azure backend for rendering canvas and content
|
// true if we are using the same Azure backend for rendering canvas and content
|
||||||
sandbox.contentSameGfxBackendAsCanvas = info.AzureContentBackend == info.AzureCanvasBackend
|
sandbox.contentSameGfxBackendAsCanvas = info.AzureContentBackend == info.AzureCanvasBackend
|
||||||
|| (info.AzureContentBackend == "none" && info.AzureCanvasBackend == "cairo");
|
|| (info.AzureContentBackend == "none" && info.AzureCanvasBackend == "cairo");
|
||||||
#endif
|
|
||||||
|
|
||||||
sandbox.layersGPUAccelerated =
|
sandbox.layersGPUAccelerated =
|
||||||
gWindowUtils.layerManagerType != "Basic";
|
gWindowUtils.layerManagerType != "Basic";
|
||||||
|
@ -38,9 +38,9 @@ public class BrowserDB {
|
|||||||
|
|
||||||
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit);
|
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit);
|
||||||
|
|
||||||
// This should onlyl return frecent sites, BrowserDB.getTopSites will do the
|
// This should only return frecent bookmarks, BrowserDB.getTopBookmarks will do the
|
||||||
// work to combine that list with the pinned sites list
|
// work to combine that list with the pinned sites list
|
||||||
public Cursor getTopSites(ContentResolver cr, int limit);
|
public Cursor getTopBookmarks(ContentResolver cr, int limit);
|
||||||
|
|
||||||
public void updateVisitedHistory(ContentResolver cr, String uri);
|
public void updateVisitedHistory(ContentResolver cr, String uri);
|
||||||
|
|
||||||
@ -137,12 +137,12 @@ public class BrowserDB {
|
|||||||
return sDb.filter(cr, constraint, limit);
|
return sDb.filter(cr, constraint, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Cursor getTopSites(ContentResolver cr, int limit) {
|
public static Cursor getTopBookmarks(ContentResolver cr, int limit) {
|
||||||
// Note this is not a single query anymore, but actually returns a mixture of two queries, one for topSites
|
// Note this is not a single query anymore, but actually returns a mixture of two queries,
|
||||||
// and one for pinned sites
|
// one for top bookmarks, and one for pinned sites (which are actually bookmarks as well).
|
||||||
Cursor topSites = sDb.getTopSites(cr, limit);
|
Cursor topBookmarks = sDb.getTopBookmarks(cr, limit);
|
||||||
Cursor pinnedSites = sDb.getPinnedSites(cr, limit);
|
Cursor pinnedSites = sDb.getPinnedSites(cr, limit);
|
||||||
return new TopSitesCursorWrapper(pinnedSites, topSites, limit);
|
return new TopSitesCursorWrapper(pinnedSites, topBookmarks, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateVisitedHistory(ContentResolver cr, String uri) {
|
public static void updateVisitedHistory(ContentResolver cr, String uri) {
|
||||||
|
@ -231,9 +231,13 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor getTopSites(ContentResolver cr, int limit) {
|
public Cursor getTopBookmarks(ContentResolver cr, int limit) {
|
||||||
// Filter out sites that are pinned
|
// Only select bookmarks. Unfortunately, we need to query the combined view,
|
||||||
String selection = DBUtils.concatenateWhere("", Combined.URL + " NOT IN (SELECT " +
|
// instead of just the bookmarks table, in order to do the frecency calculation.
|
||||||
|
String selection = Combined.BOOKMARK_ID + " IS NOT NULL";
|
||||||
|
|
||||||
|
// Filter out sites that are pinned.
|
||||||
|
selection = DBUtils.concatenateWhere(selection, Combined.URL + " NOT IN (SELECT " +
|
||||||
Bookmarks.URL + " FROM bookmarks WHERE " +
|
Bookmarks.URL + " FROM bookmarks WHERE " +
|
||||||
DBUtils.qualifyColumn("bookmarks", Bookmarks.PARENT) + " == ? AND " +
|
DBUtils.qualifyColumn("bookmarks", Bookmarks.PARENT) + " == ? AND " +
|
||||||
DBUtils.qualifyColumn("bookmarks", Bookmarks.IS_DELETED) + " == 0)");
|
DBUtils.qualifyColumn("bookmarks", Bookmarks.IS_DELETED) + " == 0)");
|
||||||
|
@ -60,13 +60,18 @@ class BookmarksListAdapter extends MultiTypeCursorAdapter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves to parent folder, if one exists.
|
* Moves to parent folder, if one exists.
|
||||||
|
*
|
||||||
|
* @return Whether the adapter successfully moved to a parent folder.
|
||||||
*/
|
*/
|
||||||
public void moveToParentFolder() {
|
public boolean moveToParentFolder() {
|
||||||
// If we're already at the root, we can't move to a parent folder
|
// If we're already at the root, we can't move to a parent folder
|
||||||
if (mParentStack.size() != 1) {
|
if (mParentStack.size() == 1) {
|
||||||
mParentStack.removeFirst();
|
return false;
|
||||||
refreshCurrentFolder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mParentStack.removeFirst();
|
||||||
|
refreshCurrentFolder();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +13,7 @@ import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
@ -56,6 +57,17 @@ public class BookmarksListView extends HomeListView
|
|||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
|
|
||||||
setOnItemClickListener(this);
|
setOnItemClickListener(this);
|
||||||
|
|
||||||
|
setOnKeyListener(new View.OnKeyListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
|
// If the user hit the BACK key, try to move to the parent folder.
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
|
return getBookmarksListAdapter().moveToParentFolder();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -101,14 +113,7 @@ public class BookmarksListView extends HomeListView
|
|||||||
// Absolute position for the adapter.
|
// Absolute position for the adapter.
|
||||||
position -= headerCount;
|
position -= headerCount;
|
||||||
|
|
||||||
BookmarksListAdapter adapter;
|
final BookmarksListAdapter adapter = getBookmarksListAdapter();
|
||||||
ListAdapter listAdapter = getAdapter();
|
|
||||||
if (listAdapter instanceof HeaderViewListAdapter) {
|
|
||||||
adapter = (BookmarksListAdapter) ((HeaderViewListAdapter) listAdapter).getWrappedAdapter();
|
|
||||||
} else {
|
|
||||||
adapter = (BookmarksListAdapter) listAdapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adapter.isShowingChildFolder()) {
|
if (adapter.isShowingChildFolder()) {
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
// If we tap on an opened folder, move back to parent folder.
|
// If we tap on an opened folder, move back to parent folder.
|
||||||
@ -141,4 +146,15 @@ public class BookmarksListView extends HomeListView
|
|||||||
getOnUrlOpenListener().onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
getOnUrlOpenListener().onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BookmarksListAdapter getBookmarksListAdapter() {
|
||||||
|
BookmarksListAdapter adapter;
|
||||||
|
ListAdapter listAdapter = getAdapter();
|
||||||
|
if (listAdapter instanceof HeaderViewListAdapter) {
|
||||||
|
adapter = (BookmarksListAdapter) ((HeaderViewListAdapter) listAdapter).getWrappedAdapter();
|
||||||
|
} else {
|
||||||
|
adapter = (BookmarksListAdapter) listAdapter;
|
||||||
|
}
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,6 +149,10 @@ public class BookmarksPage extends HomeFragment {
|
|||||||
});
|
});
|
||||||
mList.setAdapter(mListAdapter);
|
mList.setAdapter(mListAdapter);
|
||||||
|
|
||||||
|
// Invalidate the cached value that keeps track of whether or
|
||||||
|
// not desktop bookmarks (or reading list items) exist.
|
||||||
|
BrowserDB.invalidateCachedState();
|
||||||
|
|
||||||
// Create callbacks before the initial loader is started.
|
// Create callbacks before the initial loader is started.
|
||||||
mLoaderCallbacks = new CursorLoaderCallbacks(activity, getLoaderManager());
|
mLoaderCallbacks = new CursorLoaderCallbacks(activity, getLoaderManager());
|
||||||
mThumbnailsLoaderCallbacks = new ThumbnailsLoaderCallbacks();
|
mThumbnailsLoaderCallbacks = new ThumbnailsLoaderCallbacks();
|
||||||
@ -362,7 +366,7 @@ public class BookmarksPage extends HomeFragment {
|
|||||||
@Override
|
@Override
|
||||||
public Cursor loadCursor() {
|
public Cursor loadCursor() {
|
||||||
final int max = getContext().getResources().getInteger(R.integer.number_of_top_sites);
|
final int max = getContext().getResources().getInteger(R.integer.number_of_top_sites);
|
||||||
return BrowserDB.getTopSites(getContext().getContentResolver(), max);
|
return BrowserDB.getTopBookmarks(getContext().getContentResolver(), max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package org.mozilla.gecko.home;
|
package org.mozilla.gecko.home;
|
||||||
|
|
||||||
import org.mozilla.gecko.EditBookmarkDialog;
|
import org.mozilla.gecko.EditBookmarkDialog;
|
||||||
|
import org.mozilla.gecko.Favicons;
|
||||||
import org.mozilla.gecko.GeckoAppShell;
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
import org.mozilla.gecko.GeckoEvent;
|
import org.mozilla.gecko.GeckoEvent;
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
@ -132,14 +133,8 @@ abstract class HomeFragment extends Fragment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: bug 897772
|
|
||||||
Bitmap bitmap = null;
|
|
||||||
if (info.favicon != null) {
|
|
||||||
bitmap = BitmapUtils.decodeByteArray(info.favicon);
|
|
||||||
}
|
|
||||||
|
|
||||||
String shortcutTitle = TextUtils.isEmpty(info.title) ? info.url.replaceAll(REGEX_URL_TO_TITLE, "") : info.title;
|
String shortcutTitle = TextUtils.isEmpty(info.title) ? info.url.replaceAll(REGEX_URL_TO_TITLE, "") : info.title;
|
||||||
GeckoAppShell.createShortcut(shortcutTitle, info.url, bitmap, "");
|
new AddToLauncherTask(info.url, shortcutTitle).execute();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +220,35 @@ abstract class HomeFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class AddToLauncherTask extends UiAsyncTask<Void, Void, String> {
|
||||||
|
private final String mUrl;
|
||||||
|
private final String mTitle;
|
||||||
|
|
||||||
|
public AddToLauncherTask(String url, String title) {
|
||||||
|
super(ThreadUtils.getBackgroundHandler());
|
||||||
|
|
||||||
|
mUrl = url;
|
||||||
|
mTitle = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doInBackground(Void... params) {
|
||||||
|
return Favicons.getInstance().getFaviconUrlForPageUrl(mUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPostExecute(String faviconUrl) {
|
||||||
|
Favicons.OnFaviconLoadedListener listener = new Favicons.OnFaviconLoadedListener() {
|
||||||
|
@Override
|
||||||
|
public void onFaviconLoaded(String url, Bitmap favicon) {
|
||||||
|
GeckoAppShell.createShortcut(mTitle, mUrl, favicon, "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Favicons.getInstance().loadFavicon(mUrl, faviconUrl, 0, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class RemoveBookmarkTask extends UiAsyncTask<Void, Void, Void> {
|
private static class RemoveBookmarkTask extends UiAsyncTask<Void, Void, Void> {
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final int mId;
|
private final int mId;
|
||||||
|
@ -113,7 +113,6 @@ public class HomeListView extends ListView
|
|||||||
public int bookmarkId;
|
public int bookmarkId;
|
||||||
public int historyId;
|
public int historyId;
|
||||||
public String url;
|
public String url;
|
||||||
public byte[] favicon;
|
|
||||||
public String title;
|
public String title;
|
||||||
public int display;
|
public int display;
|
||||||
public boolean isFolder;
|
public boolean isFolder;
|
||||||
@ -165,13 +164,6 @@ public class HomeListView extends ListView
|
|||||||
historyId = -1;
|
historyId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int faviconCol = cursor.getColumnIndex(Combined.FAVICON);
|
|
||||||
if (faviconCol != -1) {
|
|
||||||
favicon = cursor.getBlob(faviconCol);
|
|
||||||
} else {
|
|
||||||
favicon = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only have the parent column in cursors from getBookmarksInFolder.
|
// We only have the parent column in cursors from getBookmarksInFolder.
|
||||||
final int parentCol = cursor.getColumnIndex(Bookmarks.PARENT);
|
final int parentCol = cursor.getColumnIndex(Bookmarks.PARENT);
|
||||||
if (parentCol != -1) {
|
if (parentCol != -1) {
|
||||||
|
@ -587,11 +587,11 @@ AboutReader.prototype = {
|
|||||||
|
|
||||||
let start = 0;
|
let start = 0;
|
||||||
|
|
||||||
if (host.startsWith("www"))
|
if (host.startsWith("www."))
|
||||||
start = 4;
|
start = 4;
|
||||||
else if (host.startsWith("m"))
|
else if (host.startsWith("m."))
|
||||||
start = 2;
|
start = 2;
|
||||||
else if (host.startsWith("mobile"))
|
else if (host.startsWith("mobile."))
|
||||||
start = 7;
|
start = 7;
|
||||||
|
|
||||||
return host.substring(start);
|
return host.substring(start);
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
|
#include "mozilla/StaticPtr.h"
|
||||||
#ifdef MOZ_PEERCONNECTION
|
#ifdef MOZ_PEERCONNECTION
|
||||||
#include "mtransport/runnable_utils.h"
|
#include "mtransport/runnable_utils.h"
|
||||||
#endif
|
#endif
|
||||||
@ -78,7 +79,7 @@ static bool sctp_initialized;
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
class DataChannelShutdown;
|
class DataChannelShutdown;
|
||||||
nsRefPtr<DataChannelShutdown> gDataChannelShutdown;
|
StaticRefPtr<DataChannelShutdown> gDataChannelShutdown;
|
||||||
|
|
||||||
class DataChannelShutdown : public nsIObserver
|
class DataChannelShutdown : public nsIObserver
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user