Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2014-03-19 16:27:57 +01:00
Родитель eba94e048a 5d1e3faff6
Коммит cc7e315adc
456 изменённых файлов: 32647 добавлений и 21575 удалений

Просмотреть файл

@ -699,12 +699,24 @@ var Output = {
}
},
get androidBridge() {
delete this.androidBridge;
if (Utils.MozBuildApp === 'mobile/android') {
this.androidBridge = Cc['@mozilla.org/android/bridge;1'].getService(
Ci.nsIAndroidBridge);
} else {
this.androidBridge = null;
}
return this.androidBridge;
},
Android: function Android(aDetails, aBrowser) {
const ANDROID_VIEW_TEXT_CHANGED = 0x10;
const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
if (!this._bridge)
this._bridge = Cc['@mozilla.org/android/bridge;1'].getService(Ci.nsIAndroidBridge);
if (!this.androidBridge) {
return;
}
for each (let androidEvent in aDetails) {
androidEvent.type = 'Accessibility:Event';
@ -722,7 +734,7 @@ var Output = {
androidEvent.brailleOutput = this.brailleState.init(androidEvent.brailleOutput);
break;
}
this._bridge.handleGeckoMessage(JSON.stringify(androidEvent));
this.androidBridge.handleGeckoMessage(JSON.stringify(androidEvent));
}
},

Просмотреть файл

@ -21,6 +21,10 @@ XPCOMUtils.defineLazyModuleGetter(this, 'Presentation',
this.EXPORTED_SYMBOLS = ['ContentControl'];
const MOVEMENT_GRANULARITY_CHARACTER = 1;
const MOVEMENT_GRANULARITY_WORD = 2;
const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
this.ContentControl = function ContentControl(aContentScope) {
this._contentScope = Cu.getWeakReference(aContentScope);
this._vcCache = new WeakMap();
@ -31,16 +35,19 @@ this.ContentControl.prototype = {
messagesOfInterest: ['AccessFu:MoveCursor',
'AccessFu:ClearCursor',
'AccessFu:MoveToPoint',
'AccessFu:AutoMove'],
'AccessFu:AutoMove',
'AccessFu:Activate',
'AccessFu:MoveCaret',
'AccessFu:MoveByGranularity'],
start: function ContentControl_start() {
start: function cc_start() {
let cs = this._contentScope.get();
for (let message of this.messagesOfInterest) {
cs.addMessageListener(message, this);
}
},
stop: function ContentControl_stop() {
stop: function cc_stop() {
let cs = this._contentScope.get();
for (let message of this.messagesOfInterest) {
cs.removeMessageListener(message, this);
@ -59,29 +66,19 @@ this.ContentControl.prototype = {
return Utils.getVirtualCursor(this.document);
},
receiveMessage: function ContentControl_receiveMessage(aMessage) {
receiveMessage: function cc_receiveMessage(aMessage) {
Logger.debug(() => {
return ['ContentControl.receiveMessage',
this.document.location.toString(),
aMessage.name,
JSON.stringify(aMessage.json)];
});
try {
switch (aMessage.name) {
case 'AccessFu:MoveCursor':
this.handleMove(aMessage);
break;
case 'AccessFu:ClearCursor':
this.handleClear(aMessage);
break;
case 'AccessFu:MoveToPoint':
this.handleMoveToPoint(aMessage);
break;
case 'AccessFu:AutoMove':
this.handleAutoMove(aMessage);
break;
default:
break;
let func = this['handle' + aMessage.name.slice(9)]; // 'AccessFu:'.length
if (func) {
func.bind(this)(aMessage);
} else {
Logger.warning('ContentControl: Unhandled message:', aMessage.name);
}
} catch (x) {
Logger.logException(
@ -89,7 +86,7 @@ this.ContentControl.prototype = {
}
},
handleMove: function ContentControl_handleMove(aMessage) {
handleMoveCursor: function cc_handleMoveCursor(aMessage) {
let origin = aMessage.json.origin;
let action = aMessage.json.action;
let vc = this.vc;
@ -127,7 +124,7 @@ this.ContentControl.prototype = {
}
},
handleMoveToPoint: function ContentControl_handleMoveToPoint(aMessage) {
handleMoveToPoint: function cc_handleMoveToPoint(aMessage) {
let [x, y] = [aMessage.json.x, aMessage.json.y];
let rule = TraversalRules[aMessage.json.rule];
let vc = this.vc;
@ -141,16 +138,169 @@ this.ContentControl.prototype = {
this.sendToChild(vc, aMessage, delta);
},
handleClear: function ContentControl_handleClear(aMessage) {
handleClearCursor: function cc_handleClearCursor(aMessage) {
this.sendToChild(this.vc, aMessage);
this.vc.position = null;
},
handleAutoMove: function ContentControl_handleAutoMove(aMessage) {
handleAutoMove: function cc_handleAutoMove(aMessage) {
this.autoMove(null, aMessage.json);
},
getChildCursor: function ContentControl_getChildCursor(aAccessible) {
handleActivate: function cc_handleActivate(aMessage) {
let activateAccessible = (aAccessible) => {
Logger.debug(() => {
return ['activateAccessible', Logger.accessibleToString(aAccessible)];
});
try {
if (aMessage.json.activateIfKey &&
aAccessible.role != Roles.KEY) {
// Only activate keys, don't do anything on other objects.
return;
}
} catch (e) {
// accessible is invalid. Silently fail.
return;
}
if (aAccessible.actionCount > 0) {
aAccessible.doAction(0);
} else {
let control = Utils.getEmbeddedControl(aAccessible);
if (control && control.actionCount > 0) {
control.doAction(0);
}
// XXX Some mobile widget sets do not expose actions properly
// (via ARIA roles, etc.), so we need to generate a click.
// Could possibly be made simpler in the future. Maybe core
// engine could expose nsCoreUtiles::DispatchMouseEvent()?
let docAcc = Utils.AccRetrieval.getAccessibleFor(content.document);
let docX = {}, docY = {}, docW = {}, docH = {};
docAcc.getBounds(docX, docY, docW, docH);
let objX = {}, objY = {}, objW = {}, objH = {};
aAccessible.getBounds(objX, objY, objW, objH);
let x = Math.round((objX.value - docX.value) + objW.value / 2);
let y = Math.round((objY.value - docY.value) + objH.value / 2);
let node = aAccessible.DOMNode || aAccessible.parent.DOMNode;
for (let eventType of ['mousedown', 'mouseup']) {
let evt = content.document.createEvent('MouseEvents');
evt.initMouseEvent(eventType, true, true, content,
x, y, 0, 0, 0, false, false, false, false, 0, null);
node.dispatchEvent(evt);
}
}
if (aAccessible.role !== Roles.KEY) {
// Keys will typically have a sound of their own.
this._contentScope.get().sendAsyncMessage('AccessFu:Present',
Presentation.actionInvoked(aAccessible, 'click'));
}
};
let focusedAcc = Utils.AccRetrieval.getAccessibleFor(
this.document.activeElement);
if (focusedAcc && focusedAcc.role === Roles.ENTRY) {
let accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
let oldOffset = accText.caretOffset;
let newOffset = aMessage.json.offset;
let text = accText.getText(0, accText.characterCount);
if (newOffset >= 0 && newOffset <= accText.characterCount) {
accText.caretOffset = newOffset;
}
this.presentCaretChange(text, oldOffset, accText.caretOffset);
return;
}
let vc = this.vc;
if (!this.sendToChild(vc, aMessage)) {
activateAccessible(vc.position);
}
},
handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
// XXX: Add sendToChild. Right now this is only used in Android, so no need.
let direction = aMessage.json.direction;
let granularity;
switch(aMessage.json.granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
granularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
break;
case MOVEMENT_GRANULARITY_WORD:
granularity = Ci.nsIAccessiblePivot.WORD_BOUNDARY;
break;
default:
return;
}
if (direction === 'Previous') {
this.vc.movePreviousByText(granularity);
} else if (direction === 'Next') {
this.vc.moveNextByText(granularity);
}
},
presentCaretChange: function cc_presentCaretChange(
aText, aOldOffset, aNewOffset) {
if (aOldOffset !== aNewOffset) {
let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset,
aOldOffset, aOldOffset, true);
this._contentScope.get().sendAsyncMessage('AccessFu:Present', msg);
}
},
handleMoveCaret: function cc_handleMoveCaret(aMessage) {
let direction = aMessage.json.direction;
let granularity = aMessage.json.granularity;
let accessible = this.vc.position;
let accText = accessible.QueryInterface(Ci.nsIAccessibleText);
let oldOffset = accText.caretOffset;
let text = accText.getText(0, accText.characterCount);
let start = {}, end = {};
if (direction === 'Previous' && !aMessage.json.atStart) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset--;
break;
case MOVEMENT_GRANULARITY_WORD:
accText.getTextBeforeOffset(accText.caretOffset,
Ci.nsIAccessibleText.BOUNDARY_WORD_START, start, end);
accText.caretOffset = end.value === accText.caretOffset ?
start.value : end.value;
break;
case MOVEMENT_GRANULARITY_PARAGRAPH:
let startOfParagraph = text.lastIndexOf('\n', accText.caretOffset - 1);
accText.caretOffset = startOfParagraph !== -1 ? startOfParagraph : 0;
break;
}
} else if (direction === 'Next' && !aMessage.json.atEnd) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset++;
break;
case MOVEMENT_GRANULARITY_WORD:
accText.getTextAtOffset(accText.caretOffset,
Ci.nsIAccessibleText.BOUNDARY_WORD_END, start, end);
accText.caretOffset = end.value;
break;
case MOVEMENT_GRANULARITY_PARAGRAPH:
accText.caretOffset = text.indexOf('\n', accText.caretOffset + 1);
break;
}
}
this.presentCaretChange(text, oldOffset, accText.caretOffset);
},
getChildCursor: function cc_getChildCursor(aAccessible) {
let acc = aAccessible || this.vc.position;
if (Utils.isAliveAndVisible(acc) && acc.role === Roles.INTERNAL_FRAME) {
let domNode = acc.DOMNode;
@ -167,9 +317,7 @@ this.ContentControl.prototype = {
return null;
},
sendToChild: function ContentControl_sendToChild(aVirtualCursor,
aMessage,
aReplacer) {
sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer) {
let mm = this.getChildCursor(aVirtualCursor.position);
if (!mm) {
return false;
@ -186,7 +334,7 @@ this.ContentControl.prototype = {
return true;
},
sendToParent: function ContentControl_sendToParent(aMessage) {
sendToParent: function cc_sendToParent(aMessage) {
// XXX: This is a silly way to make a deep copy
let newJSON = JSON.parse(JSON.stringify(aMessage.json));
newJSON.origin = 'child';
@ -205,7 +353,7 @@ this.ContentControl.prototype = {
* precedence over given anchor.
* - moveMethod: pivot move method to use, default is 'moveNext',
*/
autoMove: function ContentControl_autoMove(aAnchor, aOptions = {}) {
autoMove: function cc_autoMove(aAnchor, aOptions = {}) {
let win = this.window;
win.clearTimeout(this._autoMove);
@ -266,4 +414,4 @@ this.ContentControl.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
Ci.nsIMessageListener
])
};
};

Просмотреть файл

@ -625,7 +625,8 @@ this.UtteranceGenerator = {
// This is because we expose the checked information on the node itself.
// XXX: this means the checked state is always appended to the end, regardless
// of the utterance ordering preference.
if (Utils.AndroidSdkVersion < 16 && aState.contains(States.CHECKABLE)) {
if ((Utils.AndroidSdkVersion < 16 || Utils.MozBuildApp === 'browser') &&
aState.contains(States.CHECKABLE)) {
let statetr = aState.contains(States.CHECKED) ?
'stateChecked' : 'stateNotChecked';
stateUtterances.push(Utils.stringBundle.GetStringFromName(statetr));

Просмотреть файл

@ -569,15 +569,13 @@ BraillePresenter.prototype = {
this.Presentation = {
get presenters() {
delete this.presenters;
this.presenters = [new VisualPresenter()];
if (Utils.MozBuildApp == 'mobile/android') {
this.presenters.push(new AndroidPresenter());
} else {
this.presenters.push(new SpeechPresenter());
this.presenters.push(new HapticPresenter());
}
let presenterMap = {
'mobile/android': [VisualPresenter, AndroidPresenter],
'b2g': [VisualPresenter, SpeechPresenter, HapticPresenter],
'browser': [VisualPresenter, SpeechPresenter, HapticPresenter,
AndroidPresenter]
};
this.presenters = [new P() for (P of presenterMap[Utils.MozBuildApp])];
return this.presenters;
},

Просмотреть файл

@ -98,7 +98,7 @@ this.Utils = {
this._AndroidSdkVersion = Services.sysinfo.getPropertyAsInt32('version');
} else {
// Most useful in desktop debugging.
this._AndroidSdkVersion = 15;
this._AndroidSdkVersion = 16;
}
}
return this._AndroidSdkVersion;

Просмотреть файл

@ -5,10 +5,6 @@
let Ci = Components.interfaces;
let Cu = Components.utils;
const MOVEMENT_GRANULARITY_CHARACTER = 1;
const MOVEMENT_GRANULARITY_WORD = 2;
const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
'resource://gre/modules/accessibility/Utils.jsm');
@ -68,86 +64,6 @@ function forwardToChild(aMessage, aListener, aVCPosition) {
return true;
}
function activateCurrent(aMessage) {
Logger.debug('activateCurrent');
function activateAccessible(aAccessible) {
try {
if (aMessage.json.activateIfKey &&
aAccessible.role != Roles.KEY) {
// Only activate keys, don't do anything on other objects.
return;
}
} catch (e) {
// accessible is invalid. Silently fail.
return;
}
if (aAccessible.actionCount > 0) {
aAccessible.doAction(0);
} else {
let control = Utils.getEmbeddedControl(aAccessible);
if (control && control.actionCount > 0) {
control.doAction(0);
}
// XXX Some mobile widget sets do not expose actions properly
// (via ARIA roles, etc.), so we need to generate a click.
// Could possibly be made simpler in the future. Maybe core
// engine could expose nsCoreUtiles::DispatchMouseEvent()?
let docAcc = Utils.AccRetrieval.getAccessibleFor(content.document);
let docX = {}, docY = {}, docW = {}, docH = {};
docAcc.getBounds(docX, docY, docW, docH);
let objX = {}, objY = {}, objW = {}, objH = {};
aAccessible.getBounds(objX, objY, objW, objH);
let x = Math.round((objX.value - docX.value) + objW.value / 2);
let y = Math.round((objY.value - docY.value) + objH.value / 2);
let node = aAccessible.DOMNode || aAccessible.parent.DOMNode;
function dispatchMouseEvent(aEventType) {
let evt = content.document.createEvent('MouseEvents');
evt.initMouseEvent(aEventType, true, true, content,
x, y, 0, 0, 0, false, false, false, false, 0, null);
node.dispatchEvent(evt);
}
dispatchMouseEvent('mousedown');
dispatchMouseEvent('mouseup');
}
if (aAccessible.role !== Roles.KEY) {
// Keys will typically have a sound of their own.
sendAsyncMessage('AccessFu:Present',
Presentation.actionInvoked(aAccessible, 'click'));
}
}
function moveCaretTo(aAccessible, aOffset) {
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
let oldOffset = accText.caretOffset;
let text = accText.getText(0, accText.characterCount);
if (aOffset >= 0 && aOffset <= accText.characterCount) {
accText.caretOffset = aOffset;
}
presentCaretChange(text, oldOffset, accText.caretOffset);
}
let focusedAcc = Utils.AccRetrieval.getAccessibleFor(content.document.activeElement);
if (focusedAcc && focusedAcc.role === Roles.ENTRY) {
moveCaretTo(focusedAcc, aMessage.json.offset);
return;
}
let position = Utils.getVirtualCursor(content.document).position;
if (!forwardToChild(aMessage, activateCurrent, position)) {
activateAccessible(position);
}
}
function activateContextMenu(aMessage) {
function sendContextMenuCoordinates(aAccessible) {
let bounds = Utils.getBounds(aAccessible);
@ -160,72 +76,6 @@ function activateContextMenu(aMessage) {
}
}
function moveByGranularity(aMessage) {
let direction = aMessage.json.direction;
let vc = Utils.getVirtualCursor(content.document);
let granularity;
switch(aMessage.json.granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
granularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
break;
case MOVEMENT_GRANULARITY_WORD:
granularity = Ci.nsIAccessiblePivot.WORD_BOUNDARY;
break;
default:
return;
}
if (direction === 'Previous') {
vc.movePreviousByText(granularity);
} else if (direction === 'Next') {
vc.moveNextByText(granularity);
}
}
function moveCaret(aMessage) {
let direction = aMessage.json.direction;
let granularity = aMessage.json.granularity;
let accessible = Utils.getVirtualCursor(content.document).position;
let accText = accessible.QueryInterface(Ci.nsIAccessibleText);
let oldOffset = accText.caretOffset;
let text = accText.getText(0, accText.characterCount);
let start = {}, end = {};
if (direction === 'Previous' && !aMessage.json.atStart) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset--;
break;
case MOVEMENT_GRANULARITY_WORD:
accText.getTextBeforeOffset(accText.caretOffset,
Ci.nsIAccessibleText.BOUNDARY_WORD_START, start, end);
accText.caretOffset = end.value === accText.caretOffset ? start.value : end.value;
break;
case MOVEMENT_GRANULARITY_PARAGRAPH:
let startOfParagraph = text.lastIndexOf('\n', accText.caretOffset - 1);
accText.caretOffset = startOfParagraph !== -1 ? startOfParagraph : 0;
break;
}
} else if (direction === 'Next' && !aMessage.json.atEnd) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset++;
break;
case MOVEMENT_GRANULARITY_WORD:
accText.getTextAtOffset(accText.caretOffset,
Ci.nsIAccessibleText.BOUNDARY_WORD_END, start, end);
accText.caretOffset = end.value;
break;
case MOVEMENT_GRANULARITY_PARAGRAPH:
accText.caretOffset = text.indexOf('\n', accText.caretOffset + 1);
break;
}
}
presentCaretChange(text, oldOffset, accText.caretOffset);
}
function presentCaretChange(aText, aOldOffset, aNewOffset) {
if (aOldOffset !== aNewOffset) {
let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset,
@ -282,12 +132,9 @@ addMessageListener(
if (m.json.buildApp)
Utils.MozBuildApp = m.json.buildApp;
addMessageListener('AccessFu:Activate', activateCurrent);
addMessageListener('AccessFu:ContextMenu', activateContextMenu);
addMessageListener('AccessFu:Scroll', scroll);
addMessageListener('AccessFu:AdjustRange', adjustRange);
addMessageListener('AccessFu:MoveCaret', moveCaret);
addMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
if (!eventManager) {
eventManager = new EventManager(this);
@ -307,11 +154,8 @@ addMessageListener(
function(m) {
Logger.debug('AccessFu:Stop');
removeMessageListener('AccessFu:Activate', activateCurrent);
removeMessageListener('AccessFu:ContextMenu', activateContextMenu);
removeMessageListener('AccessFu:Scroll', scroll);
removeMessageListener('AccessFu:MoveCaret', moveCaret);
removeMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
eventManager.stop();
contentControl.stop();

Просмотреть файл

@ -6,9 +6,11 @@ support-files =
output.js
doc_traversal.html
doc_content_integration.html
doc_content_text.html
[test_alive.html]
[test_content_integration.html]
[test_content_text.html]
[test_explicit_names.html]
[test_landmarks.html]
[test_live_regions.html]

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>Text content test document</title>
<meta charset="utf-8" />
</head>
<body>
<p>These are my awards, Mother. From Army.
The seal is for marksmanship, and the gorilla is for sand racing.</p>
<p>You're a good guy, mon frere. That means brother in French.
I don't know how I know that. I took four years of Spanish.</p>
<textarea>Please refrain from Mayoneggs during this salmonella scare.</textarea>
</body>
</html>

Просмотреть файл

@ -172,6 +172,11 @@ AccessFuContentTest.prototype = {
this.setupMessageManager(this.mms[0], function () {
// Get child message managers and set them up
var frames = currentTabDocument().querySelectorAll('iframe');
if (frames.length === 0) {
self.pump();
return;
}
var toSetup = 0;
for (var i = 0; i < frames.length; i++ ) {
var mm = Utils.getMessageManager(frames[i]);
@ -206,7 +211,8 @@ AccessFuContentTest.prototype = {
aMessageManager.addMessageListener('AccessFu:Present', this);
aMessageManager.addMessageListener('AccessFu:Ready', function () {
aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback);
aMessageManager.sendAsyncMessage('AccessFu:Start', { buildApp: 'browser' });
aMessageManager.sendAsyncMessage('AccessFu:Start',
{ buildApp: 'browser', androidSdkVersion: Utils.AndroidSdkVersion});
});
aMessageManager.loadFrameScript(
@ -242,21 +248,46 @@ AccessFuContentTest.prototype = {
return;
}
var expected = this.currentPair[1];
if (expected) {
if (expected.speak !== undefined) {
var speech = this.extractUtterance(aMessage.json);
if (!speech) {
// Probably a visual highlight adjustment after a scroll.
return;
}
var checkFunc = SimpleTest[expected.speak_checkFunc] || is;
checkFunc(speech, expected.speak);
var expected = this.currentPair[1] || {};
var speech = this.extractUtterance(aMessage.json);
var android = this.extractAndroid(aMessage.json, expected.android);
if ((speech && expected.speak) || (android && expected.android)) {
if (expected.speak) {
(SimpleTest[expected.speak_checkFunc] || is)(speech, expected.speak);
}
if (expected.android) {
var checkFunc = SimpleTest[expected.android_checkFunc] || ok;
checkFunc.apply(SimpleTest,
this.lazyCompare(android, expected.android));
}
this.pump();
}
this.pump();
},
lazyCompare: function lazyCompare(aReceived, aExpected) {
var matches = true;
var delta = [];
for (var attr in aExpected) {
var expected = aExpected[attr];
var received = aReceived !== undefined ? aReceived[attr] : null;
if (typeof expected === 'object') {
var [childMatches, childDelta] = this.lazyCompare(received, expected);
if (!childMatches) {
delta.push(attr + ' [ ' + childDelta + ' ]');
matches = false;
}
} else {
if (received !== expected) {
delta.push(
attr + ' [ expected ' + expected + ' got ' + received + ' ]');
matches = false;
}
}
}
return [matches, delta.join(' ')];
},
extractUtterance: function(aData) {
@ -270,6 +301,156 @@ AccessFuContentTest.prototype = {
}
}
return null;
},
extractAndroid: function(aData, aExpectedEvents) {
for (var output of aData) {
if (output && output.type === 'Android') {
for (var i in output.details) {
// Only extract if event types match expected event types.
var exp = aExpectedEvents ? aExpectedEvents[i] : null;
if (!exp || (output.details[i].eventType !== exp.eventType)) {
return null;
}
}
return output.details;
}
}
return null;
}
};
// Common content messages
var ContentMessages = {
simpleMoveFirst: {
name: 'AccessFu:MoveCursor',
json: {
action: 'moveFirst',
rule: 'Simple',
inputType: 'gesture',
origin: 'top'
}
},
simpleMoveLast: {
name: 'AccessFu:MoveCursor',
json: {
action: 'moveLast',
rule: 'Simple',
inputType: 'gesture',
origin: 'top'
}
},
simpleMoveNext: {
name: 'AccessFu:MoveCursor',
json: {
action: 'moveNext',
rule: 'Simple',
inputType: 'gesture',
origin: 'top'
}
},
simpleMovePrevious: {
name: 'AccessFu:MoveCursor',
json: {
action: 'movePrevious',
rule: 'Simple',
inputType: 'gesture',
origin: 'top'
}
},
clearCursor: {
name: 'AccessFu:ClearCursor',
json: {
origin: 'top'
}
},
focusSelector: function focusSelector(aSelector, aBlur) {
return {
name: 'AccessFuTest:Focus',
json: {
selector: aSelector,
blur: aBlur
}
};
},
activateCurrent: function activateCurrent(aOffset) {
return {
name: 'AccessFu:Activate',
json: {
origin: 'top',
offset: aOffset
}
};
},
moveNextBy: function moveNextBy(aGranularity) {
return {
name: 'AccessFu:MoveByGranularity',
json: {
direction: 'Next',
granularity: this._granularityMap[aGranularity]
}
};
},
movePreviousBy: function movePreviousBy(aGranularity) {
return {
name: 'AccessFu:MoveByGranularity',
json: {
direction: 'Previous',
granularity: this._granularityMap[aGranularity]
}
};
},
moveCaretNextBy: function moveCaretNextBy(aGranularity) {
return {
name: 'AccessFu:MoveCaret',
json: {
direction: 'Next',
granularity: this._granularityMap[aGranularity]
}
};
},
moveCaretPreviousBy: function moveCaretPreviousBy(aGranularity) {
return {
name: 'AccessFu:MoveCaret',
json: {
direction: 'Previous',
granularity: this._granularityMap[aGranularity]
}
};
},
_granularityMap: {
'character': 1, // MOVEMENT_GRANULARITY_CHARACTER
'word': 2, // MOVEMENT_GRANULARITY_WORD
'paragraph': 8 // MOVEMENT_GRANULARITY_PARAGRAPH
}
};
var AndroidEvent = {
VIEW_CLICKED: 0x01,
VIEW_LONG_CLICKED: 0x02,
VIEW_SELECTED: 0x04,
VIEW_FOCUSED: 0x08,
VIEW_TEXT_CHANGED: 0x10,
WINDOW_STATE_CHANGED: 0x20,
VIEW_HOVER_ENTER: 0x80,
VIEW_HOVER_EXIT: 0x100,
VIEW_SCROLLED: 0x1000,
VIEW_TEXT_SELECTION_CHANGED: 0x2000,
ANNOUNCEMENT: 0x4000,
VIEW_ACCESSIBILITY_FOCUSED: 0x8000,
VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000
};

Просмотреть файл

@ -26,163 +26,162 @@
var iframe = doc.createElement("iframe");
iframe.mozbrowser = true;
iframe.addEventListener("mozbrowserloadend", function () {
var simpleMoveNext = { name: 'AccessFu:MoveCursor',
json: { action: 'moveNext',
rule: 'Simple',
inputType: 'gesture',
origin: 'top' }
};
var contentTest = new AccessFuContentTest(
[
// Simple traversal forward
[ContentMessages.simpleMoveNext, {
speak: 'Phone status bar Traversal Rule test document'
}],
[ContentMessages.simpleMoveNext, {
speak: 'wow heading level 1 such app'
}],
[ContentMessages.simpleMoveNext, {
speak: 'many option not checked check button'
}],
// check checkbox
[ContentMessages.activateCurrent(), {
speak: 'checked'
}],
[null, {
speak: 'checked',
speak_checkFunc: 'todo_isnot'
}],
// uncheck checkbox
[ContentMessages.simpleMoveNext, {
speak: 'Home button'
}],
var simpleMovePrevious = { name: 'AccessFu:MoveCursor',
json: { action: 'movePrevious',
rule: 'Simple',
inputType: 'gesture',
origin: 'top' }
};
// Simple traversal backward
[ContentMessages.simpleMovePrevious, {
speak: 'many option checked check button such app'
}],
[ContentMessages.activateCurrent(), {
speak: 'unchecked'
}],
[null, {
speak: 'unchecked',
speak_checkFunc: 'todo_isnot'
}],
[ContentMessages.simpleMovePrevious, {
speak: 'wow heading level 1'
}],
[ContentMessages.simpleMovePrevious, {
speak: 'Phone status bar'
}],
var activateCurrent = { name: 'AccessFu:Activate',
json: { origin: 'top' } };
// Moving to the absolute last item from an embedded document
// fails. Bug 972035.
[ContentMessages.simpleMoveNext, {
speak: 'wow heading level 1 such app'
}],
// Move from an inner frame to the last element in the parent doc
[ContentMessages.simpleMoveLast, {
speak: 'Home button',
speak_checkFunc: 'todo_is'
}],
var simpleMoveLast = { name: 'AccessFu:MoveCursor',
json: { action: 'moveLast',
rule: 'Simple',
inputType: 'gesture',
origin: 'top' }
};
[ContentMessages.clearCursor, null], // Reset cursors
var simpleMoveFirst = { name: 'AccessFu:MoveCursor',
json: { action: 'moveFirst',
rule: 'Simple',
inputType: 'gesture',
origin: 'top' }
};
// Moving to the absolute first item from an embedded document
// fails. Bug 972035.
[ContentMessages.simpleMoveNext, {
speak: 'Phone status bar Traversal Rule test document'
}],
[ContentMessages.simpleMoveNext, {
speak: 'wow heading level 1 such app'
}],
[ContentMessages.simpleMoveNext, {
speak: 'many option not checked check button'
}],
[ContentMessages.simpleMoveFirst, {
speak: 'Phone status bar',
speak_checkFunc: 'todo_is'
}],
var clearCursor = { name: 'AccessFu:ClearCursor',
json: { origin: 'top' }
};
// Reset cursors
[ContentMessages.clearCursor, null],
function focusFunc(aSelector, aBlur) {
return function (mm) {
mm.sendAsyncMessage(
'AccessFuTest:Focus', { selector: aSelector, blur: aBlur });
};
}
// Move cursor with focus in outside document
[ContentMessages.simpleMoveNext, {
speak: 'Phone status bar Traversal Rule test document'
}],
[ContentMessages.focusSelector('button#home', false), {
speak: 'Home button'
}],
var contentTest = new AccessFuContentTest(
[
// Simple traversal forward
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[simpleMoveNext,
{ speak: 'wow heading level 1 such app' }],
[simpleMoveNext,
{ speak: 'many option not checked check button' }],
// check checkbox
[activateCurrent,
{ speak: 'checked' }],
[null,
{ speak: 'checked', speak_checkFunc: 'todo_isnot' }],
// uncheck checkbox
[simpleMoveNext,
{ speak: 'Home button' }],
// Blur button and reset cursor
[ContentMessages.focusSelector('button#home', true), null],
[ContentMessages.clearCursor, null],
// Simple traversal backward
[simpleMovePrevious,
{ speak: 'many option checked check button such app' }],
[activateCurrent,
{ speak: 'unchecked' }],
[null,
{ speak: 'unchecked', speak_checkFunc: 'todo_isnot' }],
[simpleMovePrevious,
{ speak: 'wow heading level 1' }],
[simpleMovePrevious,
{ speak: 'Phone status bar' }],
// Set focus on element outside of embedded frame while
// cursor is in frame
[ContentMessages.simpleMoveNext, {
speak: 'Phone status bar Traversal Rule test document'
}],
[ContentMessages.simpleMoveNext, {
speak: 'wow heading level 1 such app'
}],
[ContentMessages.focusSelector('button#home', false), {
speak: 'Home button'
}]
// Moving to the absolute last item from an embedded document fails.
// Bug 972035.
[simpleMoveNext,
{ speak: 'wow heading level 1 such app' }],
// Move from an inner frame to the last element in the parent doc
[simpleMoveLast,
{ speak: 'Home button', speak_checkFunc: 'todo_is' }],
// Blur button and reset cursor
[ContentMessages.focusSelector('button#home', true), null],
[ContentMessages.clearCursor, null],
[clearCursor, null], // Reset cursors
// XXX: Set focus on iframe itself.
// XXX: Set focus on element in iframe when cursor is outside of it.
// XXX: Set focus on element in iframe when cursor is in iframe.
// Moving to the absolute first item from an embedded document fails.
// Bug 972035.
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[simpleMoveNext,
{ speak: 'wow heading level 1 such app' }],
[simpleMoveNext,
{ speak: 'many option not checked check button' }],
[simpleMoveFirst,
{ speak: 'Phone status bar', speak_checkFunc: 'todo_is' }],
// Open dialog in outer doc, while cursor is also in outer doc
[ContentMessages.simpleMoveNext, {
speak: 'Phone status bar Traversal Rule test document'
}],
[doc.defaultView.showAlert, {
speak: 'This is an alert! heading level 1 dialog'
}],
// Reset cursors
[clearCursor, null],
[function() {
doc.defaultView.hideAlert()
}, {
speak: 'wow heading level 1 such app'
}],
// Move cursor with focus in outside document
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[ focusFunc('button#home', false), { speak: 'Home button' }],
[ContentMessages.clearCursor, null],
// Blur button and reset cursor
[focusFunc('button#home', true), null],
[clearCursor, null],
// Open dialog in outer doc, while cursor is in inner frame
[ContentMessages.simpleMoveNext, {
speak: 'Phone status bar Traversal Rule test document'
}],
[ContentMessages.simpleMoveNext, {
speak: 'wow heading level 1 such app'
}],
[doc.defaultView.showAlert, {
speak: 'This is an alert! heading level 1 dialog'
}],
// Set focus on element outside of embedded frame while cursor is in frame
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[simpleMoveNext,
{ speak: 'wow heading level 1 such app' }],
[focusFunc('button#home', false), { speak: 'Home button' }]
// XXX: Place cursor back where it was.
[doc.defaultView.hideAlert, {
speak: 'many option not checked check button such app'
}],
// Blur button and reset cursor
[focusFunc('button#home', true), null],
[clearCursor, null],
[ContentMessages.clearCursor, null],
// XXX: Set focus on iframe itself.
// XXX: Set focus on element in iframe when cursor is outside of it.
// XXX: Set focus on element in iframe when cursor is in iframe.
// Open dialog, then focus on something when closing
[ContentMessages.simpleMoveNext, {
speak: 'Phone status bar Traversal Rule test document'
}],
[doc.defaultView.showAlert, {
speak: 'This is an alert! heading level 1 dialog'
}],
// Open dialog in outer doc, while cursor is also in outer doc
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[doc.defaultView.showAlert,
{ speak: 'This is an alert! heading level 1 dialog' }],
[function () { doc.defaultView.hideAlert() },
{ speak: 'wow heading level 1 such app' }],
[clearCursor, null],
// Open dialog in outer doc, while cursor is in inner frame
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[simpleMoveNext,
{ speak: 'wow heading level 1 such app' }],
[doc.defaultView.showAlert,
{ speak: 'This is an alert! heading level 1 dialog' }],
// XXX: Place cursor back where it was.
[doc.defaultView.hideAlert,
{ speak: 'many option not checked check button such app' }],
[clearCursor, null],
// Open dialog, then focus on something when closing
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[doc.defaultView.showAlert,
{ speak: 'This is an alert! heading level 1 dialog' }],
[function () {
doc.defaultView.hideAlert();
doc.querySelector('button#home').focus();
},
{ speak: 'Home button Traversal Rule test document' }]
]);
[function() {
doc.defaultView.hideAlert();
doc.querySelector('button#home').focus();
}, {
speak: 'Home button Traversal Rule test document'
}]
]);
contentTest.start(function () {
closeBrowserWindow();

Просмотреть файл

@ -0,0 +1,259 @@
<!DOCTYPE html>
<html>
<head>
<title>Tests AccessFu content integration</title>
<meta charset="utf-8" />
<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="chrome://mochikit/content/chrome-harness.js">
</script>
<script type="application/javascript" src="../common.js"></script>
<script type="application/javascript" src="../browser.js"></script>
<script type="application/javascript" src="../events.js"></script>
<script type="application/javascript" src="../role.js"></script>
<script type="application/javascript" src="../states.js"></script>
<script type="application/javascript" src="../layout.js"></script>
<script type="application/javascript" src="jsatcommon.js"></script>
<script type="application/javascript">
function doTest() {
var doc = currentTabDocument();
var textTest = new AccessFuContentTest(
[
// Read-only text tests
[ContentMessages.simpleMoveFirst, {
speak: 'These are my awards, Mother. From Army. ' +
'The seal is for marksmanship, and the gorilla is ' +
'for sand racing. Text content test document'
}],
[ContentMessages.moveNextBy('word'), {
speak: 'These',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 0,
toIndex: 5
}]
}],
[ContentMessages.moveNextBy('word'), {
speak: 'are',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 6,
toIndex: 9
}]
}],
[ContentMessages.moveNextBy('word'), {
speak: 'my',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 10,
toIndex: 12
}]
}],
[ContentMessages.moveNextBy('word'), {
speak: 'awards,',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 13,
toIndex: 20
}]
}],
[ContentMessages.moveNextBy('word'), {
speak: 'Mother.',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 21,
toIndex: 28
}]
}],
[ContentMessages.movePreviousBy('word'), {
speak: 'awards,',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 13,
toIndex: 20
}]
}],
[ContentMessages.movePreviousBy('word'), {
speak: 'my',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 10,
toIndex: 12
}]
}],
[ContentMessages.movePreviousBy('word'), {
speak: 'are',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 6,
toIndex: 9
}]
}],
[ContentMessages.movePreviousBy('word'), {
speak: 'These',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 0,
toIndex: 5
}]
}],
// XXX: Bug 980510: doing next after text traversal should
// bring us to the next paragraph.
[ContentMessages.simpleMoveNext, {
speak: 'You\'re a good guy, mon frere. ' +
'That means brother in French. ' +
'I don\'t know how I know that. ' +
'I took four years of Spanish.',
speak_checkFunc: 'todo_is' // Bug 980510
}],
// XXX: extra move op here because of bug 980510.
[ContentMessages.simpleMoveNext, {
speak: 'You\'re a good guy, mon frere. ' +
'That means brother in French. ' +
'I don\'t know how I know that. ' +
'I took four years of Spanish.',
}],
// XXX: Word boundary should be past the apostraphe.
[ContentMessages.moveNextBy('word'), {
speak: 'You\'re',
speak_checkFunc: 'todo_is', // Bug 980509
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 0,
toIndex: 6
}],
android_checkFunc: 'todo' // Bug 980512
}],
// Editable text tests.
[ContentMessages.focusSelector('textarea'), {
speak: 'Please refrain from Mayoneggs during this ' +
'salmonella scare. text area'
}],
[null, { // When we first focus, caret is at 0.
android: [{
eventType: AndroidEvent.VIEW_TEXT_SELECTION_CHANGED,
brailleOutput: {
selectionStart: 0,
selectionEnd: 0
}
}]
}
],
[ContentMessages.activateCurrent(10), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 0,
toIndex: 10
}]
}],
[null, {
android: [{
eventType: AndroidEvent.VIEW_TEXT_SELECTION_CHANGED,
brailleOutput: {
selectionStart: 10,
selectionEnd: 10
}
}]
}],
[ContentMessages.activateCurrent(20), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 10,
toIndex: 20
}]
}],
[null, {
android: [{
eventType: AndroidEvent.VIEW_TEXT_SELECTION_CHANGED,
brailleOutput: {
selectionStart: 20,
selectionEnd: 20
}
}]
}],
[ContentMessages.moveCaretNextBy('word'), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 20,
toIndex: 29
}]
}],
[ContentMessages.moveCaretNextBy('word'), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 29,
toIndex: 36
}]
}],
[ContentMessages.moveCaretNextBy('character'), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 36,
toIndex: 37
}]
}],
[ContentMessages.moveCaretNextBy('character'), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 37,
toIndex: 38
}]
}],
[ContentMessages.moveCaretNextBy('paragraph'), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 38,
toIndex: 59
}]
}],
[ContentMessages.moveCaretPreviousBy('word'), {
android: [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: 53,
toIndex: 59
}]
}]
]);
textTest.start(function () {
closeBrowserWindow();
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(
function () {
openBrowserWindow(
doTest,
getRootDirectory(window.location.href) + "doc_content_text.html");
});
</script>
</head>
<body id="body">
<a target="_blank"
title="Add tests for text editing and navigating"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=972047">Mozilla Bug 933808</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

Просмотреть файл

@ -4,6 +4,6 @@
"branch": "",
"revision": ""
},
"revision": "ca4f67df676ef3ab0072b9e3fb97baee4d4bde36",
"revision": "91e5760ff948d3bef3959866c6a1744991560ef6",
"repo_path": "/integration/gaia-central"
}

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>

Просмотреть файл

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2346ad9002062d70b6b27978c6b942f04192bf1b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="db2ef2b61c70889533a0837fa3e053d24e95fdea"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -1403,3 +1403,10 @@ pref("ui.key.menuAccessKeyFocuses", true);
// Delete HTTP cache v2 data of users that didn't opt-in manually
pref("browser.cache.auto_delete_cache_version", 1);
// Telemetry experiments settings.
pref("experiments.enabled", false);
pref("experiments.manifest.fetchIntervalSeconds", 86400);
pref("experiments.manifest.uri", "https://telemetry-experiment.cdn.mozilla.net/manifest/v1/firefox/%VERSION%/%CHANNEL%");
pref("experiments.manifest.certs.1.commonName", "*.cdn.mozilla.net");
pref("experiments.manifest.certs.1.issuerName", "CN=Cybertrust Public SureServer SV CA,O=Cybertrust Inc");

Просмотреть файл

@ -1186,13 +1186,6 @@ var gBrowserInit = {
WindowsPrefSync.init();
}
if (gMultiProcessBrowser) {
// Bug 862519 - Backspace doesn't work in electrolysis builds.
// We bypass the problem by disabling the backspace-to-go-back command.
document.getElementById("cmd_handleBackspace").setAttribute("disabled", true);
document.getElementById("key_delete").setAttribute("disabled", true);
}
SessionStore.promiseInitialized.then(() => {
// Bail out if the window has been closed in the meantime.
if (window.closed) {

Просмотреть файл

@ -61,4 +61,5 @@ run-if = crashreporter
[browser_pluginplaypreview2.js]
[browser_pluginCrashCommentAndURL.js]
run-if = crashreporter
skip-if = os == "linux" && debug # bug 933680
[browser_plugins_added_dynamically.js]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,4 @@
component {f7800463-3b97-47f9-9341-b7617e6d8d49} ExperimentsService.js
contract @mozilla.org/browser/experiments-service;1 {f7800463-3b97-47f9-9341-b7617e6d8d49}
category update-timer ExperimentsService @mozilla.org/browser/experiments-service;1,getService,experiments-update-timer,experiments.manifest.fetchIntervalSeconds,86400
category profile-after-change ExperimentsService @mozilla.org/browser/experiments-service;1

Просмотреть файл

@ -0,0 +1,37 @@
/* 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/. */
"use strict";
const {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/experiments/Experiments.jsm");
Cu.import("resource://gre/modules/osfile.jsm")
function ExperimentsService() {
}
ExperimentsService.prototype = {
classID: Components.ID("{f7800463-3b97-47f9-9341-b7617e6d8d49}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback, Ci.nsIObserver]),
notify: function (timer) {
if (OS.Constants.Path.profileDir === undefined) {
throw Error("Update timer fired before profile was initialized?");
}
Experiments.instance().updateManifest();
},
observe: function (subject, topic, data) {
switch (topic) {
case "profile-after-change":
Experiments.instance(); // for side effects
break;
}
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ExperimentsService]);

Просмотреть файл

@ -0,0 +1,16 @@
# 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/.
EXTRA_COMPONENTS += [
'Experiments.manifest',
'ExperimentsService.js',
]
JS_MODULES_PATH = 'modules/experiments'
EXTRA_JS_MODULES += [
'Experiments.jsm',
]
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']

Двоичные данные
browser/experiments/test/experiment-1.xpi Normal file

Двоичный файл не отображается.

Двоичные данные
browser/experiments/test/experiment-1a.xpi Normal file

Двоичный файл не отображается.

Двоичные данные
browser/experiments/test/experiment-2.xpi Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,19 @@
{
"version": 1,
"experiments": [
{
"id": "test-experiment-1@tests.mozilla.org",
"xpiURL": "https://experiments.mozilla.org/foo.xpi",
"xpiHash": "sha1:cb1eb32b89d86d78b7326f416cf404548c5e0099",
"startTime": 1393000000,
"endTime": 1394000000,
"appName": ["Firefox", "Fennec"],
"minVersion": "28",
"maxVersion": "30",
"maxActiveSeconds": 60,
"os": ["windows", "linux", "osx"],
"channel": ["daily", "weekly", "nightly"],
"jsfilter": "function filter(context) { return true; }"
}
]
}

Просмотреть файл

@ -0,0 +1,131 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://services-sync/healthreport.jsm", this);
Cu.import("resource://testing-common/services/healthreport/utils.jsm", this);
Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
const EXPERIMENT1_ID = "test-experiment-1@tests.mozilla.org";
const EXPERIMENT1_XPI_SHA1 = "sha1:08c4d3ef1d0fc74faa455e85106ef0bc8cf8ca90";
const EXPERIMENT1_XPI_NAME = "experiment-1.xpi";
const EXPERIMENT1_NAME = "Test experiment 1";
const EXPERIMENT1A_XPI_SHA1 = "sha1:2b8d14e3e06a54d5ce628fe3598cbb364cff9e6b";
const EXPERIMENT1A_XPI_NAME = "experiment-1a.xpi";
const EXPERIMENT1A_NAME = "Test experiment 1.1";
const EXPERIMENT2_ID = "test-experiment-2@tests.mozilla.org"
const EXPERIMENT2_XPI_SHA1 = "sha1:81877991ec70360fb48db84c34a9b2da7aa41d6a";
const EXPERIMENT2_XPI_NAME = "experiment-2.xpi";
let gAppInfo = null;
function getReporter(name, uri, inspected) {
return Task.spawn(function init() {
let reporter = getHealthReporter(name, uri, inspected);
yield reporter.init();
yield reporter._providerManager.registerProviderFromType(
HealthReportProvider);
throw new Task.Result(reporter);
});
}
function removeCacheFile() {
let path = OS.Path.join(OS.Constants.Path.profileDir, "experiments.json");
return OS.File.remove(path);
}
function disableCertificateChecks() {
let pref = "experiments.manifest.cert.checkAttributes";
Services.prefs.setBoolPref(pref, false);
do_register_cleanup(() => Services.prefs.clearUserPref(pref));
}
function patchPolicy(policy, data) {
for (let key of Object.keys(data)) {
Object.defineProperty(policy, key, {
value: data[key],
writable: true,
});
}
}
function defineNow(policy, time) {
patchPolicy(policy, { now: () => new Date(time) });
}
function futureDate(date, offset) {
return new Date(date.getTime() + offset);
}
function dateToSeconds(date) {
return date.getTime() / 1000;
}
function createAppInfo(options) {
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
let options = options || {};
let id = options.id || "xpcshell@tests.mozilla.org";
let name = options.name || "XPCShell";
let version = options.version || "1.0";
let platformVersion = options.platformVersion || "1.0";
let date = options.date || new Date();
let buildID = "" + date.getYear() + date.getMonth() + date.getDate() + "01";
gAppInfo = {
// nsIXULAppInfo
vendor: "Mozilla",
name: name,
ID: id,
version: version,
appBuildID: buildID,
platformVersion: platformVersion ? platformVersion : "1.0",
platformBuildID: buildID,
// nsIXULRuntime
inSafeMode: false,
logConsoleErrors: true,
OS: "XPCShell",
XPCOMABI: "noarch-spidermonkey",
invalidateCachesOnRestart: function invalidateCachesOnRestart() {
// Do nothing
},
// nsICrashReporter
annotations: {},
annotateCrashReport: function(key, data) {
this.annotations[key] = data;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
Ci.nsIXULRuntime,
Ci.nsICrashReporter,
Ci.nsISupports])
};
let XULAppInfoFactory = {
createInstance: function (outer, iid) {
if (outer != null) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return gAppInfo.QueryInterface(iid);
}
};
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
XULAPPINFO_CONTRACTID, XULAppInfoFactory);
}

Просмотреть файл

@ -0,0 +1,138 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource:///modules/experiments/Experiments.jsm");
const FILE_MANIFEST = "experiments.manifest";
const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
const PREF_LOGGING_LEVEL = "experiments.logging.level";
const PREF_LOGGING_DUMP = "experiments.logging.dump";
const PREF_MANIFEST_URI = "experiments.manifest.uri";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
let gProfileDir = null;
let gHttpServer = null;
let gHttpRoot = null;
let gReporter = null;
let gPolicy = null;
let gGlobalScope = this;
function loadAddonManager() {
let ns = {};
Cu.import("resource://gre/modules/Services.jsm", ns);
let head = "../../../../toolkit/mozapps/extensions/test/xpcshell/head_addons.js";
let file = do_get_file(head);
let uri = ns.Services.io.newFileURI(file);
ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
startupManager();
}
function ManifestEntry(data) {
this.id = data.id || EXPERIMENT1_ID;
this.xpiURL = data.xpiURL || gHttpRoot + EXPERIMENT1_XPI_NAME;
this.xpiHash = data.xpiHash || EXPERIMENT1_XPI_SHA1;
this.appName = data.appName || ["XPCShell"];
this.channel = data.appName || ["nightly"];
this.startTime = data.startTime || new Date(2010, 0, 1, 12).getTime() / 1000;
this.endTime = data.endTime || new Date(9001, 0, 1, 12).getTime() / 1000;
this.maxActiveSeconds = data.maxActiveSeconds || 5 * SEC_IN_ONE_DAY;
}
function run_test() {
run_next_test();
}
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
gPolicy = new Experiments.Policy();
gHttpServer = new HttpServer();
gHttpServer.start(-1);
let port = gHttpServer.identity.primaryPort;
gHttpRoot = "http://localhost:" + port + "/";
gHttpServer.registerDirectory("/", do_get_cwd());
do_register_cleanup(() => gHttpServer.stop(() => {}));
gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true);
patchPolicy(gPolicy, {
updatechannel: () => "nightly",
healthReportPayload: () => Promise.resolve(payload),
});
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
let experiments = new Experiments.Experiments();
});
function isApplicable(experiment) {
let deferred = Promise.defer();
experiment.isApplicable().then(
result => deferred.resolve({ applicable: true, reason: null }),
reason => deferred.resolve({ applicable: false, reason: reason })
);
return deferred.promise;
}
add_task(function* test_startStop() {
let baseDate = new Date(2014, 5, 1, 12);
let startDate = futureDate(baseDate, 30 * MS_IN_ONE_DAY);
let endDate = futureDate(baseDate, 60 * MS_IN_ONE_DAY);
let manifestData = new ManifestEntry({
startTime: dateToSeconds(startDate),
endTime: dateToSeconds(endDate),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
});
let experiment = new Experiments.ExperimentEntry(gPolicy);
experiment.initFromManifestData(manifestData);
let result;
defineNow(gPolicy, baseDate);
result = yield isApplicable(experiment);
Assert.equal(result.applicable, false, "Experiment should not be applicable.");
Assert.equal(experiment.enabled, false, "Experiment should not be enabled.");
defineNow(gPolicy, futureDate(startDate, 5 * MS_IN_ONE_DAY));
result = yield isApplicable(experiment);
Assert.equal(result.applicable, true, "Experiment should now be applicable.");
Assert.equal(experiment.enabled, false, "Experiment should not be enabled.");
yield experiment.start();
Assert.equal(experiment.enabled, true, "Experiment should now be enabled.");
yield experiment.stop();
Assert.equal(experiment.enabled, false, "Experiment should not be enabled.");
yield experiment.start();
Assert.equal(experiment.enabled, true, "Experiment should now be enabled.");
let shouldStop = yield experiment._shouldStop();
Assert.equal(shouldStop, false, "shouldStop should be false.");
let maybeStop = yield experiment.maybeStop();
Assert.equal(maybeStop, false, "Experiment should not have been stopped.");
Assert.equal(experiment.enabled, true, "Experiment should be enabled.");
defineNow(gPolicy, futureDate(endDate, MS_IN_ONE_DAY));
shouldStop = yield experiment._shouldStop();
Assert.equal(shouldStop, true, "shouldStop should now be true.");
maybeStop = yield experiment.maybeStop();
Assert.equal(maybeStop, true, "Experiment should have been stopped.");
Assert.equal(experiment.enabled, false, "Experiment should be disabled.");
});
add_task(function* shutdown() {
yield gReporter._shutdown();
yield removeCacheFile();
});

Просмотреть файл

@ -0,0 +1,762 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://testing-common/httpd.js");
XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
"resource:///modules/experiments/Experiments.jsm");
const FILE_MANIFEST = "experiments.manifest";
const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
const PREF_LOGGING_LEVEL = "experiments.logging.level";
const PREF_LOGGING_DUMP = "experiments.logging.dump";
const PREF_MANIFEST_URI = "experiments.manifest.uri";
const PREF_FETCHINTERVAL = "experiments.manifest.fetchIntervalSeconds";
const MANIFEST_HANDLER = "manifests/handler";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
let gProfileDir = null;
let gHttpServer = null;
let gHttpRoot = null;
let gDataRoot = null;
let gReporter = null;
let gPolicy = null;
let gManifestObject = null;
let gManifestHandlerURI = null;
let gTimerScheduleOffset = -1;
let gGlobalScope = this;
function loadAddonManager() {
let ns = {};
Cu.import("resource://gre/modules/Services.jsm", ns);
let head = "../../../../toolkit/mozapps/extensions/test/xpcshell/head_addons.js";
let file = do_get_file(head);
let uri = ns.Services.io.newFileURI(file);
ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
startupManager();
}
function run_test() {
run_next_test();
}
add_task(function* test_setup() {
loadAddonManager();
gProfileDir = do_get_profile();
gHttpServer = new HttpServer();
gHttpServer.start(-1);
let port = gHttpServer.identity.primaryPort;
gHttpRoot = "http://localhost:" + port + "/";
gDataRoot = gHttpRoot + "data/";
gManifestHandlerURI = gHttpRoot + MANIFEST_HANDLER;
gHttpServer.registerDirectory("/data/", do_get_cwd());
gHttpServer.registerPathHandler("/" + MANIFEST_HANDLER, (request, response) => {
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify(gManifestObject));
response.processAsync();
response.finish();
});
do_register_cleanup(() => gHttpServer.stop(() => {}));
disableCertificateChecks();
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
Services.prefs.setCharPref(PREF_MANIFEST_URI, gManifestHandlerURI);
Services.prefs.setIntPref(PREF_FETCHINTERVAL, 0);
gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true);
gPolicy = new Experiments.Policy();
patchPolicy(gPolicy, {
updatechannel: () => "nightly",
healthReportPayload: () => Promise.resolve(payload),
oneshotTimer: (callback, timeout, thisObj, name) => gTimerScheduleOffset = timeout,
});
});
// Test basic starting and stopping of experiments.
add_task(function* test_getExperiments() {
const OBSERVER_TOPIC = "experiments-changed";
let observerFireCount = 0;
let expectedObserverFireCount = 0;
let observer = () => ++observerFireCount;
Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
// Dates the following tests are based on.
let baseDate = new Date(2014, 5, 1, 12);
let startDate1 = futureDate(baseDate, 50 * MS_IN_ONE_DAY);
let endDate1 = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
let startDate2 = futureDate(baseDate, 150 * MS_IN_ONE_DAY);
let endDate2 = futureDate(baseDate, 200 * MS_IN_ONE_DAY);
// The manifest data we test with.
gManifestObject = {
"version": 1,
experiments: [
{
id: EXPERIMENT2_ID,
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
xpiHash: EXPERIMENT2_XPI_SHA1,
startTime: dateToSeconds(startDate2),
endTime: dateToSeconds(endDate2),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
{
id: EXPERIMENT1_ID,
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
xpiHash: EXPERIMENT1_XPI_SHA1,
startTime: dateToSeconds(startDate1),
endTime: dateToSeconds(endDate1),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
],
};
// Data to compare the result of Experiments.getExperiments() against.
let experimentListData = [
{
id: EXPERIMENT2_ID,
name: "Test experiment 2",
description: "And yet another experiment that experiments experimentally.",
},
{
id: EXPERIMENT1_ID,
name: EXPERIMENT1_NAME,
description: "Yet another experiment that experiments experimentally.",
},
];
let experiments = new Experiments.Experiments(gPolicy);
// Trigger update, clock set to before any activation.
// Use updateManifest() to provide for coverage of that path.
let now = baseDate;
gTimerScheduleOffset = -1;
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, 0,
"Experiments observer should not have been called yet.");
let list = yield experiments.getExperiments();
Assert.equal(list.length, 0, "Experiment list should be empty.");
// Trigger update, clock set for experiment 1 to start.
now = futureDate(startDate1, 5 * MS_IN_ONE_DAY);
gTimerScheduleOffset = -1;
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
experimentListData[1].active = true;
experimentListData[1].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
for (let k of Object.keys(experimentListData[1])) {
Assert.equal(experimentListData[1][k], list[0][k],
"Property " + k + " should match reference data.");
}
Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY,
"Experiment re-evaluation should have been scheduled correctly.");
// Trigger update, clock set for experiment 1 to stop.
now = futureDate(endDate1, 1000);
gTimerScheduleOffset = -1;
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
experimentListData[1].active = false;
experimentListData[1].endDate = now.getTime();
for (let k of Object.keys(experimentListData[1])) {
Assert.equal(experimentListData[1][k], list[0][k],
"Property " + k + " should match reference data.");
}
Assert.equal(gTimerScheduleOffset, startDate2 - now,
"Experiment re-evaluation should have been scheduled correctly.");
// Trigger update, clock set for experiment 2 to start.
// Use notify() to provide for coverage of that path.
now = startDate2;
gTimerScheduleOffset = -1;
defineNow(gPolicy, now);
experiments.notify();
yield experiments._pendingTasksDone();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 2, "Experiment list should have 2 entries now.");
experimentListData[0].active = true;
experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
for (let i=0; i<experimentListData.length; ++i) {
let entry = experimentListData[i];
for (let k of Object.keys(entry)) {
Assert.equal(entry[k], list[i][k],
"Entry " + i + " - Property '" + k + "' should match reference data.");
}
}
Assert.equal(gTimerScheduleOffset, 10 * MS_IN_ONE_DAY,
"Experiment re-evaluation should have been scheduled correctly.");
// Trigger update, clock set for experiment 2 to stop.
now = futureDate(startDate2, 10 * MS_IN_ONE_DAY + 1000);
gTimerScheduleOffset = -1;
defineNow(gPolicy, now);
experiments.notify();
yield experiments._pendingTasksDone();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 2, "Experiment list should have 2 entries now.");
experimentListData[0].active = false;
experimentListData[0].endDate = now.getTime();
for (let i=0; i<experimentListData.length; ++i) {
let entry = experimentListData[i];
for (let k of Object.keys(entry)) {
Assert.equal(entry[k], list[i][k],
"Entry " + i + " - Property '" + k + "' should match reference data.");
}
}
// Cleanup.
Services.obs.removeObserver(observer, OBSERVER_TOPIC);
yield experiments.uninit();
yield removeCacheFile();
});
// Test explicitly disabling experiments.
add_task(function* test_disableExperiment() {
// Dates this test is based on.
let startDate = new Date(2004, 10, 9, 12);
let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY);
// The manifest data we test with.
gManifestObject = {
"version": 1,
experiments: [
{
id: EXPERIMENT1_ID,
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
xpiHash: EXPERIMENT1_XPI_SHA1,
startTime: dateToSeconds(startDate),
endTime: dateToSeconds(endDate),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
],
};
// Data to compare the result of Experiments.getExperiments() against.
let experimentInfo = {
id: EXPERIMENT1_ID,
name: EXPERIMENT1_NAME,
description: "Yet another experiment that experiments experimentally.",
};
let experiments = new Experiments.Experiments(gPolicy);
// Trigger update, clock set for the experiment to start.
let now = futureDate(startDate, 5 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.updateManifest();
let list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
experimentInfo.active = true;
experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
for (let k of Object.keys(experimentInfo)) {
Assert.equal(experimentInfo[k], list[0][k],
"Property " + k + " should match reference data.");
}
// Test disabling the experiment.
now = futureDate(now, 1 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.disableExperiment(EXPERIMENT1_ID);
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
experimentInfo.active = false;
experimentInfo.endDate = now.getTime();
for (let k of Object.keys(experimentInfo)) {
Assert.equal(experimentInfo[k], list[0][k],
"Property " + k + " should match reference data.");
}
// Test that updating the list doesn't re-enable it.
now = futureDate(now, 1 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.updateManifest();
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
for (let k of Object.keys(experimentInfo)) {
Assert.equal(experimentInfo[k], list[0][k],
"Property " + k + " should match reference data.");
}
// Cleanup.
yield experiments.uninit();
yield removeCacheFile();
});
add_task(function* test_disableExperimentsFeature() {
// Dates this test is based on.
let startDate = new Date(2004, 10, 9, 12);
let endDate = futureDate(startDate, 100 * MS_IN_ONE_DAY);
// The manifest data we test with.
gManifestObject = {
"version": 1,
experiments: [
{
id: EXPERIMENT1_ID,
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
xpiHash: EXPERIMENT1_XPI_SHA1,
startTime: dateToSeconds(startDate),
endTime: dateToSeconds(endDate),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
],
};
// Data to compare the result of Experiments.getExperiments() against.
let experimentInfo = {
id: EXPERIMENT1_ID,
name: EXPERIMENT1_NAME,
description: "Yet another experiment that experiments experimentally.",
};
let experiments = new Experiments.Experiments(gPolicy);
Assert.equal(experiments.enabled, true, "Experiments feature should be enabled.");
// Trigger update, clock set for the experiment to start.
let now = futureDate(startDate, 5 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.updateManifest();
let list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
experimentInfo.active = true;
experimentInfo.endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
for (let k of Object.keys(experimentInfo)) {
Assert.equal(experimentInfo[k], list[0][k],
"Property " + k + " should match reference data.");
}
// Test disabling experiments.
yield experiments._toggleExperimentsEnabled(false);
Assert.equal(experiments.enabled, false, "Experiments feature should be disabled now.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
experimentInfo.active = false;
experimentInfo.endDate = now.getTime();
for (let k of Object.keys(experimentInfo)) {
Assert.equal(experimentInfo[k], list[0][k],
"Property " + k + " should match reference data.");
}
// Test that updating the list doesn't re-enable it.
now = futureDate(now, 1 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
try {
yield experiments.updateManifest();
} catch (e) {
// Exception expected, the feature is disabled.
}
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry.");
for (let k of Object.keys(experimentInfo)) {
Assert.equal(experimentInfo[k], list[0][k],
"Property " + k + " should match reference data.");
}
// Cleanup.
yield experiments.uninit();
yield removeCacheFile();
});
// Test that after a failed experiment install:
// * the next applicable experiment gets installed
// * changing the experiments data later triggers re-evaluation
add_task(function* test_installFailure() {
const OBSERVER_TOPIC = "experiments-changed";
let observerFireCount = 0;
let expectedObserverFireCount = 0;
let observer = () => ++observerFireCount;
Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
// Dates the following tests are based on.
let baseDate = new Date(2014, 5, 1, 12);
let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
// The manifest data we test with.
gManifestObject = {
"version": 1,
experiments: [
{
id: EXPERIMENT1_ID,
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
xpiHash: EXPERIMENT1_XPI_SHA1,
startTime: dateToSeconds(startDate),
endTime: dateToSeconds(endDate),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
{
id: EXPERIMENT2_ID,
xpiURL: gDataRoot + EXPERIMENT2_XPI_NAME,
xpiHash: EXPERIMENT2_XPI_SHA1,
startTime: dateToSeconds(startDate),
endTime: dateToSeconds(endDate),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
],
};
// Data to compare the result of Experiments.getExperiments() against.
let experimentListData = [
{
id: EXPERIMENT1_ID,
name: EXPERIMENT1_NAME,
description: "Yet another experiment that experiments experimentally.",
},
{
id: EXPERIMENT2_ID,
name: "Test experiment 2",
description: "And yet another experiment that experiments experimentally.",
},
];
let experiments = new Experiments.Experiments(gPolicy);
// Trigger update, clock set to before any activation.
let now = baseDate;
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, 0,
"Experiments observer should not have been called yet.");
let list = yield experiments.getExperiments();
Assert.equal(list.length, 0, "Experiment list should be empty.");
// Trigger update, clock set for experiment 1 & 2 to start,
// invalid hash for experiment 1.
// Order in the manifest matters, so we should start experiment 1,
// fail to install it & start experiment 2 instead.
now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
gManifestObject.experiments[0].xpiHash = "sha1:0000000000000000000000000000000000000000";
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry.");
Assert.equal(list[0].active, true, "Experiment 2 should be active.");
// Trigger update, clock set for experiment 2 to stop.
now = futureDate(now, 20 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
experimentListData[0].active = false;
experimentListData[0].endDate = now;
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
Assert.equal(list[0].id, EXPERIMENT2_ID, "Experiment 2 should be the sole entry.");
Assert.equal(list[0].active, false, "Experiment should not be active.");
// Trigger update with a fixed entry for experiment 1,
// which should get re-evaluated & started now.
now = futureDate(now, 20 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
gManifestObject.experiments[0].xpiHash = EXPERIMENT1_XPI_SHA1;
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
experimentListData[0].active = true;
experimentListData[0].endDate = now.getTime() + 10 * MS_IN_ONE_DAY;
list = yield experiments.getExperiments();
Assert.equal(list.length, 2, "Experiment list should have 2 entries now.");
for (let i=0; i<experimentListData.length; ++i) {
let entry = experimentListData[i];
for (let k of Object.keys(entry)) {
Assert.equal(entry[k], list[i][k],
"Entry " + i + " - Property '" + k + "' should match reference data.");
}
}
// Cleanup.
Services.obs.removeObserver(observer, OBSERVER_TOPIC);
yield experiments.uninit();
yield removeCacheFile();
});
// Test that after an experiment was disabled by user action,
// the experiment is not activated again if manifest data changes.
add_task(function* test_userDisabledAndUpdated() {
const OBSERVER_TOPIC = "experiments-changed";
let observerFireCount = 0;
let expectedObserverFireCount = 0;
let observer = () => ++observerFireCount;
Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
// Dates the following tests are based on.
let baseDate = new Date(2014, 5, 1, 12);
let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
// The manifest data we test with.
gManifestObject = {
"version": 1,
experiments: [
{
id: EXPERIMENT1_ID,
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
xpiHash: EXPERIMENT1_XPI_SHA1,
startTime: dateToSeconds(startDate),
endTime: dateToSeconds(endDate),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
],
};
let experiments = new Experiments.Experiments(gPolicy);
// Trigger update, clock set to before any activation.
let now = baseDate;
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, 0,
"Experiments observer should not have been called yet.");
let list = yield experiments.getExperiments();
Assert.equal(list.length, 0, "Experiment list should be empty.");
// Trigger update, clock set for experiment 1 to start.
now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
Assert.equal(list[0].active, true, "Experiment 1 should be active.");
// Explicitly disable an experiment.
now = futureDate(now, 20 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.disableExperiment(EXPERIMENT1_ID);
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
Assert.equal(list[0].active, false, "Experiment should not be active anymore.");
// Trigger an update with a faked change for experiment 1.
now = futureDate(now, 20 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
experiments._experiments.get(EXPERIMENT1_ID)._manifestData.xpiHash =
"sha1:0000000000000000000000000000000000000000";
yield experiments.updateManifest();
Assert.equal(observerFireCount, expectedObserverFireCount,
"Experiments observer should not have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
Assert.equal(list[0].active, false, "Experiment should still be inactive.");
// Cleanup.
Services.obs.removeObserver(observer, OBSERVER_TOPIC);
yield experiments.uninit();
yield removeCacheFile();
});
// Test that changing the hash for an active experiments triggers an
// update for it.
add_task(function* test_updateActiveExperiment() {
const OBSERVER_TOPIC = "experiments-changed";
let observerFireCount = 0;
let expectedObserverFireCount = 0;
let observer = () => ++observerFireCount;
Services.obs.addObserver(observer, OBSERVER_TOPIC, false);
// Dates the following tests are based on.
let baseDate = new Date(2014, 5, 1, 12);
let startDate = futureDate(baseDate, 100 * MS_IN_ONE_DAY);
let endDate = futureDate(baseDate, 10000 * MS_IN_ONE_DAY);
// The manifest data we test with.
gManifestObject = {
"version": 1,
experiments: [
{
id: EXPERIMENT1_ID,
xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
xpiHash: EXPERIMENT1_XPI_SHA1,
startTime: dateToSeconds(startDate),
endTime: dateToSeconds(endDate),
maxActiveSeconds: 10 * SEC_IN_ONE_DAY,
appName: ["XPCShell"],
channel: ["nightly"],
},
],
};
let experiments = new Experiments.Experiments(gPolicy);
// Trigger update, clock set to before any activation.
let now = baseDate;
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, 0,
"Experiments observer should not have been called yet.");
let list = yield experiments.getExperiments();
Assert.equal(list.length, 0, "Experiment list should be empty.");
// Trigger update, clock set for the experiment to start.
now = futureDate(startDate, 10 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
Assert.equal(list[0].active, true, "Experiment 1 should be active.");
Assert.equal(list[0].name, EXPERIMENT1_NAME, "Experiments name should match.");
// Trigger an update for the active experiment by changing it's hash (and xpi)
// in the manifest.
now = futureDate(now, 1 * MS_IN_ONE_DAY);
defineNow(gPolicy, now);
gManifestObject.experiments[0].xpiHash = EXPERIMENT1A_XPI_SHA1;
gManifestObject.experiments[0].xpiURL = gDataRoot + EXPERIMENT1A_XPI_NAME;
yield experiments.updateManifest();
Assert.equal(observerFireCount, ++expectedObserverFireCount,
"Experiments observer should have been called.");
list = yield experiments.getExperiments();
Assert.equal(list.length, 1, "Experiment list should have 1 entry now.");
Assert.equal(list[0].id, EXPERIMENT1_ID, "Experiment 1 should be the sole entry.");
Assert.equal(list[0].active, true, "Experiment 1 should still be active.");
Assert.equal(list[0].name, EXPERIMENT1A_NAME, "Experiments name should have been updated.");
// Cleanup.
Services.obs.removeObserver(observer, OBSERVER_TOPIC);
yield experiments.uninit();
yield removeCacheFile();
});
add_task(function* shutdown() {
yield gReporter._shutdown();
yield removeCacheFile();
});

Просмотреть файл

@ -0,0 +1,174 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource:///modules/experiments/Experiments.jsm");
const FILE_MANIFEST = "experiments.manifest";
const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
const PREF_LOGGING_LEVEL = "experiments.logging.level";
const PREF_LOGGING_DUMP = "experiments.logging.dump";
const PREF_MANIFEST_URI = "experiments.manifest.uri";
const SEC_IN_ONE_DAY = 24 * 60 * 60;
const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
let gProfileDir = null;
let gHttpServer = null;
let gHttpRoot = null;
let gReporter = null;
let gPolicy = null;
function ManifestEntry(data) {
this.id = EXPERIMENT1_ID;
this.xpiURL = "http://localhost:1/dummy.xpi";
this.xpiHash = EXPERIMENT1_XPI_SHA1;
this.startTime = new Date(2010, 0, 1, 12).getTime() / 1000;
this.endTime = new Date(9001, 0, 1, 12).getTime() / 1000;
this.maxActiveSeconds = SEC_IN_ONE_DAY;
this.appName = ["XPCShell"];
this.channel = ["nightly"];
data = data || {};
for (let k of Object.keys(data)) {
this[k] = data[k];
}
if (!this.endTime) {
this.endTime = this.startTime + 5 * SEC_IN_ONE_DAY;
}
}
function applicableFromManifestData(data, policy) {
let manifestData = new ManifestEntry(data);
let entry = new Experiments.ExperimentEntry(policy);
entry.initFromManifestData(manifestData);
return entry.isApplicable();
}
function run_test() {
run_next_test();
}
add_task(function* test_setup() {
createAppInfo();
gProfileDir = do_get_profile();
gPolicy = new Experiments.Policy();
gReporter = yield getReporter("json_payload_simple");
yield gReporter.collectMeasurements();
let payload = yield gReporter.getJSONPayload(true);
patchPolicy(gPolicy, {
updatechannel: () => "nightly",
healthReportPayload: () => Promise.resolve(payload),
});
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
let experiments = new Experiments.Experiments();
});
// This function exists solely to be .toSource()d
const sanityFilter = function filter(c) {
if (c.telemetryPayload === undefined) {
throw Error("No .telemetryPayload");
}
if (c.telemetryPayload.simpleMeasurements === undefined) {
throw Error("No .simpleMeasurements");
}
if (c.healthReportPayload === undefined) {
throw Error("No .healthReportPayload");
}
if (c.healthReportPayload.geckoAppInfo == undefined) {
throw Error("No .geckoAppInfo");
}
return true;
}
add_task(function* test_simpleFields() {
let testData = [
// "expected applicable?", failure reason or null, manifest data
[false, "os", {os: ["42", "abcdef"]}],
[true, null, {os: [gAppInfo.OS, "plan9"]}],
[false, "buildIDs", {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID + "-invalid"]}],
[true, null, {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID]}],
[true, null, {jsfilter: "function filter(c) { return true; }"}],
[false, null, {jsfilter: "function filter(c) { return false; }"}],
[true, null, {jsfilter: "function filter(c) { return 123; }"}], // truthy
[false, null, {jsfilter: "function filter(c) { return ''; }"}], // falsy
[false, null, {jsfilter: "function filter(c) { var a = []; }"}], // undefined
[false, "jsfilter:rejected some error", {jsfilter: "function filter(c) { throw new Error('some error'); }"}],
[false, "jsfilter:evalFailure", {jsfilter: "123, this won't work"}],
[true, {jsfilter: "var filter = " + sanityFilter.toSource()}],
];
for (let i=0; i<testData.length; ++i) {
let entry = testData[i];
let applicable;
let reason = null;
yield applicableFromManifestData(entry[2], gPolicy).then(
value => applicable = value,
value => {
applicable = false;
reason = value;
}
);
Assert.equal(applicable, entry[0],
"Experiment entry applicability should match for test "
+ i + ": " + JSON.stringify(entry[2]));
if (!applicable) {
Assert.equal(reason, entry[1], "Experiment rejection reason should match for test " + i);
}
}
});
add_task(function* test_times() {
let baseDate = new Date(2014, 5, 6, 12);
let baseTimeSec = baseDate.getTime() / 1000;
let testData = [
// "expected applicable?", rejection reason or null, fake now date, manifest data
[false, "maxStartTime", baseDate,
{maxStartTime: baseTimeSec - 10 * SEC_IN_ONE_DAY}],
[false, "endTime", baseDate,
{startTime: baseTimeSec - 10 * SEC_IN_ONE_DAY,
endTime: baseTimeSec - 5 * SEC_IN_ONE_DAY}],
[true, null, baseDate,
{startTime: baseTimeSec - 5 * SEC_IN_ONE_DAY,
endTime: baseTimeSec + 10 * SEC_IN_ONE_DAY}],
];
for (let i=0; i<testData.length; ++i) {
let entry = testData[i];
let applicable;
let reason = null;
defineNow(gPolicy, entry[2]);
yield applicableFromManifestData(entry[3], gPolicy).then(
value => applicable = value,
value => {
applicable = false;
reason = value;
}
);
Assert.equal(applicable, entry[0],
"Experiment entry applicability should match for test "
+ i + ": " + JSON.stringify([entry[2], entry[3]]));
if (!applicable && entry[1]) {
Assert.equal(reason, entry[1], "Experiment rejection reason should match for test " + i);
}
}
});
add_task(function* shutdown() {
yield gReporter._shutdown();
yield removeCacheFile();
});

Просмотреть файл

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource:///modules/experiments/Experiments.jsm");
const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
const PREF_LOGGING_LEVEL = "experiments.logging.level";
const PREF_LOGGING_DUMP = "experiments.logging.dump";
const PREF_MANIFEST_URI = "experiments.manifest.uri";
let gProfileDir = null;
let gHttpServer = null;
let gHttpRoot = null;
let gPolicy = new Experiments.Policy();
function run_test() {
createAppInfo();
gProfileDir = do_get_profile();
gHttpServer = new HttpServer();
gHttpServer.start(-1);
let port = gHttpServer.identity.primaryPort;
gHttpRoot = "http://localhost:" + port + "/";
gHttpServer.registerDirectory("/", do_get_cwd());
do_register_cleanup(() => gHttpServer.stop(() => {}));
disableCertificateChecks();
Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
Services.prefs.setIntPref(PREF_LOGGING_LEVEL, 0);
Services.prefs.setBoolPref(PREF_LOGGING_DUMP, true);
patchPolicy(gPolicy, {
updatechannel: () => "nightly",
});
run_next_test();
}
add_task(function* test_fetchAndCache() {
Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "experiments_1.manifest");
let ex = new Experiments.Experiments(gPolicy);
Assert.equal(ex._experiments.size, 0, "There should be no cached experiments yet.");
yield ex.updateManifest();
Assert.notEqual(ex._experiments.size, 0, "There should be cached experiments now.");
yield ex.uninit();
});
add_task(function* test_checkCache() {
let ex = new Experiments.Experiments(gPolicy);
Assert.equal(ex._experiments.size, 0, "There should be no cached experiments yet.");
yield ex._loadFromCache();
Assert.notEqual(ex._experiments.size, 0, "There should be cached experiments now.");
yield ex.uninit();
});
add_task(function* test_fetchInvalid() {
Services.prefs.setCharPref(PREF_MANIFEST_URI, gHttpRoot + "invalid.manifest");
yield removeCacheFile();
let ex = new Experiments.Experiments(gPolicy);
Assert.equal(ex._experiments.size, 0, "There should be no cached experiments yet.");
let error;
yield ex.updateManifest().then(() => error = false, () => error = true);
Assert.ok(error, "Updating the manifest should not have succeeded.");
Assert.equal(ex._experiments.size, 0, "There should still be no cached experiments.");
yield ex.uninit();
});
add_task(function* shutdown() {
yield removeCacheFile();
});

Просмотреть файл

@ -0,0 +1,14 @@
[DEFAULT]
head = head.js
tail =
firefox-appdir = browser
support-files =
experiments_1.manifest
../experiment-1.xpi
../experiment-1a.xpi
../experiment-2.xpi
[test_activate.js]
[test_api.js]
[test_conditions.js]
[test_fetch.js]

Просмотреть файл

@ -9,6 +9,7 @@ CONFIGURE_SUBST_FILES += ['installer/Makefile']
PARALLEL_DIRS += [
'base',
'components',
'experiments',
'fuel',
'locales',
'modules',

Просмотреть файл

@ -28,9 +28,11 @@ AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [
esac
fi
# if we are debugging or profiling, we want a frame pointer.
# if we are debugging, profiling or using ASAN, we want a frame pointer.
if test -z "$MOZ_OPTIMIZE" -o \
-n "$MOZ_PROFILING" -o -n "$MOZ_DEBUG"; then
-n "$MOZ_PROFILING" -o \
-n "$MOZ_DEBUG" -o \
-n "$MOZ_ASAN"; then
MOZ_FRAMEPTR_FLAGS="$MOZ_ENABLE_FRAME_PTR"
else
MOZ_FRAMEPTR_FLAGS="$MOZ_DISABLE_FRAME_PTR"

Просмотреть файл

@ -8933,9 +8933,9 @@ if test "$MOZ_TREE_FREETYPE"; then
export CXXFLAGS="$CXXFLAGS $MOZ_DEBUG_FLAGS"
export LDFLAGS="$LDFLAGS $MOZ_DEBUG_LDFLAGS"
export LIBPNG_CFLAGS="$MOZ_PNG_CFLAGS"
export LIBPNG_LDFLAGS="$MOZ_PNG_LIBS"
export LIBPNG_LIBS="$MOZ_PNG_LIBS"
export CONFIG_FILES="unix-cc.mk:unix-cc.in unix-def.mk:unix-def.in freetype-config freetype2.pc:freetype2.in"
ac_configure_args="$ac_configure_args --host=$target --disable-shared --with-pic=yes"
ac_configure_args="$ac_configure_args --host=$target --disable-shared --with-pic=yes --with-png=yes"
if ! test -e modules; then
mkdir modules

Просмотреть файл

@ -5473,6 +5473,14 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
return true;
}
bool
nsDocument::IsRegisterElementEnabled(JSContext* aCx, JSObject* aObject)
{
JS::Rooted<JSObject*> obj(aCx, aObject);
return Preferences::GetBool("dom.webcomponents.enabled") ||
IsInCertifiedApp(aCx, obj);
}
nsresult
nsDocument::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
{

Просмотреть файл

@ -1421,6 +1421,8 @@ public:
uint32_t aNamespaceID,
mozilla::ErrorResult& rv);
static bool IsRegisterElementEnabled(JSContext* aCx, JSObject* aObject);
// The "registry" from the web components spec.
nsRefPtr<Registry> mRegistry;

Просмотреть файл

@ -3577,7 +3577,7 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
thebes = new gfxContext(mTarget);
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
matrix._22, matrix._31, matrix._32));
} else if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
} else {
drawDT =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(ceil(sw), ceil(sh)),
SurfaceFormat::B8G8R8A8);
@ -3588,17 +3588,6 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
thebes = new gfxContext(drawDT);
thebes->Scale(matrix._11, matrix._22);
} else {
drawSurf =
gfxPlatform::GetPlatform()->CreateOffscreenSurface(IntSize(ceil(sw), ceil(sh)),
gfxContentType::COLOR_ALPHA);
if (!drawSurf) {
error.Throw(NS_ERROR_FAILURE);
return;
}
thebes = new gfxContext(drawSurf);
thebes->Scale(matrix._11, matrix._22);
}
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();

Просмотреть файл

@ -6,6 +6,7 @@
#include "DOMSVGPoint.h"
#include "DOMSVGPointList.h"
#include "SVGPoint.h"
#include "gfx2DGlue.h"
#include "nsSVGElement.h"
#include "nsError.h"
#include "mozilla/dom/SVGMatrix.h"
@ -13,6 +14,7 @@
// See the architecture comment in DOMSVGPointList.h.
using namespace mozilla;
using namespace mozilla::gfx;
namespace mozilla {
@ -112,7 +114,7 @@ DOMSVGPoint::MatrixTransform(dom::SVGMatrix& matrix)
float x = HasOwner() ? InternalItem().mX : mPt.mX;
float y = HasOwner() ? InternalItem().mY : mPt.mY;
gfxPoint pt = matrix.GetMatrix().Transform(gfxPoint(x, y));
Point pt = ToMatrix(matrix.GetMatrix()) * Point(x, y);
nsCOMPtr<nsISVGPoint> newPoint = new DOMSVGPoint(pt);
return newPoint.forget();
}

Просмотреть файл

@ -7,7 +7,6 @@
#define MOZILLA_DOMSVGPOINT_H__
#include "DOMSVGPointList.h"
#include "gfxPoint.h"
#include "mozilla/gfx/2D.h"
#include "nsAutoPtr.h"
#include "nsDebug.h"
@ -87,15 +86,6 @@ public:
"DOMSVGPoint coords are not finite");
}
explicit DOMSVGPoint(const gfxPoint &aPt)
: nsISVGPoint()
{
mPt.mX = float(aPt.x);
mPt.mY = float(aPt.y);
NS_ASSERTION(NS_finite(mPt.mX) && NS_finite(mPt.mX),
"DOMSVGPoint coords are not finite");
}
// WebIDL
virtual float X();

Просмотреть файл

@ -8,6 +8,7 @@
#include "SVGMotionSMILType.h"
#include "gfx2DGlue.h"
#include "mozilla/gfx/Point.h"
#include "nsSMILValue.h"
#include "nsDebug.h"
#include "nsMathUtils.h"
@ -233,16 +234,16 @@ SVGMotionSMILType::IsEqual(const nsSMILValue& aLeft,
inline static void
GetAngleAndPointAtDistance(Path* aPath, float aDistance,
RotateType aRotateType,
gfxFloat& aRotateAngle, // in & out-param.
gfxPoint& aPoint) // out-param.
float& aRotateAngle, // in & out-param.
Point& aPoint) // out-param.
{
if (aRotateType == eRotateType_Explicit) {
// Leave aRotateAngle as-is.
aPoint = ThebesPoint(aPath->ComputePointAtLength(aDistance));
aPoint = aPath->ComputePointAtLength(aDistance);
} else {
Point tangent; // Unit vector tangent to the point we find.
aPoint = ThebesPoint(aPath->ComputePointAtLength(aDistance, &tangent));
gfxFloat tangentAngle = atan2(tangent.y, tangent.x);
aPoint = aPath->ComputePointAtLength(aDistance, &tangent);
float tangentAngle = atan2(tangent.y, tangent.x);
if (aRotateType == eRotateType_Auto) {
aRotateAngle = tangentAngle;
} else {
@ -291,8 +292,8 @@ SVGMotionSMILType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
Path* path = srcParams.mPath;
// Use destination to get our rotate angle.
gfxFloat rotateAngle = dstSeg.mRotateAngle;
gfxPoint dstPt;
float rotateAngle = dstSeg.mRotateAngle;
Point dstPt;
GetAngleAndPointAtDistance(path, dstParams.mDistToPoint, dstSeg.mRotateType,
rotateAngle, dstPt);
@ -450,8 +451,8 @@ SVGMotionSMILType::CreateMatrix(const nsSMILValue& aSMILVal)
gfx::Matrix matrix;
uint32_t length = arr.Length();
for (uint32_t i = 0; i < length; i++) {
gfxPoint point; // initialized below
gfxFloat rotateAngle = arr[i].mRotateAngle; // might get updated below
Point point; // initialized below
float rotateAngle = arr[i].mRotateAngle; // might get updated below
if (arr[i].mSegmentType == eSegmentType_Translation) {
point.x = arr[i].mU.mTranslationParams.mX;
point.y = arr[i].mU.mTranslationParams.mY;

Просмотреть файл

@ -821,7 +821,7 @@ SVGPathData::ToPathForLengthOrPositionMeasuring() const
}
static double
AngleOfVector(const gfxPoint& aVector)
AngleOfVector(const Point& aVector)
{
// C99 says about atan2 "A domain error may occur if both arguments are
// zero" and "On a domain error, the function returns an implementation-
@ -829,11 +829,11 @@ AngleOfVector(const gfxPoint& aVector)
// seems to commonly be zero, but it could just as easily be a NaN value.
// We specifically want zero in this case, hence the check:
return (aVector != gfxPoint(0.0, 0.0)) ? atan2(aVector.y, aVector.x) : 0.0;
return (aVector != Point(0.0, 0.0)) ? atan2(aVector.y, aVector.x) : 0.0;
}
static float
AngleOfVectorF(const gfxPoint& aVector)
AngleOfVectorF(const Point& aVector)
{
return static_cast<float>(AngleOfVector(aVector));
}
@ -846,14 +846,14 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
// places, and repeat multiple times consecutively.
// info on current [sub]path (reset every M command):
gfxPoint pathStart(0.0, 0.0);
Point pathStart(0.0, 0.0);
float pathStartAngle = 0.0f;
// info on previous segment:
uint16_t prevSegType = PATHSEG_UNKNOWN;
gfxPoint prevSegEnd(0.0, 0.0);
Point prevSegEnd(0.0, 0.0);
float prevSegEndAngle = 0.0f;
gfxPoint prevCP; // if prev seg was a bezier, this was its last control point
Point prevCP; // if prev seg was a bezier, this was its last control point
uint32_t i = 0;
while (i < mData.Length()) {
@ -861,8 +861,8 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
// info on current segment:
uint16_t segType =
SVGPathSegUtils::DecodeType(mData[i++]); // advances i to args
gfxPoint &segStart = prevSegEnd;
gfxPoint segEnd;
Point& segStart = prevSegEnd;
Point segEnd;
float segStartAngle, segEndAngle;
switch (segType) // to find segStartAngle, segEnd and segEndAngle
@ -875,9 +875,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_MOVETO_ABS:
case PATHSEG_MOVETO_REL:
if (segType == PATHSEG_MOVETO_ABS) {
segEnd = gfxPoint(mData[i], mData[i+1]);
segEnd = Point(mData[i], mData[i+1]);
} else {
segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
segEnd = segStart + Point(mData[i], mData[i+1]);
}
pathStart = segEnd;
// If authors are going to specify multiple consecutive moveto commands
@ -889,9 +889,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_LINETO_ABS:
case PATHSEG_LINETO_REL:
if (segType == PATHSEG_LINETO_ABS) {
segEnd = gfxPoint(mData[i], mData[i+1]);
segEnd = Point(mData[i], mData[i+1]);
} else {
segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
segEnd = segStart + Point(mData[i], mData[i+1]);
}
segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
i += 2;
@ -900,15 +900,15 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_CUBIC_ABS:
case PATHSEG_CURVETO_CUBIC_REL:
{
gfxPoint cp1, cp2; // control points
Point cp1, cp2; // control points
if (segType == PATHSEG_CURVETO_CUBIC_ABS) {
cp1 = gfxPoint(mData[i], mData[i+1]);
cp2 = gfxPoint(mData[i+2], mData[i+3]);
segEnd = gfxPoint(mData[i+4], mData[i+5]);
cp1 = Point(mData[i], mData[i+1]);
cp2 = Point(mData[i+2], mData[i+3]);
segEnd = Point(mData[i+4], mData[i+5]);
} else {
cp1 = segStart + gfxPoint(mData[i], mData[i+1]);
cp2 = segStart + gfxPoint(mData[i+2], mData[i+3]);
segEnd = segStart + gfxPoint(mData[i+4], mData[i+5]);
cp1 = segStart + Point(mData[i], mData[i+1]);
cp2 = segStart + Point(mData[i+2], mData[i+3]);
segEnd = segStart + Point(mData[i+4], mData[i+5]);
}
prevCP = cp2;
if (cp1 == segStart) {
@ -926,13 +926,13 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_QUADRATIC_ABS:
case PATHSEG_CURVETO_QUADRATIC_REL:
{
gfxPoint cp1, cp2; // control points
Point cp1, cp2; // control points
if (segType == PATHSEG_CURVETO_QUADRATIC_ABS) {
cp1 = gfxPoint(mData[i], mData[i+1]);
segEnd = gfxPoint(mData[i+2], mData[i+3]);
cp1 = Point(mData[i], mData[i+1]);
segEnd = Point(mData[i+2], mData[i+3]);
} else {
cp1 = segStart + gfxPoint(mData[i], mData[i+1]);
segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]);
cp1 = segStart + Point(mData[i], mData[i+1]);
segEnd = segStart + Point(mData[i+2], mData[i+3]);
}
prevCP = cp1;
segStartAngle = AngleOfVectorF(cp1 - segStart);
@ -950,9 +950,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
bool largeArcFlag = mData[i+3] != 0.0f;
bool sweepFlag = mData[i+4] != 0.0f;
if (segType == PATHSEG_ARC_ABS) {
segEnd = gfxPoint(mData[i+5], mData[i+6]);
segEnd = Point(mData[i+5], mData[i+6]);
} else {
segEnd = segStart + gfxPoint(mData[i+5], mData[i+6]);
segEnd = segStart + Point(mData[i+5], mData[i+6]);
}
// See section F.6 of SVG 1.1 for details on what we're doing here:
@ -1017,8 +1017,8 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
double cyp = -root * ry * x1p / rx;
double theta, delta;
theta = AngleOfVector(gfxPoint((x1p-cxp)/rx, (y1p-cyp)/ry)); // F.6.5.5
delta = AngleOfVector(gfxPoint((-x1p-cxp)/rx, (-y1p-cyp)/ry)) - // F.6.5.6
theta = AngleOfVector(Point((x1p-cxp)/rx, (y1p-cyp)/ry)); // F.6.5.5
delta = AngleOfVector(Point((-x1p-cxp)/rx, (-y1p-cyp)/ry)) - // F.6.5.6
theta;
if (!sweepFlag && delta > 0)
delta -= 2.0 * M_PI;
@ -1047,9 +1047,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_LINETO_HORIZONTAL_ABS:
case PATHSEG_LINETO_HORIZONTAL_REL:
if (segType == PATHSEG_LINETO_HORIZONTAL_ABS) {
segEnd = gfxPoint(mData[i++], segStart.y);
segEnd = Point(mData[i++], segStart.y);
} else {
segEnd = segStart + gfxPoint(mData[i++], 0.0f);
segEnd = segStart + Point(mData[i++], 0.0f);
}
segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
break;
@ -1057,9 +1057,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_LINETO_VERTICAL_ABS:
case PATHSEG_LINETO_VERTICAL_REL:
if (segType == PATHSEG_LINETO_VERTICAL_ABS) {
segEnd = gfxPoint(segStart.x, mData[i++]);
segEnd = Point(segStart.x, mData[i++]);
} else {
segEnd = segStart + gfxPoint(0.0f, mData[i++]);
segEnd = segStart + Point(0.0f, mData[i++]);
}
segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
break;
@ -1067,15 +1067,15 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
{
gfxPoint cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ?
Point cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ?
segStart * 2 - prevCP : segStart;
gfxPoint cp2;
Point cp2;
if (segType == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS) {
cp2 = gfxPoint(mData[i], mData[i+1]);
segEnd = gfxPoint(mData[i+2], mData[i+3]);
cp2 = Point(mData[i], mData[i+1]);
segEnd = Point(mData[i+2], mData[i+3]);
} else {
cp2 = segStart + gfxPoint(mData[i], mData[i+1]);
segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]);
cp2 = segStart + Point(mData[i], mData[i+1]);
segEnd = segStart + Point(mData[i+2], mData[i+3]);
}
prevCP = cp2;
if (cp1 == segStart) {
@ -1093,13 +1093,13 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
{
gfxPoint cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ?
Point cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ?
segStart * 2 - prevCP : segStart;
gfxPoint cp2;
Point cp2;
if (segType == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS) {
segEnd = gfxPoint(mData[i], mData[i+1]);
segEnd = Point(mData[i], mData[i+1]);
} else {
segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
segEnd = segStart + Point(mData[i], mData[i+1]);
}
prevCP = cp1;
segStartAngle = AngleOfVectorF(cp1 - segStart);

Просмотреть файл

@ -334,7 +334,7 @@ SVGPathElement::ConstructPath(gfxContext *aCtx)
mD.GetAnimValue().ConstructPath(aCtx);
}
gfxFloat
float
SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
{
NS_ABORT_IF_FALSE(aFor == eForTextPath || aFor == eForStroking,

Просмотреть файл

@ -82,7 +82,7 @@ public:
* length (as provided by the <path> element's 'pathLength' attribute). This
* is used to scale stroke dashing, and to scale offsets along a textPath.
*/
gfxFloat GetPathLengthScale(PathLengthScaleForType aFor);
float GetPathLengthScale(PathLengthScaleForType aFor);
// WebIDL
already_AddRefed<SVGAnimatedNumber> PathLength();

Просмотреть файл

@ -131,14 +131,14 @@ SplitCubicBezier(const Point* aCurve, Point* aLeft, Point* aRight)
aLeft[3].y = aRight[0].y = (aLeft[2].y + aRight[1].y) / 2;
}
static gfxFloat
static float
CalcBezLengthHelper(const Point* aCurve, uint32_t aNumPts,
uint32_t aRecursionCount,
void (*aSplit)(const Point*, Point*, Point*))
{
Point left[4];
Point right[4];
gfxFloat length = 0, dist;
float length = 0, dist;
for (uint32_t i = 0; i < aNumPts - 1; i++) {
length += CalcDistanceBetweenPoints(aCurve[i], aCurve[i+1]);
}
@ -153,7 +153,7 @@ CalcBezLengthHelper(const Point* aCurve, uint32_t aNumPts,
return length;
}
static inline gfxFloat
static inline float
CalcLengthOfCubicBezier(const Point& aPos, const Point &aCP1,
const Point& aCP2, const Point &aTo)
{
@ -161,7 +161,7 @@ CalcLengthOfCubicBezier(const Point& aPos, const Point &aCP1,
return CalcBezLengthHelper(curve, 4, 0, SplitCubicBezier);
}
static inline gfxFloat
static inline float
CalcLengthOfQuadraticBezier(const Point& aPos, const Point& aCP,
const Point& aTo)
{

Просмотреть файл

@ -73,3 +73,10 @@ if CONFIG['SOLARIS_SUNPRO_CC']:
if CONFIG['OS_ARCH'] == 'WINNT':
RCFILE = 'sqlite.rc'
RESFILE = 'sqlite.res'
# Suppress warnings in third-party code.
if CONFIG['GNU_CC']:
CFLAGS += [
'-Wno-sign-compare',
'-Wno-type-limits',
]

Просмотреть файл

@ -334,6 +334,8 @@ parent:
__delete__();
ReplyKeyEvent(WidgetKeyboardEvent event);
child:
/**
* Notify the remote browser that it has been Show()n on this

Просмотреть файл

@ -1932,6 +1932,10 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event)
mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
}
if (localEvent.mFlags.mWantReplyFromContentProcess) {
SendReplyKeyEvent(localEvent);
}
return true;
}

Просмотреть файл

@ -1192,6 +1192,28 @@ TabParent::GetChildProcessOffset()
pt, targetFrame->PresContext()->AppUnitsPerDevPixel()));
}
bool
TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event)
{
NS_ENSURE_TRUE(mFrameElement, true);
WidgetKeyboardEvent localEvent(event);
// Set mNoCrossProcessBoundaryForwarding to avoid this event from
// being infinitely redispatched and forwarded to the child again.
localEvent.mFlags.mNoCrossProcessBoundaryForwarding = true;
// Here we convert the WidgetEvent that we received to an nsIDOMEvent
// to be able to dispatch it to the <browser> element as the target element.
nsIDocument* doc = mFrameElement->OwnerDoc();
nsIPresShell* presShell = doc->GetShell();
NS_ENSURE_TRUE(presShell, true);
nsPresContext* presContext = presShell->GetPresContext();
NS_ENSURE_TRUE(presContext, true);
EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent);
return true;
}
/**
* Try to answer query event using cached text.
*

Просмотреть файл

@ -114,6 +114,7 @@ public:
virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE;
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) MOZ_OVERRIDE;
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& event);
virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* actor) MOZ_OVERRIDE;
virtual bool RecvInitRenderFrame(PRenderFrameParent* aFrame,
ScrollingBehavior* scrolling,

Просмотреть файл

@ -27,6 +27,7 @@
#include "nsPluginNativeWindow.h"
#include "GeckoProfiler.h"
#include "nsPluginInstanceOwner.h"
#include "nsDataHashtable.h"
#define MAGIC_REQUEST_CONTEXT 0x01020304
@ -39,12 +40,12 @@ class nsPluginByteRangeStreamListener
public:
nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr);
virtual ~nsPluginByteRangeStreamListener();
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
private:
nsCOMPtr<nsIStreamListener> mStreamConverter;
nsWeakPtr mWeakPtrPluginStreamListenerPeer;
@ -88,17 +89,17 @@ NS_IMETHODIMP
nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
nsresult rv;
nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
if (!finalStreamListener)
return NS_ERROR_FAILURE;
nsPluginStreamListenerPeer *pslp =
static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
NS_ASSERTION(pslp->mRequests.IndexOfObject(GetBaseRequest(request)) != -1,
"Untracked byte-range request?");
nsCOMPtr<nsIStreamConverterService> serv = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = serv->AsyncConvertData(MULTIPART_BYTERANGES,
@ -113,18 +114,18 @@ nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports
}
}
mStreamConverter = 0;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
if (!httpChannel) {
return NS_ERROR_FAILURE;
}
uint32_t responseCode = 0;
rv = httpChannel->GetResponseStatus(&responseCode);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
if (responseCode != 200) {
uint32_t wantsAllNetworkStreams = 0;
rv = pslp->GetPluginInstance()->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
@ -138,12 +139,12 @@ nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports
return NS_ERROR_FAILURE;
}
}
// if server cannot continue with byte range (206 status) and sending us whole object (200 status)
// reset this seekable stream & try serve it to plugin instance as a file
mStreamConverter = finalStreamListener;
mRemoveMagicNumber = true;
rv = pslp->ServeStreamAsFile(request, ctxt);
return rv;
}
@ -154,11 +155,11 @@ nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports
{
if (!mStreamConverter)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
if (!finalStreamListener)
return NS_ERROR_FAILURE;
nsPluginStreamListenerPeer *pslp =
static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
bool found = pslp->mRequests.RemoveObject(request);
@ -181,7 +182,7 @@ nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports
NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
}
}
return mStreamConverter->OnStopRequest(request, ctxt, status);
}
@ -223,11 +224,11 @@ nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupport
{
if (!mStreamConverter)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
if (!finalStreamListener)
return NS_ERROR_FAILURE;
return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
}
@ -241,28 +242,6 @@ nsPluginByteRangeStreamListener::GetInterface(const nsIID& aIID, void** result)
return finalStreamListener->GetInterface(aIID, result);
}
// nsPRUintKey
class nsPRUintKey : public nsHashKey {
protected:
uint32_t mKey;
public:
nsPRUintKey(uint32_t key) : mKey(key) {}
uint32_t HashCode() const {
return mKey;
}
bool Equals(const nsHashKey *aKey) const {
return mKey == ((const nsPRUintKey*)aKey)->mKey;
}
nsHashKey *Clone() const {
return new nsPRUintKey(mKey);
}
uint32_t GetValue() { return mKey; }
};
// nsPluginStreamListenerPeer
@ -280,11 +259,11 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
mStartBinding = false;
mAbort = false;
mRequestFailed = false;
mPendingRequests = 0;
mHaveFiredOnStartRequest = false;
mDataForwardToRequest = nullptr;
mSeekable = false;
mModified = 0;
mStreamOffset = 0;
@ -306,7 +285,7 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
// or we won't be able to remove the cache file
if (mFileCacheOutputStream)
mFileCacheOutputStream = nullptr;
delete mDataForwardToRequest;
if (mPluginInstance)
@ -350,7 +329,7 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
mPendingRequests = 1;
mDataForwardToRequest = new nsHashtable();
mDataForwardToRequest = new nsDataHashtable<nsUint32HashKey, uint32_t>();
return NS_OK;
}
@ -394,38 +373,38 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
if (NS_FAILED(rv)) {
return rv;
}
// Get the filename from the channel
nsCOMPtr<nsIURI> uri;
rv = channel->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
if (!url)
return NS_ERROR_FAILURE;
nsAutoCString filename;
url->GetFileName(filename);
if (NS_FAILED(rv))
return rv;
// Create a file to save our stream into. Should we scramble the name?
filename.Insert(NS_LITERAL_CSTRING("plugin-"), 0);
rv = pluginTmp->AppendNative(filename);
if (NS_FAILED(rv))
return rv;
// Yes, make it unique.
rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv))
return rv;
// create a file output stream to write to...
nsCOMPtr<nsIOutputStream> outstream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
if (NS_FAILED(rv))
return rv;
// save the file.
mLocalCachedFileHolder = new CachedFileHolder(pluginTmp);
}
@ -618,28 +597,28 @@ nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACStr
//the string should look like this: bytes=500-700,601-999
if (!aRangeList)
return;
int32_t requestCnt = 0;
nsAutoCString string("bytes=");
for (NPByteRange * range = aRangeList; range != nullptr; range = range->next) {
// XXX zero length?
if (!range->length)
continue;
// XXX needs to be fixed for negative offsets
string.AppendInt(range->offset);
string.Append("-");
string.AppendInt(range->offset + range->length - 1);
if (range->next)
string += ",";
requestCnt++;
}
// get rid of possible trailing comma
string.Trim(",", false);
rangeRequest = string;
*numRequests = requestCnt;
return;
@ -650,32 +629,32 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
{
nsAutoCString rangeString;
int32_t numRequests;
MakeByteRangeString(rangeList, rangeString, &numRequests);
if (numRequests == 0)
return NS_ERROR_FAILURE;
nsresult rv = NS_OK;
nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel), mURL, nullptr, loadGroup, callbacks);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (!httpChannel)
return NS_ERROR_FAILURE;
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
mAbort = true; // instruct old stream listener to cancel
// the request on the next ODA.
nsCOMPtr<nsIStreamListener> converter;
if (numRequests == 1) {
converter = this;
// set current stream offset equal to the first offset in the range list
@ -692,16 +671,16 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
else
return NS_ERROR_OUT_OF_MEMORY;
}
mPendingRequests += numRequests;
nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
rv = container->SetData(MAGIC_REQUEST_CONTEXT);
if (NS_FAILED(rv))
return rv;
rv = channel->AsyncOpen(converter, container);
if (NS_SUCCEEDED(rv))
TrackRequest(channel);
@ -727,7 +706,7 @@ nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
{
if (!mPluginInstance)
return NS_ERROR_FAILURE;
// mPluginInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
mPluginInstance->Stop();
mPluginInstance->Start();
@ -737,7 +716,7 @@ nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
owner->GetWindow(window);
#if (MOZ_WIDGET_GTK == 2) || defined(MOZ_WIDGET_QT)
// Should call GetPluginPort() here.
// This part is copied from nsPluginInstanceOwner::GetPluginPort().
// This part is copied from nsPluginInstanceOwner::GetPluginPort().
nsCOMPtr<nsIWidget> widget;
((nsPluginNativeWindow*)window)->GetPluginWidget(getter_AddRefs(widget));
if (widget) {
@ -746,22 +725,22 @@ nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
#endif
owner->CallSetWindow();
}
mSeekable = false;
mPStreamListener->OnStartBinding(this);
mStreamOffset = 0;
// force the plugin to use stream as file
mStreamType = NP_ASFILE;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (channel) {
SetupPluginCacheFile(channel);
}
// unset mPendingRequests
mPendingRequests = 0;
return NS_OK;
}
@ -769,7 +748,7 @@ bool
nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi)
{
NS_ENSURE_TRUE(psi, false);
if (psi->mLength == mLength &&
psi->mModified == mModified &&
mStreamComplete &&
@ -793,32 +772,32 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
if (mRequestFailed)
return NS_ERROR_FAILURE;
if (mAbort) {
uint32_t magicNumber = 0; // set it to something that is not the magic number.
nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
if (container)
container->GetData(&magicNumber);
if (magicNumber != MAGIC_REQUEST_CONTEXT) {
// this is not one of our range requests
mAbort = false;
return NS_BINDING_ABORTED;
}
}
nsresult rv = NS_OK;
if (!mPStreamListener)
return NS_ERROR_FAILURE;
const char * url = nullptr;
GetURL(&url);
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%llu, length=%u, url=%s\n",
this, request, sourceOffset, aLength, url ? url : "no url set"));
// if the plugin has requested an AsFileOnly stream, then don't
// call OnDataAvailable
if (mStreamType != NP_ASFILEONLY) {
@ -827,44 +806,42 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
if (brr) {
if (!mDataForwardToRequest)
return NS_ERROR_FAILURE;
int64_t absoluteOffset64 = 0;
brr->GetStartRange(&absoluteOffset64);
// XXX handle 64-bit for real
int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
// we need to track how much data we have forwarded to the
// plugin.
// FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
//
// Why couldn't this be tracked on the plugin info, and not in a
// *hash table*?
nsPRUintKey key(absoluteOffset);
int32_t amtForwardToPlugin =
NS_PTR_TO_INT32(mDataForwardToRequest->Get(&key));
mDataForwardToRequest->Put(&key, NS_INT32_TO_PTR(amtForwardToPlugin + aLength));
int32_t amtForwardToPlugin = mDataForwardToRequest->Get(absoluteOffset);
mDataForwardToRequest->Put(absoluteOffset, (amtForwardToPlugin + aLength));
SetStreamOffset(absoluteOffset + amtForwardToPlugin);
}
nsCOMPtr<nsIInputStream> stream = aIStream;
// if we are caching the file ourselves to disk, we want to 'tee' off
// the data as the plugin read from the stream. We do this by the magic
// of an input stream tee.
if (mFileCacheOutputStream) {
rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
if (NS_FAILED(rv))
return rv;
}
rv = mPStreamListener->OnDataAvailable(this,
stream,
aLength);
// if a plugin returns an error, the peer must kill the stream
// else the stream and PluginStreamListener leak
if (NS_FAILED(rv))
@ -876,7 +853,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
char* buffer = new char[aLength];
uint32_t amountRead, amountWrote = 0;
rv = aIStream->Read(buffer, aLength, &amountRead);
// if we are caching this to disk ourselves, lets write the bytes out.
if (mFileCacheOutputStream) {
while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
@ -901,11 +878,11 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
NS_ERROR("Received OnStopRequest for untracked request.");
}
}
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%d request=%p\n",
this, aStatus, request));
// for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
if (brr) {
@ -913,13 +890,11 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
brr->GetStartRange(&absoluteOffset64);
// XXX support 64-bit offsets
int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
nsPRUintKey key(absoluteOffset);
// remove the request from our data forwarding count hash.
mDataForwardToRequest->Remove(&key);
mDataForwardToRequest->Remove(absoluteOffset);
PLUGIN_LOG(PLUGIN_LOG_NOISY,
(" ::OnStopRequest for ByteRangeRequest Started=%d\n",
absoluteOffset));
@ -929,11 +904,11 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
// close & tear it down here
mFileCacheOutputStream = nullptr;
}
// if we still have pending stuff to do, lets not close the plugin socket.
if (--mPendingRequests > 0)
return NS_OK;
// we keep our connections around...
nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
if (container) {
@ -944,10 +919,10 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
return NS_OK;
}
}
if (!mPStreamListener)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (!channel)
return NS_ERROR_FAILURE;
@ -956,21 +931,21 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
rv = channel->GetContentType(aContentType);
if (NS_FAILED(rv) && !mRequestFailed)
return rv;
if (!aContentType.IsEmpty())
mContentType = aContentType;
// set error status if stream failed so we notify the plugin
if (mRequestFailed)
aStatus = NS_ERROR_FAILURE;
if (NS_FAILED(aStatus)) {
// on error status cleanup the stream
// and return w/o OnFileAvailable()
mPStreamListener->OnStopBinding(this, aStatus);
return NS_OK;
}
// call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
if (mStreamType >= NP_ASFILE) {
nsCOMPtr<nsIFile> localFile;
@ -983,12 +958,12 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
fileChannel->GetFile(getter_AddRefs(localFile));
}
}
if (localFile) {
OnFileAvailable(localFile);
}
}
if (mStartBinding) {
// On start binding has been called
mPStreamListener->OnStopBinding(this, aStatus);
@ -997,11 +972,11 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
mPStreamListener->OnStartBinding(this);
mPStreamListener->OnStopBinding(this, aStatus);
}
if (NS_SUCCEEDED(aStatus)) {
mStreamComplete = true;
}
return NS_OK;
}
@ -1009,7 +984,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
nsIURI* aURL)
{
nsresult rv = NS_OK;
// If we don't yet have a stream listener, we need to get
// one from the plugin.
// NOTE: this should only happen when a stream was NOT created
@ -1033,11 +1008,11 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
mPStreamListener->SetStreamListenerPeer(this);
bool useLocalCache = false;
// get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
/*
* Assumption
* By the time nsPluginStreamListenerPeer::OnDataAvailable() gets
@ -1077,7 +1052,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
// Also provide all HTTP response headers to our listener.
httpChannel->VisitResponseHeaders(this);
mSeekable = false;
// first we look for a content-encoding header. If we find one, we tell the
// plugin that stream is not seekable, because the plugin always sees
@ -1103,7 +1078,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
}
}
}
// we require a content len
// get Last-Modified header for plugin info
nsAutoCString lastModified;
@ -1111,22 +1086,22 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
!lastModified.IsEmpty()) {
PRTime time64;
PR_ParseTimeString(lastModified.get(), true, &time64); //convert string time to integer time
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch
double fpTime = double(time64);
mModified = (uint32_t)(fpTime * 1e-6 + 0.5);
}
}
rv = mPStreamListener->OnStartBinding(this);
mStartBinding = true;
if (NS_FAILED(rv))
return rv;
mPStreamListener->GetStreamType(&mStreamType);
if (!useLocalCache && mStreamType >= NP_ASFILE) {
// check it out if this is not a file channel.
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
@ -1134,11 +1109,11 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
useLocalCache = true;
}
}
if (useLocalCache) {
SetupPluginCacheFile(channel);
}
return NS_OK;
}
@ -1148,16 +1123,16 @@ nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
nsresult rv;
if (!mPStreamListener)
return NS_ERROR_FAILURE;
nsAutoCString path;
rv = aFile->GetNativePath(path);
if (NS_FAILED(rv)) return rv;
if (path.IsEmpty()) {
NS_WARNING("empty path");
return NS_OK;
}
rv = mPStreamListener->OnFileAvailable(this, path.get());
return rv;
}
@ -1247,7 +1222,7 @@ private:
};
NS_IMPL_ISUPPORTS1(ChannelRedirectProxyCallback, nsIAsyncVerifyRedirectCallback)
NS_IMETHODIMP
nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel,

Просмотреть файл

@ -13,7 +13,8 @@
#include "nsIHttpHeaderVisitor.h"
#include "nsWeakReference.h"
#include "nsNPAPIPluginStreamListener.h"
#include "nsHashtable.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsNPAPIPluginInstance.h"
#include "nsIInterfaceRequestor.h"
#include "nsIChannelEventSink.h"
@ -31,12 +32,12 @@ class CachedFileHolder
public:
CachedFileHolder(nsIFile* cacheFile);
~CachedFileHolder();
void AddRef();
void Release();
nsIFile* file() const { return mFile; }
private:
nsAutoRefCnt mRefCnt;
nsCOMPtr<nsIFile> mFile;
@ -52,7 +53,7 @@ public nsIChannelEventSink
public:
nsPluginStreamListenerPeer();
virtual ~nsPluginStreamListenerPeer();
NS_DECL_ISUPPORTS
NS_DECL_NSIPROGRESSEVENTSINK
NS_DECL_NSIREQUESTOBSERVER
@ -105,7 +106,7 @@ public:
mRequests.ReplaceObjectAt(newRequest, i);
}
}
void CancelRequests(nsresult status)
{
// Copy the array to avoid modification during the loop.
@ -137,7 +138,7 @@ private:
// Set to true if we request failed (like with a HTTP response of 404)
bool mRequestFailed;
/*
* Set to true after nsNPAPIPluginStreamListener::OnStartBinding() has
* been called. Checked in ::OnStopRequest so we can call the
@ -149,20 +150,20 @@ private:
// these get passed to the plugin stream listener
uint32_t mLength;
int32_t mStreamType;
// local cached file, we save the content into local cache if browser cache is not available,
// or plugin asks stream as file and it expects file extension until bug 90558 got fixed
nsRefPtr<CachedFileHolder> mLocalCachedFileHolder;
nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
nsHashtable *mDataForwardToRequest;
nsDataHashtable<nsUint32HashKey, uint32_t>* mDataForwardToRequest;
nsCString mContentType;
bool mSeekable;
uint32_t mModified;
nsRefPtr<nsNPAPIPluginInstance> mPluginInstance;
int32_t mStreamOffset;
bool mStreamComplete;
public:
bool mAbort;
int32_t mPendingRequests;

Просмотреть файл

@ -529,42 +529,7 @@ TelephonyProvider.prototype = {
return;
}
let parentId = this._currentCalls[aClientId][aCallIndex].parentId;
if (parentId) {
this.resumeCall(aClientId, parentId);
return;
}
function onCdmaHoldCallSuccess() {
let call = this._currentCalls[aClientId][aCallIndex];
if (!call) {
return;
}
call.state = RIL.CALL_STATE_HOLDING;
this.notifyCallStateChanged(aClientId, call);
if (!call.childId) {
return;
}
let childCall = this._currentCalls[aClientId][call.childId];
childCall.state = RIL.CALL_STATE_ACTIVE;
this.notifyCallStateChanged(aClientId, childCall);
};
this._getClient(aClientId).sendWorkerMessage("holdCall", {
callIndex: aCallIndex
},(function(response) {
if (!response.success) {
return false;
}
if (response.isCdma) {
onCdmaHoldCallSuccess.call(this);
}
return false;
}).bind(this));
this._getClient(aClientId).sendWorkerMessage("holdCall", { callIndex: aCallIndex });
},
resumeCall: function(aClientId, aCallIndex) {
@ -575,43 +540,7 @@ TelephonyProvider.prototype = {
return;
}
let parentId = this._currentCalls[aClientId][aCallIndex].parentId;
if (parentId) {
this.holdCall(aClientId, parentId);
return;
}
function onCdmaResumeCallSuccess() {
let call = this._currentCalls[aClientId][aCallIndex];
if (!call) {
return;
}
call.state = RIL.CALL_STATE_ACTIVE;
this.notifyCallStateChanged(aClientId, call);
let childId = call.childId;
if (!childId) {
return;
}
let childCall = this._currentCalls[aClientId][childId];
childCall.state = RIL.CALL_STATE_HOLDING;
this.notifyCallStateChanged(aClientId, childCall);
};
this._getClient(aClientId).sendWorkerMessage("resumeCall", {
callIndex: aCallIndex
},(function(response) {
if (!response.success) {
return false;
}
if (response.isCdma) {
onCdmaResumeCallSuccess.call(this);
}
return false;
}).bind(this));
this._getClient(aClientId).sendWorkerMessage("resumeCall", { callIndex: aCallIndex });
},
conferenceCall: function(aClientId) {

Просмотреть файл

@ -20,8 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=850517
sb.win = window;
sb.childA = ifrA.contentWindow;
sb.childB = ifrB.contentWindow;
sb.is = is;
sb.ok = ok;
sb.is = SpecialPowers.wrap(is);
sb.ok = SpecialPowers.wrap(ok);
is(window.theoneandonly.frameElement, ifrA, "Named child resolution works");
SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childA, "Named child resolution works via Xray");', sb);
ifrA.removeAttribute('name');

Просмотреть файл

@ -19,8 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=862918
is(evt.data, 'dosetup', "message from modal window is correct");
var win = SpecialPowers.wrap(evt.source);
win.wrappedJSObject.SpecialPowers = SpecialPowers;
win.wrappedJSObject.is = is;
win.wrappedJSObject.ok = ok;
win.wrappedJSObject.is = SpecialPowers.wrap(is);
win.wrappedJSObject.ok = SpecialPowers.wrap(ok);
win.wrappedJSObject.go();
};

Просмотреть файл

@ -239,7 +239,7 @@ partial interface Document {
//http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register
partial interface Document {
[Throws, Pref="dom.webcomponents.enabled"]
[Throws, Func="nsDocument::IsRegisterElementEnabled"]
object registerElement(DOMString name, optional ElementRegistrationOptions options);
};

Просмотреть файл

@ -75,7 +75,7 @@ XBLFinalize(JSFreeOp *fop, JSObject *obj)
nsXBLDocumentInfo* docInfo =
static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(obj));
nsContentUtils::DeferredFinalize(docInfo);
nsXBLJSClass* c = nsXBLJSClass::fromJSClass(::JS_GetClass(obj));
c->Drop();
}
@ -121,8 +121,7 @@ nsXBLJSClass::Destroy()
"referenced nsXBLJSClass is on LRU list already!?");
if (nsXBLService::gClassTable) {
nsCStringKey key(mKey);
(nsXBLService::gClassTable)->Remove(&key);
nsXBLService::gClassTable->Remove(mKey);
mKey.Truncate();
}
@ -141,14 +140,7 @@ nsXBLJSClass::Destroy()
nsXBLJSClass*
nsXBLService::getClass(const nsCString& k)
{
nsCStringKey key(k);
return getClass(&key);
}
nsXBLJSClass*
nsXBLService::getClass(nsCStringKey *k)
{
return static_cast<nsXBLJSClass*>(nsXBLService::gClassTable->Get(k));
return nsXBLService::gClassTable->Get(k);
}
// Implementation /////////////////////////////////////////////////////////////////
@ -265,7 +257,7 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem
// XXXbz This really shouldn't be a void method!
child->UnbindFromTree();
return;
}
}
child->SetFlags(NODE_IS_ANONYMOUS_ROOT);
@ -360,7 +352,7 @@ nsXBLBinding::GenerateAnonymousContent()
return;
}
// Find out if we're really building kids or if we're just
// using the attribute-setting shorthand hack.
uint32_t contentCount = content->GetChildCount();
@ -478,7 +470,7 @@ nsXBLBinding::FindInsertionPointFor(nsIContent* aChild)
if (mContent) {
return FindInsertionPointForInternal(aChild);
}
return mNextBinding ? mNextBinding->FindInsertionPointFor(aChild)
: nullptr;
}
@ -492,7 +484,7 @@ nsXBLBinding::FindInsertionPointForInternal(nsIContent* aChild)
return point;
}
}
return mDefaultInsertionPoint;
}
@ -584,7 +576,7 @@ nsXBLBinding::InstallEventHandlers()
nsAutoString type;
handler->GetEventName(type);
// If this is a command, add it in the system event group, otherwise
// If this is a command, add it in the system event group, otherwise
// add it to the standard event group.
// Figure out if we're using capturing or not.
@ -684,7 +676,7 @@ nsXBLBinding::UnhookEventHandlers()
if (!manager) {
return;
}
bool isChromeBinding = mPrototypeBinding->IsChrome();
nsXBLPrototypeHandler* curr;
for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
@ -692,7 +684,7 @@ nsXBLBinding::UnhookEventHandlers()
if (!handler) {
continue;
}
nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
if (!eventAtom ||
eventAtom == nsGkAtoms::keyup ||
@ -731,7 +723,7 @@ nsXBLBinding::UnhookEventHandlers()
EventListenerFlags flags;
flags.mCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
// If this is a command, remove it from the system event group, otherwise
// If this is a command, remove it from the system event group, otherwise
// remove it from the standard event group.
if ((handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) &&
@ -905,7 +897,7 @@ nsXBLBinding::InheritsStyle() const
// XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
if (mContent)
return mPrototypeBinding->InheritsStyle();
if (mNextBinding)
return mNextBinding->InheritsStyle();
@ -995,9 +987,8 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
// We need to initialize the class.
*aNew = true;
nsCStringKey key(xblKey);
if (!c) {
c = nsXBLService::getClass(&key);
c = nsXBLService::getClass(xblKey);
}
if (c) {
// If c is on the LRU list, remove it now!
@ -1015,8 +1006,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
nsXBLService::gClassLRUListLength--;
// Remove any mapping from the old name to the class struct.
nsCStringKey oldKey(c->Key());
(nsXBLService::gClassTable)->Remove(&oldKey);
nsXBLService::gClassTable->Remove(c->Key());
// Change the class name and we're done.
nsMemory::Free((void*) c->name);
@ -1025,7 +1015,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
}
// Add c to our table.
(nsXBLService::gClassTable)->Put(&key, (void*)c);
nsXBLService::gClassTable->Put(xblKey, c);
}
// The prototype holds a strong reference to its class struct.
@ -1034,7 +1024,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
// Make a new object prototyped by parent_proto and parented by global.
proto = ::JS_InitClass(cx, // context
global, // global object
parent_proto, // parent proto
parent_proto, // parent proto
c, // JSClass
nullptr, // JSNative ctor
0, // ctor args
@ -1046,7 +1036,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
// This will happen if we're OOM or if the security manager
// denies defining the new class...
(nsXBLService::gClassTable)->Remove(&key);
nsXBLService::gClassTable->Remove(xblKey);
c->Drop();

Просмотреть файл

@ -154,7 +154,7 @@ public:
}
};
// nsXBLStreamListener, a helper class used for
// nsXBLStreamListener, a helper class used for
// asynchronous parsing of URLs
/* Header file */
class nsXBLStreamListener MOZ_FINAL : public nsIStreamListener,
@ -177,7 +177,7 @@ public:
private:
nsCOMPtr<nsIStreamListener> mInner;
nsAutoTArray<nsXBLBindingRequest*, 8> mBindingRequests;
nsCOMPtr<nsIWeakReference> mBoundDocument;
nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest
nsCOMPtr<nsIDocument> mBindingDocument; // Only set until OnStartRequest
@ -247,7 +247,7 @@ nsXBLStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aCtxt)
return mInner->OnStartRequest(request, aCtxt);
}
NS_IMETHODIMP
NS_IMETHODIMP
nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aCtxt, nsresult aStatus)
{
nsresult rv = NS_OK;
@ -301,7 +301,7 @@ nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent)
// We have to do a flush prior to notification of the document load.
// This has to happen since the HTML content sink can be holding on
// to notifications related to our children (e.g., if you bind to the
// <body> tag) that result in duplication of content.
// <body> tag) that result in duplication of content.
// We need to get the sink's notifications flushed and then make the binding
// ready.
if (count > 0) {
@ -347,7 +347,7 @@ nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent)
cache->PutXBLDocumentInfo(info);
}
#endif
bindingManager->PutXBLDocumentInfo(info);
// Notify all pending requests that their bindings are
@ -368,7 +368,7 @@ nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent)
// Static member variable initialization
bool nsXBLService::gAllowDataURIs = false;
nsHashtable* nsXBLService::gClassTable = nullptr;
nsXBLService::ClassTable* nsXBLService::gClassTable = nullptr;
LinkedList<nsXBLJSClass>* nsXBLService::gClassLRUList = nullptr;
uint32_t nsXBLService::gClassLRUListLength = 0;
@ -393,7 +393,7 @@ nsXBLService::Init()
// Constructors/Destructors
nsXBLService::nsXBLService(void)
{
gClassTable = new nsHashtable();
gClassTable = new ClassTable();
gClassLRUList = new LinkedList<nsXBLJSClass>();
Preferences::AddBoolVarCache(&gAllowDataURIs, "layout.debug.enable_data_xbl");
@ -423,7 +423,7 @@ nsXBLService::IsChromeOrResourceURI(nsIURI* aURI)
{
bool isChrome = false;
bool isResource = false;
if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) &&
if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) &&
NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
return (isChrome || isResource);
return false;
@ -435,10 +435,10 @@ nsXBLService::IsChromeOrResourceURI(nsIURI* aURI)
nsresult
nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
nsIPrincipal* aOriginPrincipal,
nsXBLBinding** aBinding, bool* aResolveStyle)
nsXBLBinding** aBinding, bool* aResolveStyle)
{
NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
*aBinding = nullptr;
*aResolveStyle = false;
@ -518,11 +518,11 @@ nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
// Figure out if we have any scoped sheets. If so, we do a second resolve.
*aResolveStyle = newBinding->HasStyleSheets();
newBinding.swap(*aBinding);
}
return NS_OK;
return NS_OK;
}
nsresult
@ -537,7 +537,7 @@ nsXBLService::FlushStyleBindings(nsIContent* aContent)
aContent->SetXBLBinding(nullptr); // Flush old style bindings
}
return NS_OK;
}
@ -585,6 +585,15 @@ nsXBLService::AttachGlobalKeyHandler(EventTarget* aTarget)
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
TrustedEventsAtSystemGroupBubble());
// The capturing listener is only used for XUL keysets to properly handle
// shortcut keys in a multi-process environment.
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
TrustedEventsAtSystemGroupCapture());
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
TrustedEventsAtSystemGroupCapture());
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
TrustedEventsAtSystemGroupCapture());
if (contentNode)
return contentNode->SetProperty(nsGkAtoms::listener,
handler.forget().take(),
@ -630,6 +639,13 @@ nsXBLService::DetachGlobalKeyHandler(EventTarget* aTarget)
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
TrustedEventsAtSystemGroupBubble());
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
TrustedEventsAtSystemGroupCapture());
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
TrustedEventsAtSystemGroupCapture());
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
TrustedEventsAtSystemGroupCapture());
contentNode->DeleteProperty(nsGkAtoms::listener);
return NS_OK;
@ -659,7 +675,7 @@ nsXBLService::FlushMemory()
nsresult
nsXBLService::BindingReady(nsIContent* aBoundElement,
nsIURI* aURI,
nsIURI* aURI,
bool* aIsReady)
{
// Don't do a security check here; we know this binding is set to go.
@ -667,7 +683,7 @@ nsXBLService::BindingReady(nsIContent* aBoundElement,
}
nsresult
nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
bool* aIsReady, nsXBLBinding** aResult)
{
@ -678,7 +694,7 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
}
nsresult
nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
bool* aIsReady, nsXBLBinding** aResult,
nsTArray<nsIURI*>& aDontExtendURIs)
@ -686,7 +702,7 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
NS_ASSERTION(aPeekOnly || aResult,
"Must have non-null out param if not just peeking to see "
"whether the binding is ready");
if (aResult)
*aResult = nullptr;
@ -703,7 +719,7 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
aOriginPrincipal,
false, getter_AddRefs(docInfo));
NS_ENSURE_SUCCESS(rv, rv);
if (!docInfo)
return NS_ERROR_FAILURE;
@ -821,11 +837,11 @@ IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal)
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
return true;
}
nsCOMPtr<nsIURI> uri;
aPrincipal->GetURI(getter_AddRefs(uri));
NS_ENSURE_TRUE(uri, false);
bool isChrome = false;
return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome;
}
@ -841,11 +857,11 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
NS_PRECONDITION(aBindingURI, "Must have a binding URI");
NS_PRECONDITION(!aOriginPrincipal || aBoundDocument,
"If we're doing a security check, we better have a document!");
nsresult rv;
if (aOriginPrincipal) {
// Security check - Enforce same-origin policy, except to chrome.
// We have to be careful to not pass aContent as the context here.
// We have to be careful to not pass aContent as the context here.
// Otherwise, if there is a JS-implemented content policy, we will attempt
// to wrap the content node, which will try to load XBL bindings for it, if
// any. Since we're not done loading this binding yet, that will reenter
@ -886,13 +902,13 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
#ifdef MOZ_XUL
// We've got a file. Check our XBL document cache.
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
bool useXULCache = cache && cache->IsEnabled();
bool useXULCache = cache && cache->IsEnabled();
if (useXULCache) {
// The first line of defense is the chrome cache.
// The first line of defense is the chrome cache.
// This cache crosses the entire product, so that any XBL bindings that are
// part of chrome will be reused across all XUL documents.
info = cache->GetXBLDocumentInfo(documentURI);
info = cache->GetXBLDocumentInfo(documentURI);
}
#endif
@ -957,7 +973,7 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
if (!info) {
// Finally, if all lines of defense fail, we go and fetch the binding
// document.
// Always load chrome synchronously
bool chrome;
if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome)
@ -985,7 +1001,7 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
info->WritePrototypeBindings();
}
#endif
if (bindingManager) {
// Also put it in our binding manager's document table.
bindingManager->PutXBLDocumentInfo(info);
@ -1001,7 +1017,7 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
nsresult
nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
nsIURI* aDocumentURI, nsIURI* aBindingURI,
nsIURI* aDocumentURI, nsIURI* aBindingURI,
bool aForceSyncLoad, nsIDocument** aResult)
{
nsresult rv = NS_OK;
@ -1009,7 +1025,7 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
*aResult = nullptr;
// Now we have to synchronously load the binding file.
// Create an XML content sink and a parser.
// Create an XML content sink and a parser.
nsCOMPtr<nsILoadGroup> loadGroup;
if (aBoundDocument)
loadGroup = aBoundDocument->GetDocumentLoadGroup();
@ -1092,4 +1108,3 @@ nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoun
return NS_OK;
}

Просмотреть файл

@ -14,8 +14,9 @@
#include "nsWeakReference.h"
#include "js/Class.h" // nsXBLJSClass derives from JSClass
#include "nsTArray.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
class nsCStringKey;
class nsXBLBinding;
class nsXBLDocumentInfo;
class nsXBLJSClass;
@ -24,7 +25,6 @@ class nsIDocument;
class nsString;
class nsIURI;
class nsIPrincipal;
class nsHashtable;
namespace mozilla {
namespace dom {
@ -84,10 +84,10 @@ protected:
// Release any memory that we can
nsresult FlushMemory();
// This method synchronously loads and parses an XBL file.
nsresult FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
nsIURI* aDocumentURI, nsIURI* aBindingURI,
nsIURI* aDocumentURI, nsIURI* aBindingURI,
bool aForceSyncLoad, nsIDocument** aResult);
/**
@ -123,7 +123,8 @@ protected:
public:
static bool gDisableChromeCache;
static nsHashtable* gClassTable; // A table of nsXBLJSClass objects.
typedef nsDataHashtable<nsCStringHashKey, nsXBLJSClass*> ClassTable;
static ClassTable* gClassTable; // A table of nsXBLJSClass objects.
static mozilla::LinkedList<nsXBLJSClass>* gClassLRUList;
// LRU list of cached classes.
@ -135,7 +136,6 @@ public:
// Look up the class by key in gClassTable.
static nsXBLJSClass *getClass(const nsCString &key);
static nsXBLJSClass *getClass(nsCStringKey *key);
};
class nsXBLJSClass : public mozilla::LinkedListElement<nsXBLJSClass>

Просмотреть файл

@ -26,6 +26,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "nsEventStateManager.h"
#include "nsIEditor.h"
#include "nsIHTMLEditor.h"
@ -276,24 +277,23 @@ nsXBLWindowKeyHandler::WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventTy
nsresult rv = EnsureHandlers();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Element> el = GetElement();
bool isDisabled;
nsCOMPtr<Element> el = GetElement(&isDisabled);
if (!el) {
if (mUserHandler) {
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler);
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler, true);
aKeyEvent->GetDefaultPrevented(&prevent);
if (prevent)
return NS_OK; // Handled by the user bindings. Our work here is done.
}
}
nsCOMPtr<nsIContent> content = do_QueryInterface(el);
// skip keysets that are disabled
if (content && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
nsGkAtoms::_true, eCaseMatters)) {
if (el && isDisabled) {
return NS_OK;
}
WalkHandlersInternal(aKeyEvent, aEventType, mHandler);
WalkHandlersInternal(aKeyEvent, aEventType, mHandler, true);
return NS_OK;
}
@ -304,20 +304,50 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDOMEvent* aEvent)
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent));
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
uint16_t eventPhase;
aEvent->GetEventPhase(&eventPhase);
if (eventPhase == nsIDOMEvent::CAPTURING_PHASE) {
HandleEventOnCapture(keyEvent);
return NS_OK;
}
nsAutoString eventType;
aEvent->GetType(eventType);
nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(eventType);
NS_ENSURE_TRUE(eventTypeAtom, NS_ERROR_OUT_OF_MEMORY);
if (!mWeakPtrForElement) {
nsCOMPtr<mozilla::dom::Element> originalTarget =
do_QueryInterface(aEvent->GetInternalNSEvent()->originalTarget);
if (nsEventStateManager::IsRemoteTarget(originalTarget)) {
return NS_OK;
}
return WalkHandlers(keyEvent, eventTypeAtom);
}
void
nsXBLWindowKeyHandler::HandleEventOnCapture(nsIDOMKeyEvent* aEvent)
{
WidgetKeyboardEvent* widgetEvent =
aEvent->GetInternalNSEvent()->AsKeyboardEvent();
if (widgetEvent->mFlags.mNoCrossProcessBoundaryForwarding) {
return;
}
return WalkHandlers(keyEvent, eventTypeAtom);
nsCOMPtr<mozilla::dom::Element> originalTarget =
do_QueryInterface(aEvent->GetInternalNSEvent()->originalTarget);
if (!nsEventStateManager::IsRemoteTarget(originalTarget)) {
return;
}
if (!HasHandlerForEvent(aEvent)) {
return;
}
// If this event hasn't been marked as mNoCrossProcessBoundaryForwarding
// yet, it means it wasn't processed by content. We'll not call any
// of the handlers at this moment, and will wait for the event to be
// redispatched with mNoCrossProcessBoundaryForwarding = 1 to process it.
// Inform the child process that this is a event that we want a reply
// from.
widgetEvent->mFlags.mWantReplyFromContentProcess = 1;
aEvent->StopPropagation();
}
//
@ -391,29 +421,31 @@ nsXBLWindowKeyHandler::IsHTMLEditableFieldFocused()
// WalkHandlersInternal and WalkHandlersAndExecute
//
// Given a particular DOM event and a pointer to the first handler in the list,
// scan through the list to find something to handle the event and then make it
// so.
// scan through the list to find something to handle the event. If aExecute = true,
// the handler will be executed; otherwise just return an answer telling if a handler
// for that event was found.
//
nsresult
bool
nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler)
nsXBLPrototypeHandler* aHandler,
bool aExecute)
{
nsAutoTArray<nsShortcutCandidate, 10> accessKeys;
nsContentUtils::GetAccelKeyCandidates(aKeyEvent, accessKeys);
if (accessKeys.IsEmpty()) {
WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, 0, false);
return NS_OK;
return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
0, false, aExecute);
}
for (uint32_t i = 0; i < accessKeys.Length(); ++i) {
nsShortcutCandidate &key = accessKeys[i];
if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
key.mCharCode, key.mIgnoreShift))
return NS_OK;
key.mCharCode, key.mIgnoreShift, aExecute))
return true;
}
return NS_OK;
return false;
}
bool
@ -421,7 +453,8 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler,
uint32_t aCharCode,
bool aIgnoreShiftKey)
bool aIgnoreShiftKey,
bool aExecute)
{
nsresult rv;
@ -491,6 +524,10 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
piTarget = mTarget;
}
if (!aExecute) {
return true;
}
rv = currHandler->ExecuteHandler(piTarget, aKeyEvent);
if (NS_SUCCEEDED(rv)) {
return true;
@ -500,10 +537,38 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
return false;
}
bool
nsXBLWindowKeyHandler::HasHandlerForEvent(nsIDOMKeyEvent* aEvent)
{
if (!aEvent->InternalDOMEvent()->IsTrusted()) {
return false;
}
nsresult rv = EnsureHandlers();
NS_ENSURE_SUCCESS(rv, false);
bool isDisabled;
nsCOMPtr<Element> el = GetElement(&isDisabled);
if (el && isDisabled) {
return false;
}
nsAutoString eventType;
aEvent->GetType(eventType);
nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(eventType);
NS_ENSURE_TRUE(eventTypeAtom, false);
return WalkHandlersInternal(aEvent, eventTypeAtom, mHandler, false);
}
already_AddRefed<Element>
nsXBLWindowKeyHandler::GetElement()
nsXBLWindowKeyHandler::GetElement(bool* aIsDisabled)
{
nsCOMPtr<Element> element = do_QueryReferent(mWeakPtrForElement);
if (element && aIsDisabled) {
*aIsDisabled = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
nsGkAtoms::_true, eCaseMatters);
}
return element.forget();
}

Просмотреть файл

@ -35,14 +35,23 @@ protected:
nsresult WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType);
// walk the handlers, looking for one to handle the event
nsresult WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler);
bool WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler,
bool aExecute);
// walk the handlers for aEvent, aCharCode and aIgnoreShiftKey
// walk the handlers for aEvent, aCharCode and aIgnoreShiftKey. Execute it
// if aExecute = true.
bool WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler,
uint32_t aCharCode, bool aIgnoreShiftKey);
nsXBLPrototypeHandler* aHandler,
uint32_t aCharCode, bool aIgnoreShiftKey,
bool aExecute);
// HandleEvent function for the capturing phase.
void HandleEventOnCapture(nsIDOMKeyEvent* aEvent);
// Check if any handler would handle the given event.
bool HasHandlerForEvent(nsIDOMKeyEvent* aEvent);
// lazily load the handlers. Overridden to handle being attached
// to a particular element rather than the document
@ -57,8 +66,10 @@ protected:
bool IsHTMLEditableFieldFocused();
// Returns the element which was passed as a parameter to the constructor,
// unless the element has been removed from the document.
already_AddRefed<mozilla::dom::Element> GetElement();
// unless the element has been removed from the document. Optionally returns
// whether the disabled attribute is set on the element (assuming the element
// is non-null).
already_AddRefed<mozilla::dom::Element> GetElement(bool* aIsDisabled = nullptr);
// Using weak pointer to the DOM Element.
nsWeakPtr mWeakPtrForElement;
mozilla::dom::EventTarget* mTarget; // weak ref

Просмотреть файл

@ -68,5 +68,39 @@ Matrix::NudgeToIntegers()
NudgeToInteger(&_32);
}
Rect
Matrix4x4::TransformBounds(const Rect& aRect) const
{
Point quad[4];
Float min_x, max_x;
Float min_y, max_y;
quad[0] = *this * aRect.TopLeft();
quad[1] = *this * aRect.TopRight();
quad[2] = *this * aRect.BottomLeft();
quad[3] = *this * aRect.BottomRight();
min_x = max_x = quad[0].x;
min_y = max_y = quad[0].y;
for (int i = 1; i < 4; i++) {
if (quad[i].x < min_x) {
min_x = quad[i].x;
}
if (quad[i].x > max_x) {
max_x = quad[i].x;
}
if (quad[i].y < min_y) {
min_y = quad[i].y;
}
if (quad[i].y > max_y) {
max_y = quad[i].y;
}
}
return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
}
}
}

Просмотреть файл

@ -353,6 +353,40 @@ public:
return Is2D() && As2D().IsIntegerTranslation();
}
Point4D operator *(const Point4D& aPoint) const
{
Point4D retPoint;
retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41;
retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42;
retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43;
retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44;
return retPoint;
}
Point3D operator *(const Point3D& aPoint) const
{
Point4D temp(aPoint.x, aPoint.y, aPoint.z, 1);
temp = *this * temp;
temp /= temp.w;
return Point3D(temp.x, temp.y, temp.z);
}
Point operator *(const Point &aPoint) const
{
Point4D temp(aPoint.x, aPoint.y, 0, 1);
temp = *this * temp;
temp /= temp.w;
return Point(temp.x, temp.y);
}
GFX2D_API Rect TransformBounds(const Rect& rect) const;
// Apply a scale to this matrix. This scale will be applied -before- the
// existing transformation of the matrix.
Matrix4x4 &Scale(Float aX, Float aY, Float aZ)

Просмотреть файл

@ -10,6 +10,7 @@
#include "Types.h"
#include "BasePoint.h"
#include "BasePoint3D.h"
#include "BasePoint4D.h"
#include "BaseSize.h"
#include <cmath>
@ -92,6 +93,27 @@ struct Point3DTyped :
};
typedef Point3DTyped<UnknownUnits> Point3D;
template<class units>
struct Point4DTyped :
public BasePoint4D< Float, Point4DTyped<units> > {
typedef BasePoint4D< Float, Point4DTyped<units> > Super;
Point4DTyped() : Super() {}
Point4DTyped(Float aX, Float aY, Float aZ, Float aW) : Super(aX, aY, aZ, aW) {}
// XXX When all of the code is ported, the following functions to convert to and from
// unknown types should be removed.
static Point4DTyped<units> FromUnknownPoint(const Point4DTyped<UnknownUnits>& aPoint) {
return Point4DTyped<units>(aPoint.x, aPoint.y, aPoint.z, aPoint.w);
}
Point4DTyped<UnknownUnits> ToUnknownPoint() const {
return Point4DTyped<UnknownUnits>(this->x, this->y, this->z, this->w);
}
};
typedef Point4DTyped<UnknownUnits> Point4D;
template<class units>
struct IntSizeTyped :
public BaseSize< int32_t, IntSizeTyped<units> >,

Просмотреть файл

@ -82,24 +82,14 @@ TextureClientX11::UpdateSurface(gfxASurface* aSurface)
{
MOZ_ASSERT(IsValid());
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
RefPtr<DrawTarget> dt = GetAsDrawTarget();
if (!dt) {
return false;
}
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
dt->CopySurface(source, IntRect(IntPoint(), GetSize()), IntPoint());
} else {
if (!mSurface) {
return false;
}
nsRefPtr<gfxContext> ctx = new gfxContext(mSurface.get());
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->DrawSurface(aSurface, mSurface->GetSize());
RefPtr<DrawTarget> dt = GetAsDrawTarget();
if (!dt) {
return false;
}
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
dt->CopySurface(source, IntRect(IntPoint(), GetSize()), IntPoint());
return true;
}

Просмотреть файл

@ -37,11 +37,6 @@ using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
TextureClientPoolMember::TextureClientPoolMember(SurfaceFormat aFormat, TextureClientPool* aTexturePool)
: mFormat(aFormat)
, mTexturePool(aTexturePool)
{}
ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
: mPhase(PHASE_NONE)
, mWidget(aWidget)
@ -61,8 +56,6 @@ ClientLayerManager::~ClientLayerManager()
mRoot = nullptr;
MOZ_COUNT_DTOR(ClientLayerManager);
mTexturePools.clear();
}
int32_t
@ -233,9 +226,8 @@ ClientLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
MakeSnapshotIfRequired();
}
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
item; item = item->getNext()) {
item->mTexturePool->ReturnDeferredClients();
for (size_t i = 0; i < mTexturePools.Length(); i++) {
mTexturePools[i]->ReturnDeferredClients();
}
}
@ -458,21 +450,18 @@ ClientLayerManager::SetIsFirstPaint()
TextureClientPool*
ClientLayerManager::GetTexturePool(SurfaceFormat aFormat)
{
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
item; item = item->getNext()) {
if (item->mFormat == aFormat) {
return item->mTexturePool;
for (size_t i = 0; i < mTexturePools.Length(); i++) {
if (mTexturePools[i]->GetFormat() == aFormat) {
return mTexturePools[i];
}
}
TextureClientPoolMember* texturePoolMember =
new TextureClientPoolMember(aFormat,
mTexturePools.AppendElement(
new TextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE,
TILEDLAYERBUFFER_TILE_SIZE),
mForwarder));
mTexturePools.insertBack(texturePoolMember);
return texturePoolMember->mTexturePool;
return mTexturePools.LastElement();
}
SimpleTextureClientPool*
@ -502,9 +491,8 @@ ClientLayerManager::ClearCachedResources(Layer* aSubtree)
} else if (mRoot) {
ClearLayer(mRoot);
}
for (const TextureClientPoolMember* item = mTexturePools.getFirst();
item; item = item->getNext()) {
item->mTexturePool->Clear();
for (size_t i = 0; i < mTexturePools.Length(); i++) {
mTexturePools[i]->Clear();
}
}

Просмотреть файл

@ -36,15 +36,6 @@ class PLayerChild;
class TextureClientPool;
class SimpleTextureClientPool;
class TextureClientPoolMember
: public LinkedListElement<TextureClientPoolMember> {
public:
TextureClientPoolMember(gfx::SurfaceFormat aFormat, TextureClientPool* aTexturePool);
gfx::SurfaceFormat mFormat;
RefPtr<TextureClientPool> mTexturePool;
};
class ClientLayerManager : public LayerManager
{
typedef nsTArray<nsRefPtr<Layer> > LayerRefArray;
@ -229,7 +220,7 @@ private:
bool mNeedsComposite;
RefPtr<ShadowLayerForwarder> mForwarder;
LinkedList<TextureClientPoolMember> mTexturePools;
nsAutoTArray<RefPtr<TextureClientPool>,2> mTexturePools;
// indexed by gfx::SurfaceFormat
nsTArray<RefPtr<SimpleTextureClientPool> > mSimpleTilePools;

Просмотреть файл

@ -103,7 +103,6 @@ ContentClientBasic::CreateBuffer(ContentType aType,
RefPtr<gfx::DrawTarget>* aWhiteDT)
{
MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContent());
gfxImageFormat format =
gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
@ -1285,7 +1284,6 @@ ContentClientIncremental::BorrowDrawTargetForPainting(ThebesLayer* aLayer,
"BeginUpdate should always modify the draw region in the same way!");
FillSurface(onBlack, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0));
FillSurface(onWhite, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0));
MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContent());
RefPtr<DrawTarget> onBlackDT = gfxPlatform::GetPlatform()->CreateDrawTargetForUpdateSurface(onBlack, onBlack->GetSize().ToIntSize());
RefPtr<DrawTarget> onWhiteDT = gfxPlatform::GetPlatform()->CreateDrawTargetForUpdateSurface(onWhite, onWhite->GetSize().ToIntSize());
mLoanedDrawTarget = Factory::CreateDualDrawTarget(onBlackDT, onWhiteDT);
@ -1294,7 +1292,6 @@ ContentClientIncremental::BorrowDrawTargetForPainting(ThebesLayer* aLayer,
}
} else {
nsRefPtr<gfxASurface> surf = GetUpdateSurface(BUFFER_BLACK, aPaintState.mRegionToDraw);
MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContent());
mLoanedDrawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForUpdateSurface(surf, surf->GetSize().ToIntSize());
}
if (!mLoanedDrawTarget) {

Просмотреть файл

@ -248,29 +248,8 @@ DisableGralloc(SurfaceFormat aFormat)
if (aFormat == gfx::SurfaceFormat::A8) {
return true;
}
#if ANDROID_VERSION <= 15
static bool checkedDevice = false;
static bool disableGralloc = false;
if (!checkedDevice) {
char propValue[PROPERTY_VALUE_MAX];
property_get("ro.product.device", propValue, "None");
if (strcmp("crespo",propValue) == 0) {
NS_WARNING("Nexus S has issues with gralloc, falling back to shmem");
disableGralloc = true;
}
checkedDevice = true;
}
if (disableGralloc) {
return true;
}
return false;
#else
return false;
#endif
}
#endif
@ -678,25 +657,13 @@ BufferTextureClient::UpdateSurface(gfxASurface* aSurface)
return false;
}
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
RefPtr<DrawTarget> dt = GetAsDrawTarget();
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
RefPtr<DrawTarget> dt = GetAsDrawTarget();
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
dt->CopySurface(source, IntRect(IntPoint(), serializer.GetSize()), IntPoint());
// XXX - if the Moz2D backend is D2D, we would be much better off memcpying
// the content of the surface directly because with D2D, GetAsDrawTarget is
// very expensive.
} else {
RefPtr<gfxImageSurface> surf = serializer.GetAsThebesSurface();
if (!surf) {
return false;
}
nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width,
serializer.GetSize().height));
}
dt->CopySurface(source, IntRect(IntPoint(), serializer.GetSize()), IntPoint());
// XXX - if the Moz2D backend is D2D, we would be much better off memcpying
// the content of the surface directly because with D2D, GetAsDrawTarget is
// very expensive.
if (TextureRequiresLocking(mFlags) && !ImplementsLocking()) {
// We don't have support for proper locking yet, so we'll

Просмотреть файл

@ -30,6 +30,11 @@ TextureClientPool::TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aS
mTimer = do_CreateInstance("@mozilla.org/timer;1");
}
TextureClientPool::~TextureClientPool()
{
mTimer->Cancel();
}
TemporaryRef<TextureClient>
TextureClientPool::GetTextureClient()
{

Просмотреть файл

@ -24,6 +24,7 @@ public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(TextureClientPool)
TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
ISurfaceAllocator *aAllocator);
~TextureClientPool();
/**
* Gets an allocated TextureClient of size and format that are determined
@ -78,6 +79,8 @@ public:
*/
void Clear();
gfx::SurfaceFormat GetFormat() { return mFormat; }
private:
// The time in milliseconds before the pool will be shrunk to the minimum
// size after returning a client.

Просмотреть файл

@ -318,9 +318,8 @@ TiledContentHost::RenderTile(const TileHost& aTile,
}
nsIntRect screenBounds = aScreenRegion.GetBounds();
Matrix mat = aTransform.As2D();
Rect quad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
quad = mat.TransformBounds(quad);
quad = aTransform.TransformBounds(quad);
if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(aClipRect))) {
return;

Просмотреть файл

@ -408,14 +408,6 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
FillTexturesBlackWhite(aRegion, visibleRect.TopLeft());
if (!gfxPlatform::GetPlatform()->SupportsAzureContent()) {
gfxASurface* surfaces[2] = { mD2DSurface.get(), mD2DSurfaceOnWhite.get() };
destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces));
// Using this surface as a source will likely go horribly wrong, since
// only the onBlack surface will really be used, so alpha information will
// be incorrect.
destinationSurface->SetAllowUseAsSource(false);
}
} else {
destinationSurface = mD2DSurface;
}
@ -465,18 +457,7 @@ ThebesLayerD3D10::CreateNewTextures(const gfx::IntSize &aSize, SurfaceMode aMode
NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
}
if (!gfxPlatform::GetPlatform()->SupportsAzureContent()) {
mD2DSurface = new gfxD2DSurface(mTexture, aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ?
gfxContentType::COLOR : gfxContentType::COLOR_ALPHA);
if (!mD2DSurface || mD2DSurface->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurface = nullptr;
return;
}
} else {
mDrawTarget = nullptr;
}
mDrawTarget = nullptr;
}
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA && !mTextureOnWhite) {
@ -493,20 +474,10 @@ ThebesLayerD3D10::CreateNewTextures(const gfx::IntSize &aSize, SurfaceMode aMode
NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
}
if (!gfxPlatform::GetPlatform()->SupportsAzureContent()) {
mD2DSurfaceOnWhite = new gfxD2DSurface(mTextureOnWhite, gfxContentType::COLOR);
if (!mD2DSurfaceOnWhite || mD2DSurfaceOnWhite->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurfaceOnWhite = nullptr;
return;
}
} else {
mDrawTarget = nullptr;
}
mDrawTarget = nullptr;
}
if (gfxPlatform::GetPlatform()->SupportsAzureContent() && !mDrawTarget) {
if (!mDrawTarget) {
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
mDrawTarget = Factory::CreateDualDrawTargetForD3D10Textures(mTexture, mTextureOnWhite, SurfaceFormat::B8G8R8X8);
} else {

Просмотреть файл

@ -47,12 +47,16 @@ IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface)
ISurfaceAllocator::~ISurfaceAllocator()
{
ShrinkShmemSectionHeap();
// Check if we're not leaking..
MOZ_ASSERT(mUsedShmems.empty());
}
void
ISurfaceAllocator::Finalize()
{
ShrinkShmemSectionHeap();
}
bool
ISurfaceAllocator::AllocSharedImageSurface(const gfx::IntSize& aSize,
gfxContentType aContent,

Просмотреть файл

@ -17,6 +17,7 @@
#include "mozilla/layers/LayersMessages.h" // for ShmemSection
#include "LayersTypes.h"
#include <vector>
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
/*
* FIXME [bjacob] *** PURE CRAZYNESS WARNING ***
@ -76,12 +77,14 @@ bool ReleaseOwnedSurfaceDescriptor(const SurfaceDescriptor& aDescriptor);
* These methods should be only called in the ipdl implementor's thread, unless
* specified otherwise in the implementing class.
*/
class ISurfaceAllocator : public AtomicRefCounted<ISurfaceAllocator>
class ISurfaceAllocator : public AtomicRefCountedWithFinalize<ISurfaceAllocator>
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
ISurfaceAllocator() {}
void Finalize();
/**
* Returns the type of backend that is used off the main thread.
* We only don't allow changing the backend type at runtime so this value can
@ -181,7 +184,7 @@ protected:
// This is used to implement an extremely simple & naive heap allocator.
std::vector<mozilla::ipc::Shmem> mUsedShmems;
friend class detail::RefCounted<ISurfaceAllocator, detail::AtomicRefCount>;
friend class AtomicRefCountedWithFinalize<ISurfaceAllocator>;
};
class GfxMemoryImageReporter MOZ_FINAL : public nsIMemoryReporter

Просмотреть файл

@ -423,29 +423,6 @@ ISurfaceAllocator::PlatformAllocSurfaceDescriptor(const gfx::IntSize& aSize,
SurfaceDescriptor* aBuffer)
{
// Check for devices that have problems with gralloc. We only check for
// this on ICS or earlier, in hopes that JB will work.
#if ANDROID_VERSION <= 15
static bool checkedDevice = false;
static bool disableGralloc = false;
if (!checkedDevice) {
char propValue[PROPERTY_VALUE_MAX];
property_get("ro.product.device", propValue, "None");
if (strcmp("crespo",propValue) == 0) {
NS_WARNING("Nexus S has issues with gralloc, falling back to shmem");
disableGralloc = true;
}
checkedDevice = true;
}
if (disableGralloc) {
return false;
}
#endif
// Some GL implementations fail to render gralloc textures with
// width < 64. There's not much point in gralloc'ing buffers that
// small anyway, so fall back on shared memory plus a texture

Просмотреть файл

@ -169,18 +169,10 @@ GrallocTextureClientOGL::UpdateSurface(gfxASurface* aSurface)
return false;
}
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
RefPtr<DrawTarget> dt = GetAsDrawTarget();
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
RefPtr<DrawTarget> dt = GetAsDrawTarget();
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
dt->CopySurface(source, IntRect(IntPoint(), GetSize()), IntPoint());
} else {
nsRefPtr<gfxASurface> surf = GetAsSurface();
nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->DrawSurface(aSurface, gfxSize(GetSize().width,
GetSize().height));
}
dt->CopySurface(source, IntRect(IntPoint(), GetSize()), IntPoint());
return true;
}

Просмотреть файл

@ -362,17 +362,10 @@ gfxASurface::CopyToARGB32ImageSurface()
nsRefPtr<gfxImageSurface> imgSurface =
new gfxImageSurface(size, gfxImageFormat::ARGB32);
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(imgSurface, IntSize(size.width, size.height));
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, this);
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(imgSurface, IntSize(size.width, size.height));
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, this);
dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint());
} else {
gfxContext ctx(imgSurface);
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
ctx.SetSource(this);
ctx.Paint();
}
dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint());
return imgSurface.forget();
}

Просмотреть файл

@ -392,13 +392,11 @@ gfxPlatform::Init()
NS_RUNTIMEABORT("Could not initialize mScreenReferenceSurface");
}
if (gPlatform->SupportsAzureContent()) {
gPlatform->mScreenReferenceDrawTarget =
gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
SurfaceFormat::B8G8R8A8);
if (!gPlatform->mScreenReferenceDrawTarget) {
NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
}
gPlatform->mScreenReferenceDrawTarget =
gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
SurfaceFormat::B8G8R8A8);
if (!gPlatform->mScreenReferenceDrawTarget) {
NS_RUNTIMEABORT("Could not initialize mScreenReferenceDrawTarget");
}
rv = gfxFontCache::Init();

Просмотреть файл

@ -256,20 +256,6 @@ public:
CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize,
int32_t aStride, mozilla::gfx::SurfaceFormat aFormat);
/**
* Returns true if we will render content using Azure using a gfxPlatform
* provided DrawTarget.
* Prefer using SupportsAzureContentForDrawTarget or
* SupportsAzureContentForType.
* This function is potentially misleading and dangerous because we might
* support a certain Azure backend on the current platform, but when you
* ask for a DrawTarget you get one for a different backend which is not
* supported for content drawing.
*/
bool SupportsAzureContent() {
return GetContentBackend() != mozilla::gfx::BackendType::NONE;
}
/**
* Returns true if we should use Azure to render content with aTarget. For
* example, it is possible that we are using Direct2D for rendering and thus

Просмотреть файл

@ -235,19 +235,10 @@ ClippedImage::GetFrameInternal(const nsIntSize& aViewportSize,
mozilla::RefPtr<mozilla::gfx::DrawTarget> target;
nsRefPtr<gfxContext> ctx;
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
target = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(gfx::IntSize(mClip.width, mClip.height),
gfx::SurfaceFormat::B8G8R8A8);
ctx = new gfxContext(target);
} else {
target = gfxPlatform::GetPlatform()->
CreateOffscreenCanvasDrawTarget(gfx::IntSize(mClip.width, mClip.height),
gfx::SurfaceFormat::B8G8R8A8);
nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
GetThebesSurfaceForDrawTarget(target);
ctx = new gfxContext(surface);
}
target = gfxPlatform::GetPlatform()->
CreateOffscreenContentDrawTarget(gfx::IntSize(mClip.width, mClip.height),
gfx::SurfaceFormat::B8G8R8A8);
ctx = new gfxContext(target);
// Create our callback.
nsRefPtr<gfxDrawingCallback> drawTileCallback =

Просмотреть файл

@ -17,12 +17,6 @@
namespace base {
namespace {
// Paranoia. Semaphores and shared memory segments should live in different
// namespaces, but who knows what's out there.
const char kSemaphoreSuffix[] = "-sem";
}
SharedMemory::SharedMemory()
: mapped_file_(-1),
inode_(0),

Просмотреть файл

@ -302,20 +302,6 @@ TrimPositions TrimStringT(const STR& input,
((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
}
// Removes characters in trim_chars from the beginning and end of input.
// NOTE: Safe to use the same variable for both input and output.
static bool TrimString(const std::wstring& input,
const wchar_t trim_chars[],
std::wstring* output) {
return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
}
static bool TrimString(const std::string& input,
const char trim_chars[],
std::string* output) {
return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
}
TrimPositions TrimWhitespace(const std::wstring& input,
TrimPositions positions,
std::wstring* output) {
@ -501,6 +487,24 @@ struct IntToStringT {
}
};
// This set of templates is very similar to the above templates, but
// for testing whether an integer is negative.
template <typename INT2, bool NEG2>
struct TestNegT {};
template <typename INT2>
struct TestNegT<INT2, false> {
static bool TestNeg(INT2 value) {
// value is unsigned, and can never be negative.
return false;
}
};
template <typename INT2>
struct TestNegT<INT2, true> {
static bool TestNeg(INT2 value) {
return value < 0;
}
};
static STR IntToString(INT value) {
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
// So round up to allocate 3 output characters per byte, plus 1 for '-'.
@ -510,7 +514,7 @@ struct IntToStringT {
// then return the substr of what we ended up using.
STR outbuf(kOutputBufSize, 0);
bool is_neg = value < 0;
bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
// Even though is_neg will never be true when INT is parameterized as
// unsigned, even the presence of the unary operation causes a warning.
UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);

Просмотреть файл

@ -113,11 +113,10 @@ static CFStringRef STLStringToCFStringWithEncodingsT(
// Specify the byte ordering explicitly, otherwise CFString will be confused
// when strings don't carry BOMs, as they typically won't.
static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
#ifdef __BIG_ENDIAN__
static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16BE;
static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE;
#elif defined(__LITTLE_ENDIAN__)
static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16LE;
static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
#endif // __LITTLE_ENDIAN__

Просмотреть файл

@ -23,7 +23,7 @@ class JSAtom;
class JSFreeOp;
namespace js {
class StackFrame;
class InterpreterFrame;
class ScriptFrameIter;
}
@ -94,7 +94,7 @@ FormatStackDump(JSContext *cx, char *buf, bool showArgs, bool showLocals, bool s
# ifdef JS_DEBUG
JS_FRIEND_API(void) js_DumpValue(const JS::Value &val);
JS_FRIEND_API(void) js_DumpId(jsid id);
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, js::StackFrame *start = nullptr);
JS_FRIEND_API(void) js_DumpInterpreterFrame(JSContext *cx, js::InterpreterFrame *start = nullptr);
# endif
JS_FRIEND_API(void)

Просмотреть файл

@ -260,7 +260,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
unsigned staticLevel;
RootedValue thisv(cx);
if (evalType == DIRECT_EVAL) {
JS_ASSERT_IF(caller.isStackFrame(), !caller.asStackFrame()->runningInJit());
JS_ASSERT_IF(caller.isInterpreterFrame(), !caller.asInterpreterFrame()->runningInJit());
staticLevel = caller.script()->staticLevel() + 1;
// Direct calls to eval are supposed to see the caller's |this|. If we

Просмотреть файл

@ -211,6 +211,7 @@ CreateX4Class(JSContext *cx, Handle<GlobalObject*> global)
return nullptr;
x4->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
x4->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*proto));
// Link constructor to prototype and install properties.

Просмотреть файл

@ -608,6 +608,8 @@ ArrayMetaTypeDescr::create(JSContext *cx,
if (!prototypeObj)
return nullptr;
obj->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*prototypeObj));
if (!LinkConstructorAndPrototype(cx, obj, prototypeObj))
return nullptr;
@ -979,6 +981,8 @@ StructMetaTypeDescr::create(JSContext *cx,
if (!prototypeObj)
return nullptr;
descr->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*prototypeObj));
if (!LinkConstructorAndPrototype(cx, descr, prototypeObj))
return nullptr;

Просмотреть файл

@ -135,6 +135,14 @@ static T ConvertScalar(double d)
class TypeDescr : public JSObject
{
public:
// This is *intentionally* not defined so as to produce link
// errors if a is<FooTypeDescr>() etc goes wrong. Otherwise, the
// default implementation resolves this to a reference to
// FooTypeDescr::class_ which resolves to
// JSObject::class_. Debugging the resulting errors leads to much
// fun and rejoicing.
static const Class class_;
enum Kind {
Scalar = JS_TYPEREPR_SCALAR_KIND,
Reference = JS_TYPEREPR_REFERENCE_KIND,
@ -269,10 +277,22 @@ class ReferenceTypeDescr : public SimpleTypeDescr
macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
// Type descriptors whose instances are objects and hence which have
// an associated `prototype` property.
class ComplexTypeDescr : public SizedTypeDescr
{
public:
// Returns the prototype that instances of this type descriptor
// will have.
JSObject &instancePrototype() const {
return getReservedSlot(JS_DESCR_SLOT_PROTO).toObject();
}
};
/*
* Type descriptors `float32x4` and `int32x4`
*/
class X4TypeDescr : public SizedTypeDescr
class X4TypeDescr : public ComplexTypeDescr
{
public:
enum Type {
@ -346,6 +366,11 @@ class ArrayMetaTypeDescr : public JSObject
/*
* Type descriptor created by `new ArrayType(typeObj)`
*
* These have a prototype, and hence *could* be a subclass of
* `ComplexTypeDescr`, but it would require some reshuffling of the
* hierarchy, and it's not worth the trouble since they will be going
* away as part of bug 973238.
*/
class UnsizedArrayTypeDescr : public TypeDescr
{
@ -364,7 +389,7 @@ class UnsizedArrayTypeDescr : public TypeDescr
/*
* Type descriptor created by `unsizedArrayTypeObj.dimension()`
*/
class SizedArrayTypeDescr : public SizedTypeDescr
class SizedArrayTypeDescr : public ComplexTypeDescr
{
public:
static const Class class_;
@ -413,7 +438,8 @@ class StructMetaTypeDescr : public JSObject
static bool construct(JSContext *cx, unsigned argc, Value *vp);
};
class StructTypeDescr : public SizedTypeDescr {
class StructTypeDescr : public ComplexTypeDescr
{
public:
static const Class class_;
@ -873,13 +899,19 @@ IsSimpleTypeDescrClass(const Class* clasp)
clasp == &ReferenceTypeDescr::class_;
}
inline bool
IsComplexTypeDescrClass(const Class* clasp)
{
return clasp == &StructTypeDescr::class_ ||
clasp == &SizedArrayTypeDescr::class_ ||
clasp == &X4TypeDescr::class_;
}
inline bool
IsSizedTypeDescrClass(const Class* clasp)
{
return IsSimpleTypeDescrClass(clasp) ||
clasp == &StructTypeDescr::class_ ||
clasp == &SizedArrayTypeDescr::class_ ||
clasp == &X4TypeDescr::class_;
IsComplexTypeDescrClass(clasp);
}
inline bool
@ -908,6 +940,13 @@ JSObject::is<js::SizedTypeDescr>() const
return IsSizedTypeDescrClass(getClass());
}
template <>
inline bool
JSObject::is<js::ComplexTypeDescr>() const
{
return IsComplexTypeDescrClass(getClass());
}
template <>
inline bool
JSObject::is<js::TypeDescr>() const

Просмотреть файл

@ -945,18 +945,21 @@ function TypedArrayMap(a, b) {
// Warning: user exposed!
function TypedArrayMapPar(a, b) {
// Arguments: [depth], func
// Defer to the sequential variant for error cases or
// when not working with typed objects.
if (!IsObject(this) || !ObjectIsTypedObject(this))
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return callFunction(TypedArrayMap, this, a, b);
var thisType = TYPEDOBJ_TYPE_DESCR(this);
if (!TypeDescrIsArrayType(thisType))
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return callFunction(TypedArrayMap, this, a, b);
// Arguments: [depth], func
if (typeof a === "number" && typeof b === "function")
if (typeof a === "number" && IsCallable(b))
return MapTypedParImpl(this, a, thisType, b);
else if (typeof a === "function")
else if (IsCallable(a))
return MapTypedParImpl(this, 1, thisType, a);
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return callFunction(TypedArrayMap, this, a, b);
}
// Warning: user exposed!
@ -1017,6 +1020,20 @@ function TypedObjectArrayTypeBuildPar(a,b,c) {
// Warning: user exposed!
function TypedObjectArrayTypeFromPar(a,b,c) {
// Arguments: arrayLike, [depth], func
// Use the sequential version for error cases or when arrayLike is
// not a typed object.
if (!IsObject(this) || !ObjectIsTypeDescr(this) || !TypeDescrIsArrayType(this))
return callFunction(TypedObjectArrayTypeFrom, this, a, b, c);
if (!IsObject(a) || !ObjectIsTypedObject(a))
return callFunction(TypedObjectArrayTypeFrom, this, a, b, c);
// Detect whether an explicit depth is supplied.
if (typeof b === "number" && IsCallable(c))
return MapTypedParImpl(a, b, this, c);
if (IsCallable(b))
return MapTypedParImpl(a, 1, this, b);
return callFunction(TypedObjectArrayTypeFrom, this, a, b, c);
}
@ -1355,6 +1372,10 @@ function MapTypedParImpl(inArray, depth, outputType, func) {
"Map/From called on non-object or untyped input array.");
assert(TypeDescrIsArrayType(outputType),
"Map/From called on non array-type outputType");
assert(typeof depth === "number",
"Map/From called with non-numeric depth");
assert(IsCallable(func),
"Map/From called on something not callable");
var inArrayType = TypeOfTypedObject(inArray);
@ -1516,6 +1537,12 @@ function MapTypedParImplDepth1(inArray, inArrayType, outArrayType, func) {
outOffset += outGrainTypeSize;
}
// A transparent result type cannot contain references, and
// hence there is no way for a pointer to a thread-local object
// to escape.
if (outGrainTypeIsTransparent)
ClearThreadLocalArenas();
MARK_SLICE_DONE(slicesInfo, sliceId);
if (warmup)
return;

Просмотреть файл

@ -21,23 +21,24 @@
#define JS_DESCR_SLOT_TYPE_REPR 0 // Associated Type Representation
#define JS_DESCR_SLOT_ALIGNMENT 1 // Alignment in bytes
#define JS_DESCR_SLOT_SIZE 2 // Size in bytes, if sized, else 0
#define JS_DESCR_SLOT_PROTO 3 // Prototype for instances, if any
// Slots on scalars, references, and x4s
#define JS_DESCR_SLOT_TYPE 3 // Type code
#define JS_DESCR_SLOT_TYPE 4 // Type code
// Slots on all array descriptors
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 3
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 4
// Slots on sized array descriptors
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 4
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 5
// Slots on struct type objects
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 3
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 4
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 5
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 4
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 5
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 6
// Maximum number of slots for any descriptor
#define JS_DESCR_SLOTS 6
#define JS_DESCR_SLOTS 7
///////////////////////////////////////////////////////////////////////////
// Slots for type representation objects

Просмотреть файл

@ -1136,7 +1136,8 @@ if test "$GNU_CC"; then
AC_MSG_CHECKING([for --build-id option to ld])
_SAVE_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS -Wl,--build-id"
AC_TRY_LINK(,,AC_MSG_RESULT([yes]),
AC_TRY_LINK(,,AC_MSG_RESULT([yes])
[NSPR_LDFLAGS="$NSPR_LDFLAGS -Wl,--build-id"],
AC_MSG_RESULT([no])
LDFLAGS=$_SAVE_LDFLAGS)

Просмотреть файл

@ -37,6 +37,7 @@ class FreeOp;
namespace gc {
struct Arena;
struct ArenaList;
struct ArenaHeader;
struct Chunk;
@ -579,6 +580,8 @@ struct Arena
return address() + ArenaSize;
}
void setAsFullyUnused(AllocKind thingKind);
template <typename T>
bool finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize);
};
@ -801,6 +804,7 @@ struct Chunk
ArenaHeader *allocateArena(JS::Zone *zone, AllocKind kind);
void releaseArena(ArenaHeader *aheader);
void recycleArena(ArenaHeader *aheader, ArenaList &dest, AllocKind thingKind);
static Chunk *allocate(JSRuntime *rt);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше