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) { Android: function Android(aDetails, aBrowser) {
const ANDROID_VIEW_TEXT_CHANGED = 0x10; const ANDROID_VIEW_TEXT_CHANGED = 0x10;
const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000; const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
if (!this._bridge) if (!this.androidBridge) {
this._bridge = Cc['@mozilla.org/android/bridge;1'].getService(Ci.nsIAndroidBridge); return;
}
for each (let androidEvent in aDetails) { for each (let androidEvent in aDetails) {
androidEvent.type = 'Accessibility:Event'; androidEvent.type = 'Accessibility:Event';
@ -722,7 +734,7 @@ var Output = {
androidEvent.brailleOutput = this.brailleState.init(androidEvent.brailleOutput); androidEvent.brailleOutput = this.brailleState.init(androidEvent.brailleOutput);
break; 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']; 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.ContentControl = function ContentControl(aContentScope) {
this._contentScope = Cu.getWeakReference(aContentScope); this._contentScope = Cu.getWeakReference(aContentScope);
this._vcCache = new WeakMap(); this._vcCache = new WeakMap();
@ -31,16 +35,19 @@ this.ContentControl.prototype = {
messagesOfInterest: ['AccessFu:MoveCursor', messagesOfInterest: ['AccessFu:MoveCursor',
'AccessFu:ClearCursor', 'AccessFu:ClearCursor',
'AccessFu:MoveToPoint', '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(); let cs = this._contentScope.get();
for (let message of this.messagesOfInterest) { for (let message of this.messagesOfInterest) {
cs.addMessageListener(message, this); cs.addMessageListener(message, this);
} }
}, },
stop: function ContentControl_stop() { stop: function cc_stop() {
let cs = this._contentScope.get(); let cs = this._contentScope.get();
for (let message of this.messagesOfInterest) { for (let message of this.messagesOfInterest) {
cs.removeMessageListener(message, this); cs.removeMessageListener(message, this);
@ -59,29 +66,19 @@ this.ContentControl.prototype = {
return Utils.getVirtualCursor(this.document); return Utils.getVirtualCursor(this.document);
}, },
receiveMessage: function ContentControl_receiveMessage(aMessage) { receiveMessage: function cc_receiveMessage(aMessage) {
Logger.debug(() => { Logger.debug(() => {
return ['ContentControl.receiveMessage', return ['ContentControl.receiveMessage',
this.document.location.toString(), aMessage.name,
JSON.stringify(aMessage.json)]; JSON.stringify(aMessage.json)];
}); });
try { try {
switch (aMessage.name) { let func = this['handle' + aMessage.name.slice(9)]; // 'AccessFu:'.length
case 'AccessFu:MoveCursor': if (func) {
this.handleMove(aMessage); func.bind(this)(aMessage);
break; } else {
case 'AccessFu:ClearCursor': Logger.warning('ContentControl: Unhandled message:', aMessage.name);
this.handleClear(aMessage);
break;
case 'AccessFu:MoveToPoint':
this.handleMoveToPoint(aMessage);
break;
case 'AccessFu:AutoMove':
this.handleAutoMove(aMessage);
break;
default:
break;
} }
} catch (x) { } catch (x) {
Logger.logException( 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 origin = aMessage.json.origin;
let action = aMessage.json.action; let action = aMessage.json.action;
let vc = this.vc; 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 [x, y] = [aMessage.json.x, aMessage.json.y];
let rule = TraversalRules[aMessage.json.rule]; let rule = TraversalRules[aMessage.json.rule];
let vc = this.vc; let vc = this.vc;
@ -141,16 +138,169 @@ this.ContentControl.prototype = {
this.sendToChild(vc, aMessage, delta); this.sendToChild(vc, aMessage, delta);
}, },
handleClear: function ContentControl_handleClear(aMessage) { handleClearCursor: function cc_handleClearCursor(aMessage) {
this.sendToChild(this.vc, aMessage); this.sendToChild(this.vc, aMessage);
this.vc.position = null; this.vc.position = null;
}, },
handleAutoMove: function ContentControl_handleAutoMove(aMessage) { handleAutoMove: function cc_handleAutoMove(aMessage) {
this.autoMove(null, aMessage.json); 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; let acc = aAccessible || this.vc.position;
if (Utils.isAliveAndVisible(acc) && acc.role === Roles.INTERNAL_FRAME) { if (Utils.isAliveAndVisible(acc) && acc.role === Roles.INTERNAL_FRAME) {
let domNode = acc.DOMNode; let domNode = acc.DOMNode;
@ -167,9 +317,7 @@ this.ContentControl.prototype = {
return null; return null;
}, },
sendToChild: function ContentControl_sendToChild(aVirtualCursor, sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer) {
aMessage,
aReplacer) {
let mm = this.getChildCursor(aVirtualCursor.position); let mm = this.getChildCursor(aVirtualCursor.position);
if (!mm) { if (!mm) {
return false; return false;
@ -186,7 +334,7 @@ this.ContentControl.prototype = {
return true; return true;
}, },
sendToParent: function ContentControl_sendToParent(aMessage) { sendToParent: function cc_sendToParent(aMessage) {
// XXX: This is a silly way to make a deep copy // XXX: This is a silly way to make a deep copy
let newJSON = JSON.parse(JSON.stringify(aMessage.json)); let newJSON = JSON.parse(JSON.stringify(aMessage.json));
newJSON.origin = 'child'; newJSON.origin = 'child';
@ -205,7 +353,7 @@ this.ContentControl.prototype = {
* precedence over given anchor. * precedence over given anchor.
* - moveMethod: pivot move method to use, default is 'moveNext', * - 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; let win = this.window;
win.clearTimeout(this._autoMove); win.clearTimeout(this._autoMove);
@ -266,4 +414,4 @@ this.ContentControl.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
Ci.nsIMessageListener Ci.nsIMessageListener
]) ])
}; };

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

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

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

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

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

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

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

@ -5,10 +5,6 @@
let Ci = Components.interfaces; let Ci = Components.interfaces;
let Cu = Components.utils; 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'); Cu.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Logger', XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
'resource://gre/modules/accessibility/Utils.jsm'); 'resource://gre/modules/accessibility/Utils.jsm');
@ -68,86 +64,6 @@ function forwardToChild(aMessage, aListener, aVCPosition) {
return true; 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 activateContextMenu(aMessage) {
function sendContextMenuCoordinates(aAccessible) { function sendContextMenuCoordinates(aAccessible) {
let bounds = Utils.getBounds(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) { function presentCaretChange(aText, aOldOffset, aNewOffset) {
if (aOldOffset !== aNewOffset) { if (aOldOffset !== aNewOffset) {
let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset, let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset,
@ -282,12 +132,9 @@ addMessageListener(
if (m.json.buildApp) if (m.json.buildApp)
Utils.MozBuildApp = m.json.buildApp; Utils.MozBuildApp = m.json.buildApp;
addMessageListener('AccessFu:Activate', activateCurrent);
addMessageListener('AccessFu:ContextMenu', activateContextMenu); addMessageListener('AccessFu:ContextMenu', activateContextMenu);
addMessageListener('AccessFu:Scroll', scroll); addMessageListener('AccessFu:Scroll', scroll);
addMessageListener('AccessFu:AdjustRange', adjustRange); addMessageListener('AccessFu:AdjustRange', adjustRange);
addMessageListener('AccessFu:MoveCaret', moveCaret);
addMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
if (!eventManager) { if (!eventManager) {
eventManager = new EventManager(this); eventManager = new EventManager(this);
@ -307,11 +154,8 @@ addMessageListener(
function(m) { function(m) {
Logger.debug('AccessFu:Stop'); Logger.debug('AccessFu:Stop');
removeMessageListener('AccessFu:Activate', activateCurrent);
removeMessageListener('AccessFu:ContextMenu', activateContextMenu); removeMessageListener('AccessFu:ContextMenu', activateContextMenu);
removeMessageListener('AccessFu:Scroll', scroll); removeMessageListener('AccessFu:Scroll', scroll);
removeMessageListener('AccessFu:MoveCaret', moveCaret);
removeMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
eventManager.stop(); eventManager.stop();
contentControl.stop(); contentControl.stop();

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

@ -6,9 +6,11 @@ support-files =
output.js output.js
doc_traversal.html doc_traversal.html
doc_content_integration.html doc_content_integration.html
doc_content_text.html
[test_alive.html] [test_alive.html]
[test_content_integration.html] [test_content_integration.html]
[test_content_text.html]
[test_explicit_names.html] [test_explicit_names.html]
[test_landmarks.html] [test_landmarks.html]
[test_live_regions.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 () { this.setupMessageManager(this.mms[0], function () {
// Get child message managers and set them up // Get child message managers and set them up
var frames = currentTabDocument().querySelectorAll('iframe'); var frames = currentTabDocument().querySelectorAll('iframe');
if (frames.length === 0) {
self.pump();
return;
}
var toSetup = 0; var toSetup = 0;
for (var i = 0; i < frames.length; i++ ) { for (var i = 0; i < frames.length; i++ ) {
var mm = Utils.getMessageManager(frames[i]); var mm = Utils.getMessageManager(frames[i]);
@ -206,7 +211,8 @@ AccessFuContentTest.prototype = {
aMessageManager.addMessageListener('AccessFu:Present', this); aMessageManager.addMessageListener('AccessFu:Present', this);
aMessageManager.addMessageListener('AccessFu:Ready', function () { aMessageManager.addMessageListener('AccessFu:Ready', function () {
aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback); aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback);
aMessageManager.sendAsyncMessage('AccessFu:Start', { buildApp: 'browser' }); aMessageManager.sendAsyncMessage('AccessFu:Start',
{ buildApp: 'browser', androidSdkVersion: Utils.AndroidSdkVersion});
}); });
aMessageManager.loadFrameScript( aMessageManager.loadFrameScript(
@ -242,21 +248,46 @@ AccessFuContentTest.prototype = {
return; return;
} }
var expected = this.currentPair[1]; var expected = this.currentPair[1] || {};
var speech = this.extractUtterance(aMessage.json);
if (expected) { var android = this.extractAndroid(aMessage.json, expected.android);
if (expected.speak !== undefined) { if ((speech && expected.speak) || (android && expected.android)) {
var speech = this.extractUtterance(aMessage.json); if (expected.speak) {
if (!speech) { (SimpleTest[expected.speak_checkFunc] || is)(speech, expected.speak);
// Probably a visual highlight adjustment after a scroll.
return;
}
var checkFunc = SimpleTest[expected.speak_checkFunc] || is;
checkFunc(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) { 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; 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"); var iframe = doc.createElement("iframe");
iframe.mozbrowser = true; iframe.mozbrowser = true;
iframe.addEventListener("mozbrowserloadend", function () { iframe.addEventListener("mozbrowserloadend", function () {
var simpleMoveNext = { name: 'AccessFu:MoveCursor', var contentTest = new AccessFuContentTest(
json: { action: 'moveNext', [
rule: 'Simple', // Simple traversal forward
inputType: 'gesture', [ContentMessages.simpleMoveNext, {
origin: 'top' } 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', // Simple traversal backward
json: { action: 'movePrevious', [ContentMessages.simpleMovePrevious, {
rule: 'Simple', speak: 'many option checked check button such app'
inputType: 'gesture', }],
origin: 'top' } [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', // Moving to the absolute last item from an embedded document
json: { origin: 'top' } }; // 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', [ContentMessages.clearCursor, null], // Reset cursors
json: { action: 'moveLast',
rule: 'Simple',
inputType: 'gesture',
origin: 'top' }
};
var simpleMoveFirst = { name: 'AccessFu:MoveCursor', // Moving to the absolute first item from an embedded document
json: { action: 'moveFirst', // fails. Bug 972035.
rule: 'Simple', [ContentMessages.simpleMoveNext, {
inputType: 'gesture', speak: 'Phone status bar Traversal Rule test document'
origin: 'top' } }],
}; [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', // Reset cursors
json: { origin: 'top' } [ContentMessages.clearCursor, null],
};
function focusFunc(aSelector, aBlur) { // Move cursor with focus in outside document
return function (mm) { [ContentMessages.simpleMoveNext, {
mm.sendAsyncMessage( speak: 'Phone status bar Traversal Rule test document'
'AccessFuTest:Focus', { selector: aSelector, blur: aBlur }); }],
}; [ContentMessages.focusSelector('button#home', false), {
} speak: 'Home button'
}],
var contentTest = new AccessFuContentTest( // Blur button and reset cursor
[ [ContentMessages.focusSelector('button#home', true), null],
// Simple traversal forward [ContentMessages.clearCursor, null],
[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' }],
// Simple traversal backward // Set focus on element outside of embedded frame while
[simpleMovePrevious, // cursor is in frame
{ speak: 'many option checked check button such app' }], [ContentMessages.simpleMoveNext, {
[activateCurrent, speak: 'Phone status bar Traversal Rule test document'
{ speak: 'unchecked' }], }],
[null, [ContentMessages.simpleMoveNext, {
{ speak: 'unchecked', speak_checkFunc: 'todo_isnot' }], speak: 'wow heading level 1 such app'
[simpleMovePrevious, }],
{ speak: 'wow heading level 1' }], [ContentMessages.focusSelector('button#home', false), {
[simpleMovePrevious, speak: 'Home button'
{ speak: 'Phone status bar' }], }]
// Moving to the absolute last item from an embedded document fails. // Blur button and reset cursor
// Bug 972035. [ContentMessages.focusSelector('button#home', true), null],
[simpleMoveNext, [ContentMessages.clearCursor, null],
{ 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' }],
[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. // Open dialog in outer doc, while cursor is also in outer doc
// Bug 972035. [ContentMessages.simpleMoveNext, {
[simpleMoveNext, speak: 'Phone status bar Traversal Rule test document'
{ speak: 'Phone status bar Traversal Rule test document' }], }],
[simpleMoveNext, [doc.defaultView.showAlert, {
{ speak: 'wow heading level 1 such app' }], speak: 'This is an alert! heading level 1 dialog'
[simpleMoveNext, }],
{ speak: 'many option not checked check button' }],
[simpleMoveFirst,
{ speak: 'Phone status bar', speak_checkFunc: 'todo_is' }],
// Reset cursors [function() {
[clearCursor, null], doc.defaultView.hideAlert()
}, {
speak: 'wow heading level 1 such app'
}],
// Move cursor with focus in outside document [ContentMessages.clearCursor, null],
[simpleMoveNext,
{ speak: 'Phone status bar Traversal Rule test document' }],
[ focusFunc('button#home', false), { speak: 'Home button' }],
// Blur button and reset cursor // Open dialog in outer doc, while cursor is in inner frame
[focusFunc('button#home', true), null], [ContentMessages.simpleMoveNext, {
[clearCursor, null], 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 // XXX: Place cursor back where it was.
[simpleMoveNext, [doc.defaultView.hideAlert, {
{ speak: 'Phone status bar Traversal Rule test document' }], speak: 'many option not checked check button such app'
[simpleMoveNext, }],
{ speak: 'wow heading level 1 such app' }],
[focusFunc('button#home', false), { speak: 'Home button' }]
// Blur button and reset cursor [ContentMessages.clearCursor, null],
[focusFunc('button#home', true), null],
[clearCursor, null],
// XXX: Set focus on iframe itself. // Open dialog, then focus on something when closing
// XXX: Set focus on element in iframe when cursor is outside of it. [ContentMessages.simpleMoveNext, {
// XXX: Set focus on element in iframe when cursor is in iframe. 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 [function() {
[simpleMoveNext, doc.defaultView.hideAlert();
{ speak: 'Phone status bar Traversal Rule test document' }], doc.querySelector('button#home').focus();
[doc.defaultView.showAlert, }, {
{ speak: 'This is an alert! heading level 1 dialog' }], speak: 'Home button Traversal Rule test document'
}]
[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' }]
]);
contentTest.start(function () { contentTest.start(function () {
closeBrowserWindow(); 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"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

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

@ -17,7 +17,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/> <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>

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

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

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

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

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

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

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

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

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

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

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

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

@ -17,7 +17,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/> <project name="moztt" path="external/moztt" remote="b2g" revision="cb16958e41105d7c551d9941f522db97b8312538"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>

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

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/> <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 // Delete HTTP cache v2 data of users that didn't opt-in manually
pref("browser.cache.auto_delete_cache_version", 1); 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(); 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(() => { SessionStore.promiseInitialized.then(() => {
// Bail out if the window has been closed in the meantime. // Bail out if the window has been closed in the meantime.
if (window.closed) { if (window.closed) {

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

@ -61,4 +61,5 @@ run-if = crashreporter
[browser_pluginplaypreview2.js] [browser_pluginplaypreview2.js]
[browser_pluginCrashCommentAndURL.js] [browser_pluginCrashCommentAndURL.js]
run-if = crashreporter run-if = crashreporter
skip-if = os == "linux" && debug # bug 933680
[browser_plugins_added_dynamically.js] [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 += [ PARALLEL_DIRS += [
'base', 'base',
'components', 'components',
'experiments',
'fuel', 'fuel',
'locales', 'locales',
'modules', 'modules',

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

@ -28,9 +28,11 @@ AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [
esac esac
fi 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 \ 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" MOZ_FRAMEPTR_FLAGS="$MOZ_ENABLE_FRAME_PTR"
else else
MOZ_FRAMEPTR_FLAGS="$MOZ_DISABLE_FRAME_PTR" MOZ_FRAMEPTR_FLAGS="$MOZ_DISABLE_FRAME_PTR"

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

@ -8933,9 +8933,9 @@ if test "$MOZ_TREE_FREETYPE"; then
export CXXFLAGS="$CXXFLAGS $MOZ_DEBUG_FLAGS" export CXXFLAGS="$CXXFLAGS $MOZ_DEBUG_FLAGS"
export LDFLAGS="$LDFLAGS $MOZ_DEBUG_LDFLAGS" export LDFLAGS="$LDFLAGS $MOZ_DEBUG_LDFLAGS"
export LIBPNG_CFLAGS="$MOZ_PNG_CFLAGS" 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" 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 if ! test -e modules; then
mkdir modules mkdir modules

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

@ -5473,6 +5473,14 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
return true; 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 nsresult
nsDocument::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName) nsDocument::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
{ {

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

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

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

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

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

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

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

@ -7,7 +7,6 @@
#define MOZILLA_DOMSVGPOINT_H__ #define MOZILLA_DOMSVGPOINT_H__
#include "DOMSVGPointList.h" #include "DOMSVGPointList.h"
#include "gfxPoint.h"
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsDebug.h" #include "nsDebug.h"
@ -87,15 +86,6 @@ public:
"DOMSVGPoint coords are not finite"); "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 // WebIDL
virtual float X(); virtual float X();

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

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

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

@ -821,7 +821,7 @@ SVGPathData::ToPathForLengthOrPositionMeasuring() const
} }
static double static double
AngleOfVector(const gfxPoint& aVector) AngleOfVector(const Point& aVector)
{ {
// C99 says about atan2 "A domain error may occur if both arguments are // C99 says about atan2 "A domain error may occur if both arguments are
// zero" and "On a domain error, the function returns an implementation- // 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. // 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: // 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 static float
AngleOfVectorF(const gfxPoint& aVector) AngleOfVectorF(const Point& aVector)
{ {
return static_cast<float>(AngleOfVector(aVector)); return static_cast<float>(AngleOfVector(aVector));
} }
@ -846,14 +846,14 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
// places, and repeat multiple times consecutively. // places, and repeat multiple times consecutively.
// info on current [sub]path (reset every M command): // 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; float pathStartAngle = 0.0f;
// info on previous segment: // info on previous segment:
uint16_t prevSegType = PATHSEG_UNKNOWN; uint16_t prevSegType = PATHSEG_UNKNOWN;
gfxPoint prevSegEnd(0.0, 0.0); Point prevSegEnd(0.0, 0.0);
float prevSegEndAngle = 0.0f; 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; uint32_t i = 0;
while (i < mData.Length()) { while (i < mData.Length()) {
@ -861,8 +861,8 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
// info on current segment: // info on current segment:
uint16_t segType = uint16_t segType =
SVGPathSegUtils::DecodeType(mData[i++]); // advances i to args SVGPathSegUtils::DecodeType(mData[i++]); // advances i to args
gfxPoint &segStart = prevSegEnd; Point& segStart = prevSegEnd;
gfxPoint segEnd; Point segEnd;
float segStartAngle, segEndAngle; float segStartAngle, segEndAngle;
switch (segType) // to find segStartAngle, segEnd and 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_ABS:
case PATHSEG_MOVETO_REL: case PATHSEG_MOVETO_REL:
if (segType == PATHSEG_MOVETO_ABS) { if (segType == PATHSEG_MOVETO_ABS) {
segEnd = gfxPoint(mData[i], mData[i+1]); segEnd = Point(mData[i], mData[i+1]);
} else { } else {
segEnd = segStart + gfxPoint(mData[i], mData[i+1]); segEnd = segStart + Point(mData[i], mData[i+1]);
} }
pathStart = segEnd; pathStart = segEnd;
// If authors are going to specify multiple consecutive moveto commands // 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_ABS:
case PATHSEG_LINETO_REL: case PATHSEG_LINETO_REL:
if (segType == PATHSEG_LINETO_ABS) { if (segType == PATHSEG_LINETO_ABS) {
segEnd = gfxPoint(mData[i], mData[i+1]); segEnd = Point(mData[i], mData[i+1]);
} else { } else {
segEnd = segStart + gfxPoint(mData[i], mData[i+1]); segEnd = segStart + Point(mData[i], mData[i+1]);
} }
segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart); segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
i += 2; i += 2;
@ -900,15 +900,15 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_CUBIC_ABS: case PATHSEG_CURVETO_CUBIC_ABS:
case PATHSEG_CURVETO_CUBIC_REL: case PATHSEG_CURVETO_CUBIC_REL:
{ {
gfxPoint cp1, cp2; // control points Point cp1, cp2; // control points
if (segType == PATHSEG_CURVETO_CUBIC_ABS) { if (segType == PATHSEG_CURVETO_CUBIC_ABS) {
cp1 = gfxPoint(mData[i], mData[i+1]); cp1 = Point(mData[i], mData[i+1]);
cp2 = gfxPoint(mData[i+2], mData[i+3]); cp2 = Point(mData[i+2], mData[i+3]);
segEnd = gfxPoint(mData[i+4], mData[i+5]); segEnd = Point(mData[i+4], mData[i+5]);
} else { } else {
cp1 = segStart + gfxPoint(mData[i], mData[i+1]); cp1 = segStart + Point(mData[i], mData[i+1]);
cp2 = segStart + gfxPoint(mData[i+2], mData[i+3]); cp2 = segStart + Point(mData[i+2], mData[i+3]);
segEnd = segStart + gfxPoint(mData[i+4], mData[i+5]); segEnd = segStart + Point(mData[i+4], mData[i+5]);
} }
prevCP = cp2; prevCP = cp2;
if (cp1 == segStart) { if (cp1 == segStart) {
@ -926,13 +926,13 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_QUADRATIC_ABS: case PATHSEG_CURVETO_QUADRATIC_ABS:
case PATHSEG_CURVETO_QUADRATIC_REL: case PATHSEG_CURVETO_QUADRATIC_REL:
{ {
gfxPoint cp1, cp2; // control points Point cp1, cp2; // control points
if (segType == PATHSEG_CURVETO_QUADRATIC_ABS) { if (segType == PATHSEG_CURVETO_QUADRATIC_ABS) {
cp1 = gfxPoint(mData[i], mData[i+1]); cp1 = Point(mData[i], mData[i+1]);
segEnd = gfxPoint(mData[i+2], mData[i+3]); segEnd = Point(mData[i+2], mData[i+3]);
} else { } else {
cp1 = segStart + gfxPoint(mData[i], mData[i+1]); cp1 = segStart + Point(mData[i], mData[i+1]);
segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]); segEnd = segStart + Point(mData[i+2], mData[i+3]);
} }
prevCP = cp1; prevCP = cp1;
segStartAngle = AngleOfVectorF(cp1 - segStart); segStartAngle = AngleOfVectorF(cp1 - segStart);
@ -950,9 +950,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
bool largeArcFlag = mData[i+3] != 0.0f; bool largeArcFlag = mData[i+3] != 0.0f;
bool sweepFlag = mData[i+4] != 0.0f; bool sweepFlag = mData[i+4] != 0.0f;
if (segType == PATHSEG_ARC_ABS) { if (segType == PATHSEG_ARC_ABS) {
segEnd = gfxPoint(mData[i+5], mData[i+6]); segEnd = Point(mData[i+5], mData[i+6]);
} else { } 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: // 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 cyp = -root * ry * x1p / rx;
double theta, delta; double theta, delta;
theta = AngleOfVector(gfxPoint((x1p-cxp)/rx, (y1p-cyp)/ry)); // F.6.5.5 theta = AngleOfVector(Point((x1p-cxp)/rx, (y1p-cyp)/ry)); // F.6.5.5
delta = AngleOfVector(gfxPoint((-x1p-cxp)/rx, (-y1p-cyp)/ry)) - // F.6.5.6 delta = AngleOfVector(Point((-x1p-cxp)/rx, (-y1p-cyp)/ry)) - // F.6.5.6
theta; theta;
if (!sweepFlag && delta > 0) if (!sweepFlag && delta > 0)
delta -= 2.0 * M_PI; delta -= 2.0 * M_PI;
@ -1047,9 +1047,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_LINETO_HORIZONTAL_ABS: case PATHSEG_LINETO_HORIZONTAL_ABS:
case PATHSEG_LINETO_HORIZONTAL_REL: case PATHSEG_LINETO_HORIZONTAL_REL:
if (segType == PATHSEG_LINETO_HORIZONTAL_ABS) { if (segType == PATHSEG_LINETO_HORIZONTAL_ABS) {
segEnd = gfxPoint(mData[i++], segStart.y); segEnd = Point(mData[i++], segStart.y);
} else { } else {
segEnd = segStart + gfxPoint(mData[i++], 0.0f); segEnd = segStart + Point(mData[i++], 0.0f);
} }
segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart); segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
break; break;
@ -1057,9 +1057,9 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_LINETO_VERTICAL_ABS: case PATHSEG_LINETO_VERTICAL_ABS:
case PATHSEG_LINETO_VERTICAL_REL: case PATHSEG_LINETO_VERTICAL_REL:
if (segType == PATHSEG_LINETO_VERTICAL_ABS) { if (segType == PATHSEG_LINETO_VERTICAL_ABS) {
segEnd = gfxPoint(segStart.x, mData[i++]); segEnd = Point(segStart.x, mData[i++]);
} else { } else {
segEnd = segStart + gfxPoint(0.0f, mData[i++]); segEnd = segStart + Point(0.0f, mData[i++]);
} }
segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart); segStartAngle = segEndAngle = AngleOfVectorF(segEnd - segStart);
break; break;
@ -1067,15 +1067,15 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
case PATHSEG_CURVETO_CUBIC_SMOOTH_REL: case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
{ {
gfxPoint cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? Point cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ?
segStart * 2 - prevCP : segStart; segStart * 2 - prevCP : segStart;
gfxPoint cp2; Point cp2;
if (segType == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS) { if (segType == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS) {
cp2 = gfxPoint(mData[i], mData[i+1]); cp2 = Point(mData[i], mData[i+1]);
segEnd = gfxPoint(mData[i+2], mData[i+3]); segEnd = Point(mData[i+2], mData[i+3]);
} else { } else {
cp2 = segStart + gfxPoint(mData[i], mData[i+1]); cp2 = segStart + Point(mData[i], mData[i+1]);
segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]); segEnd = segStart + Point(mData[i+2], mData[i+3]);
} }
prevCP = cp2; prevCP = cp2;
if (cp1 == segStart) { if (cp1 == segStart) {
@ -1093,13 +1093,13 @@ SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark> *aMarks) const
case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
{ {
gfxPoint cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? Point cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ?
segStart * 2 - prevCP : segStart; segStart * 2 - prevCP : segStart;
gfxPoint cp2; Point cp2;
if (segType == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS) { if (segType == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS) {
segEnd = gfxPoint(mData[i], mData[i+1]); segEnd = Point(mData[i], mData[i+1]);
} else { } else {
segEnd = segStart + gfxPoint(mData[i], mData[i+1]); segEnd = segStart + Point(mData[i], mData[i+1]);
} }
prevCP = cp1; prevCP = cp1;
segStartAngle = AngleOfVectorF(cp1 - segStart); segStartAngle = AngleOfVectorF(cp1 - segStart);

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

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

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

@ -82,7 +82,7 @@ public:
* length (as provided by the <path> element's 'pathLength' attribute). This * length (as provided by the <path> element's 'pathLength' attribute). This
* is used to scale stroke dashing, and to scale offsets along a textPath. * is used to scale stroke dashing, and to scale offsets along a textPath.
*/ */
gfxFloat GetPathLengthScale(PathLengthScaleForType aFor); float GetPathLengthScale(PathLengthScaleForType aFor);
// WebIDL // WebIDL
already_AddRefed<SVGAnimatedNumber> PathLength(); 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; aLeft[3].y = aRight[0].y = (aLeft[2].y + aRight[1].y) / 2;
} }
static gfxFloat static float
CalcBezLengthHelper(const Point* aCurve, uint32_t aNumPts, CalcBezLengthHelper(const Point* aCurve, uint32_t aNumPts,
uint32_t aRecursionCount, uint32_t aRecursionCount,
void (*aSplit)(const Point*, Point*, Point*)) void (*aSplit)(const Point*, Point*, Point*))
{ {
Point left[4]; Point left[4];
Point right[4]; Point right[4];
gfxFloat length = 0, dist; float length = 0, dist;
for (uint32_t i = 0; i < aNumPts - 1; i++) { for (uint32_t i = 0; i < aNumPts - 1; i++) {
length += CalcDistanceBetweenPoints(aCurve[i], aCurve[i+1]); length += CalcDistanceBetweenPoints(aCurve[i], aCurve[i+1]);
} }
@ -153,7 +153,7 @@ CalcBezLengthHelper(const Point* aCurve, uint32_t aNumPts,
return length; return length;
} }
static inline gfxFloat static inline float
CalcLengthOfCubicBezier(const Point& aPos, const Point &aCP1, CalcLengthOfCubicBezier(const Point& aPos, const Point &aCP1,
const Point& aCP2, const Point &aTo) const Point& aCP2, const Point &aTo)
{ {
@ -161,7 +161,7 @@ CalcLengthOfCubicBezier(const Point& aPos, const Point &aCP1,
return CalcBezLengthHelper(curve, 4, 0, SplitCubicBezier); return CalcBezLengthHelper(curve, 4, 0, SplitCubicBezier);
} }
static inline gfxFloat static inline float
CalcLengthOfQuadraticBezier(const Point& aPos, const Point& aCP, CalcLengthOfQuadraticBezier(const Point& aPos, const Point& aCP,
const Point& aTo) const Point& aTo)
{ {

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

@ -73,3 +73,10 @@ if CONFIG['SOLARIS_SUNPRO_CC']:
if CONFIG['OS_ARCH'] == 'WINNT': if CONFIG['OS_ARCH'] == 'WINNT':
RCFILE = 'sqlite.rc' RCFILE = 'sqlite.rc'
RESFILE = 'sqlite.res' 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__(); __delete__();
ReplyKeyEvent(WidgetKeyboardEvent event);
child: child:
/** /**
* Notify the remote browser that it has been Show()n on this * 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; mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
} }
if (localEvent.mFlags.mWantReplyFromContentProcess) {
SendReplyKeyEvent(localEvent);
}
return true; return true;
} }

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

@ -1192,6 +1192,28 @@ TabParent::GetChildProcessOffset()
pt, targetFrame->PresContext()->AppUnitsPerDevPixel())); 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. * Try to answer query event using cached text.
* *

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

@ -114,6 +114,7 @@ public:
virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE; virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE;
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) 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 RecvPRenderFrameConstructor(PRenderFrameParent* actor) MOZ_OVERRIDE;
virtual bool RecvInitRenderFrame(PRenderFrameParent* aFrame, virtual bool RecvInitRenderFrame(PRenderFrameParent* aFrame,
ScrollingBehavior* scrolling, ScrollingBehavior* scrolling,

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

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

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

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

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

@ -529,42 +529,7 @@ TelephonyProvider.prototype = {
return; return;
} }
let parentId = this._currentCalls[aClientId][aCallIndex].parentId; this._getClient(aClientId).sendWorkerMessage("holdCall", { callIndex: aCallIndex });
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));
}, },
resumeCall: function(aClientId, aCallIndex) { resumeCall: function(aClientId, aCallIndex) {
@ -575,43 +540,7 @@ TelephonyProvider.prototype = {
return; return;
} }
let parentId = this._currentCalls[aClientId][aCallIndex].parentId; this._getClient(aClientId).sendWorkerMessage("resumeCall", { callIndex: aCallIndex });
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));
}, },
conferenceCall: function(aClientId) { conferenceCall: function(aClientId) {

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

@ -20,8 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=850517
sb.win = window; sb.win = window;
sb.childA = ifrA.contentWindow; sb.childA = ifrA.contentWindow;
sb.childB = ifrB.contentWindow; sb.childB = ifrB.contentWindow;
sb.is = is; sb.is = SpecialPowers.wrap(is);
sb.ok = ok; sb.ok = SpecialPowers.wrap(ok);
is(window.theoneandonly.frameElement, ifrA, "Named child resolution works"); is(window.theoneandonly.frameElement, ifrA, "Named child resolution works");
SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childA, "Named child resolution works via Xray");', sb); SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childA, "Named child resolution works via Xray");', sb);
ifrA.removeAttribute('name'); 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"); is(evt.data, 'dosetup', "message from modal window is correct");
var win = SpecialPowers.wrap(evt.source); var win = SpecialPowers.wrap(evt.source);
win.wrappedJSObject.SpecialPowers = SpecialPowers; win.wrappedJSObject.SpecialPowers = SpecialPowers;
win.wrappedJSObject.is = is; win.wrappedJSObject.is = SpecialPowers.wrap(is);
win.wrappedJSObject.ok = ok; win.wrappedJSObject.ok = SpecialPowers.wrap(ok);
win.wrappedJSObject.go(); 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 //http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register
partial interface Document { partial interface Document {
[Throws, Pref="dom.webcomponents.enabled"] [Throws, Func="nsDocument::IsRegisterElementEnabled"]
object registerElement(DOMString name, optional ElementRegistrationOptions options); object registerElement(DOMString name, optional ElementRegistrationOptions options);
}; };

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

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

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

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

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

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

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

@ -26,6 +26,7 @@
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/TextEvents.h" #include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "nsEventStateManager.h" #include "nsEventStateManager.h"
#include "nsIEditor.h" #include "nsIEditor.h"
#include "nsIHTMLEditor.h" #include "nsIHTMLEditor.h"
@ -276,24 +277,23 @@ nsXBLWindowKeyHandler::WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventTy
nsresult rv = EnsureHandlers(); nsresult rv = EnsureHandlers();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Element> el = GetElement(); bool isDisabled;
nsCOMPtr<Element> el = GetElement(&isDisabled);
if (!el) { if (!el) {
if (mUserHandler) { if (mUserHandler) {
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler); WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler, true);
aKeyEvent->GetDefaultPrevented(&prevent); aKeyEvent->GetDefaultPrevented(&prevent);
if (prevent) if (prevent)
return NS_OK; // Handled by the user bindings. Our work here is done. return NS_OK; // Handled by the user bindings. Our work here is done.
} }
} }
nsCOMPtr<nsIContent> content = do_QueryInterface(el);
// skip keysets that are disabled // skip keysets that are disabled
if (content && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, if (el && isDisabled) {
nsGkAtoms::_true, eCaseMatters)) {
return NS_OK; return NS_OK;
} }
WalkHandlersInternal(aKeyEvent, aEventType, mHandler); WalkHandlersInternal(aKeyEvent, aEventType, mHandler, true);
return NS_OK; return NS_OK;
} }
@ -304,20 +304,50 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDOMEvent* aEvent)
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent)); nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent));
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG); 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; nsAutoString eventType;
aEvent->GetType(eventType); aEvent->GetType(eventType);
nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(eventType); nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(eventType);
NS_ENSURE_TRUE(eventTypeAtom, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(eventTypeAtom, NS_ERROR_OUT_OF_MEMORY);
if (!mWeakPtrForElement) { return WalkHandlers(keyEvent, eventTypeAtom);
nsCOMPtr<mozilla::dom::Element> originalTarget = }
do_QueryInterface(aEvent->GetInternalNSEvent()->originalTarget);
if (nsEventStateManager::IsRemoteTarget(originalTarget)) { void
return NS_OK; 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 // WalkHandlersInternal and WalkHandlersAndExecute
// //
// Given a particular DOM event and a pointer to the first handler in the list, // 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 // scan through the list to find something to handle the event. If aExecute = true,
// so. // 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, nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
nsIAtom* aEventType, nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler) nsXBLPrototypeHandler* aHandler,
bool aExecute)
{ {
nsAutoTArray<nsShortcutCandidate, 10> accessKeys; nsAutoTArray<nsShortcutCandidate, 10> accessKeys;
nsContentUtils::GetAccelKeyCandidates(aKeyEvent, accessKeys); nsContentUtils::GetAccelKeyCandidates(aKeyEvent, accessKeys);
if (accessKeys.IsEmpty()) { if (accessKeys.IsEmpty()) {
WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, 0, false); return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
return NS_OK; 0, false, aExecute);
} }
for (uint32_t i = 0; i < accessKeys.Length(); ++i) { for (uint32_t i = 0; i < accessKeys.Length(); ++i) {
nsShortcutCandidate &key = accessKeys[i]; nsShortcutCandidate &key = accessKeys[i];
if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
key.mCharCode, key.mIgnoreShift)) key.mCharCode, key.mIgnoreShift, aExecute))
return NS_OK; return true;
} }
return NS_OK; return false;
} }
bool bool
@ -421,7 +453,8 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
nsIAtom* aEventType, nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler, nsXBLPrototypeHandler* aHandler,
uint32_t aCharCode, uint32_t aCharCode,
bool aIgnoreShiftKey) bool aIgnoreShiftKey,
bool aExecute)
{ {
nsresult rv; nsresult rv;
@ -491,6 +524,10 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
piTarget = mTarget; piTarget = mTarget;
} }
if (!aExecute) {
return true;
}
rv = currHandler->ExecuteHandler(piTarget, aKeyEvent); rv = currHandler->ExecuteHandler(piTarget, aKeyEvent);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
return true; return true;
@ -500,10 +537,38 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
return false; 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> already_AddRefed<Element>
nsXBLWindowKeyHandler::GetElement() nsXBLWindowKeyHandler::GetElement(bool* aIsDisabled)
{ {
nsCOMPtr<Element> element = do_QueryReferent(mWeakPtrForElement); nsCOMPtr<Element> element = do_QueryReferent(mWeakPtrForElement);
if (element && aIsDisabled) {
*aIsDisabled = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
nsGkAtoms::_true, eCaseMatters);
}
return element.forget(); return element.forget();
} }

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

@ -35,14 +35,23 @@ protected:
nsresult WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType); nsresult WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType);
// walk the handlers, looking for one to handle the event // walk the handlers, looking for one to handle the event
nsresult WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent, bool WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
nsIAtom* aEventType, nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler); 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, bool WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler, nsXBLPrototypeHandler* aHandler,
uint32_t aCharCode, bool aIgnoreShiftKey); 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 // lazily load the handlers. Overridden to handle being attached
// to a particular element rather than the document // to a particular element rather than the document
@ -57,8 +66,10 @@ protected:
bool IsHTMLEditableFieldFocused(); bool IsHTMLEditableFieldFocused();
// Returns the element which was passed as a parameter to the constructor, // Returns the element which was passed as a parameter to the constructor,
// unless the element has been removed from the document. // unless the element has been removed from the document. Optionally returns
already_AddRefed<mozilla::dom::Element> GetElement(); // 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. // Using weak pointer to the DOM Element.
nsWeakPtr mWeakPtrForElement; nsWeakPtr mWeakPtrForElement;
mozilla::dom::EventTarget* mTarget; // weak ref mozilla::dom::EventTarget* mTarget; // weak ref

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

@ -68,5 +68,39 @@ Matrix::NudgeToIntegers()
NudgeToInteger(&_32); 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(); 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 // Apply a scale to this matrix. This scale will be applied -before- the
// existing transformation of the matrix. // existing transformation of the matrix.
Matrix4x4 &Scale(Float aX, Float aY, Float aZ) Matrix4x4 &Scale(Float aX, Float aY, Float aZ)

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

@ -10,6 +10,7 @@
#include "Types.h" #include "Types.h"
#include "BasePoint.h" #include "BasePoint.h"
#include "BasePoint3D.h" #include "BasePoint3D.h"
#include "BasePoint4D.h"
#include "BaseSize.h" #include "BaseSize.h"
#include <cmath> #include <cmath>
@ -92,6 +93,27 @@ struct Point3DTyped :
}; };
typedef Point3DTyped<UnknownUnits> Point3D; 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> template<class units>
struct IntSizeTyped : struct IntSizeTyped :
public BaseSize< int32_t, IntSizeTyped<units> >, public BaseSize< int32_t, IntSizeTyped<units> >,

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

@ -82,24 +82,14 @@ TextureClientX11::UpdateSurface(gfxASurface* aSurface)
{ {
MOZ_ASSERT(IsValid()); MOZ_ASSERT(IsValid());
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) { RefPtr<DrawTarget> dt = GetAsDrawTarget();
RefPtr<DrawTarget> dt = GetAsDrawTarget(); if (!dt) {
if (!dt) { return false;
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<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
dt->CopySurface(source, IntRect(IntPoint(), GetSize()), IntPoint());
return true; return true;
} }

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

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

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

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

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

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

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

@ -248,29 +248,8 @@ DisableGralloc(SurfaceFormat aFormat)
if (aFormat == gfx::SurfaceFormat::A8) { if (aFormat == gfx::SurfaceFormat::A8) {
return true; 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; return false;
#else
return false;
#endif
} }
#endif #endif
@ -678,25 +657,13 @@ BufferTextureClient::UpdateSurface(gfxASurface* aSurface)
return false; return false;
} }
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) { RefPtr<DrawTarget> dt = GetAsDrawTarget();
RefPtr<DrawTarget> dt = GetAsDrawTarget(); RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
dt->CopySurface(source, IntRect(IntPoint(), serializer.GetSize()), IntPoint()); dt->CopySurface(source, IntRect(IntPoint(), serializer.GetSize()), IntPoint());
// XXX - if the Moz2D backend is D2D, we would be much better off memcpying // 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 // the content of the surface directly because with D2D, GetAsDrawTarget is
// very expensive. // 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));
}
if (TextureRequiresLocking(mFlags) && !ImplementsLocking()) { if (TextureRequiresLocking(mFlags) && !ImplementsLocking()) {
// We don't have support for proper locking yet, so we'll // 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"); mTimer = do_CreateInstance("@mozilla.org/timer;1");
} }
TextureClientPool::~TextureClientPool()
{
mTimer->Cancel();
}
TemporaryRef<TextureClient> TemporaryRef<TextureClient>
TextureClientPool::GetTextureClient() TextureClientPool::GetTextureClient()
{ {

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

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

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

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

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

@ -408,14 +408,6 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
FillTexturesBlackWhite(aRegion, visibleRect.TopLeft()); 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 { } else {
destinationSurface = mD2DSurface; destinationSurface = mD2DSurface;
} }
@ -465,18 +457,7 @@ ThebesLayerD3D10::CreateNewTextures(const gfx::IntSize &aSize, SurfaceMode aMode
NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10."); NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
} }
if (!gfxPlatform::GetPlatform()->SupportsAzureContent()) { mDrawTarget = nullptr;
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;
}
} }
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA && !mTextureOnWhite) { 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."); NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
} }
if (!gfxPlatform::GetPlatform()->SupportsAzureContent()) { mDrawTarget = nullptr;
mD2DSurfaceOnWhite = new gfxD2DSurface(mTextureOnWhite, gfxContentType::COLOR);
if (!mD2DSurfaceOnWhite || mD2DSurfaceOnWhite->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurfaceOnWhite = nullptr;
return;
}
} else {
mDrawTarget = nullptr;
}
} }
if (gfxPlatform::GetPlatform()->SupportsAzureContent() && !mDrawTarget) { if (!mDrawTarget) {
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
mDrawTarget = Factory::CreateDualDrawTargetForD3D10Textures(mTexture, mTextureOnWhite, SurfaceFormat::B8G8R8X8); mDrawTarget = Factory::CreateDualDrawTargetForD3D10Textures(mTexture, mTextureOnWhite, SurfaceFormat::B8G8R8X8);
} else { } else {

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

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

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

@ -17,6 +17,7 @@
#include "mozilla/layers/LayersMessages.h" // for ShmemSection #include "mozilla/layers/LayersMessages.h" // for ShmemSection
#include "LayersTypes.h" #include "LayersTypes.h"
#include <vector> #include <vector>
#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
/* /*
* FIXME [bjacob] *** PURE CRAZYNESS WARNING *** * 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 * These methods should be only called in the ipdl implementor's thread, unless
* specified otherwise in the implementing class. * specified otherwise in the implementing class.
*/ */
class ISurfaceAllocator : public AtomicRefCounted<ISurfaceAllocator> class ISurfaceAllocator : public AtomicRefCountedWithFinalize<ISurfaceAllocator>
{ {
public: public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator) MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
ISurfaceAllocator() {} ISurfaceAllocator() {}
void Finalize();
/** /**
* Returns the type of backend that is used off the main thread. * 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 * 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. // This is used to implement an extremely simple & naive heap allocator.
std::vector<mozilla::ipc::Shmem> mUsedShmems; std::vector<mozilla::ipc::Shmem> mUsedShmems;
friend class detail::RefCounted<ISurfaceAllocator, detail::AtomicRefCount>; friend class AtomicRefCountedWithFinalize<ISurfaceAllocator>;
}; };
class GfxMemoryImageReporter MOZ_FINAL : public nsIMemoryReporter class GfxMemoryImageReporter MOZ_FINAL : public nsIMemoryReporter

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

@ -423,29 +423,6 @@ ISurfaceAllocator::PlatformAllocSurfaceDescriptor(const gfx::IntSize& aSize,
SurfaceDescriptor* aBuffer) 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 // Some GL implementations fail to render gralloc textures with
// width < 64. There's not much point in gralloc'ing buffers that // width < 64. There's not much point in gralloc'ing buffers that
// small anyway, so fall back on shared memory plus a texture // small anyway, so fall back on shared memory plus a texture

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

@ -169,18 +169,10 @@ GrallocTextureClientOGL::UpdateSurface(gfxASurface* aSurface)
return false; return false;
} }
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) { RefPtr<DrawTarget> dt = GetAsDrawTarget();
RefPtr<DrawTarget> dt = GetAsDrawTarget(); RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
dt->CopySurface(source, IntRect(IntPoint(), GetSize()), IntPoint()); 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));
}
return true; return true;
} }

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

@ -362,17 +362,10 @@ gfxASurface::CopyToARGB32ImageSurface()
nsRefPtr<gfxImageSurface> imgSurface = nsRefPtr<gfxImageSurface> imgSurface =
new gfxImageSurface(size, gfxImageFormat::ARGB32); new gfxImageSurface(size, gfxImageFormat::ARGB32);
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) { RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(imgSurface, IntSize(size.width, size.height));
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(imgSurface, IntSize(size.width, size.height)); RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, this);
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, this);
dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint()); 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();
}
return imgSurface.forget(); return imgSurface.forget();
} }

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

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

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

@ -256,20 +256,6 @@ public:
CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize, CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize,
int32_t aStride, mozilla::gfx::SurfaceFormat aFormat); 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 * 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 * 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; mozilla::RefPtr<mozilla::gfx::DrawTarget> target;
nsRefPtr<gfxContext> ctx; nsRefPtr<gfxContext> ctx;
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) { target = gfxPlatform::GetPlatform()->
target = gfxPlatform::GetPlatform()-> CreateOffscreenContentDrawTarget(gfx::IntSize(mClip.width, mClip.height),
CreateOffscreenContentDrawTarget(gfx::IntSize(mClip.width, mClip.height), gfx::SurfaceFormat::B8G8R8A8);
gfx::SurfaceFormat::B8G8R8A8); ctx = new gfxContext(target);
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);
}
// Create our callback. // Create our callback.
nsRefPtr<gfxDrawingCallback> drawTileCallback = nsRefPtr<gfxDrawingCallback> drawTileCallback =

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

@ -17,12 +17,6 @@
namespace base { 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() SharedMemory::SharedMemory()
: mapped_file_(-1), : mapped_file_(-1),
inode_(0), inode_(0),

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

@ -302,20 +302,6 @@ TrimPositions TrimStringT(const STR& input,
((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING)); ((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 TrimWhitespace(const std::wstring& input,
TrimPositions positions, TrimPositions positions,
std::wstring* output) { 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) { static STR IntToString(INT value) {
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. // 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 '-'. // 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. // then return the substr of what we ended up using.
STR outbuf(kOutputBufSize, 0); 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 // Even though is_neg will never be true when INT is parameterized as
// unsigned, even the presence of the unary operation causes a warning. // unsigned, even the presence of the unary operation causes a warning.
UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value); 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 // Specify the byte ordering explicitly, otherwise CFString will be confused
// when strings don't carry BOMs, as they typically won't. // when strings don't carry BOMs, as they typically won't.
static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8; static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16BE;
static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE; static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE;
#elif defined(__LITTLE_ENDIAN__) #elif defined(__LITTLE_ENDIAN__)
static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16LE;
static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE; static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
#endif // __LITTLE_ENDIAN__ #endif // __LITTLE_ENDIAN__

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

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

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

@ -260,7 +260,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
unsigned staticLevel; unsigned staticLevel;
RootedValue thisv(cx); RootedValue thisv(cx);
if (evalType == DIRECT_EVAL) { 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; staticLevel = caller.script()->staticLevel() + 1;
// Direct calls to eval are supposed to see the caller's |this|. If we // 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; return nullptr;
x4->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR, ObjectValue(*typeReprObj)); x4->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type)); x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
x4->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*proto));
// Link constructor to prototype and install properties. // Link constructor to prototype and install properties.

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

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

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

@ -135,6 +135,14 @@ static T ConvertScalar(double d)
class TypeDescr : public JSObject class TypeDescr : public JSObject
{ {
public: 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 { enum Kind {
Scalar = JS_TYPEREPR_SCALAR_KIND, Scalar = JS_TYPEREPR_SCALAR_KIND,
Reference = JS_TYPEREPR_REFERENCE_KIND, Reference = JS_TYPEREPR_REFERENCE_KIND,
@ -269,10 +277,22 @@ class ReferenceTypeDescr : public SimpleTypeDescr
macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \ macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string) 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` * Type descriptors `float32x4` and `int32x4`
*/ */
class X4TypeDescr : public SizedTypeDescr class X4TypeDescr : public ComplexTypeDescr
{ {
public: public:
enum Type { enum Type {
@ -346,6 +366,11 @@ class ArrayMetaTypeDescr : public JSObject
/* /*
* Type descriptor created by `new ArrayType(typeObj)` * 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 class UnsizedArrayTypeDescr : public TypeDescr
{ {
@ -364,7 +389,7 @@ class UnsizedArrayTypeDescr : public TypeDescr
/* /*
* Type descriptor created by `unsizedArrayTypeObj.dimension()` * Type descriptor created by `unsizedArrayTypeObj.dimension()`
*/ */
class SizedArrayTypeDescr : public SizedTypeDescr class SizedArrayTypeDescr : public ComplexTypeDescr
{ {
public: public:
static const Class class_; static const Class class_;
@ -413,7 +438,8 @@ class StructMetaTypeDescr : public JSObject
static bool construct(JSContext *cx, unsigned argc, Value *vp); static bool construct(JSContext *cx, unsigned argc, Value *vp);
}; };
class StructTypeDescr : public SizedTypeDescr { class StructTypeDescr : public ComplexTypeDescr
{
public: public:
static const Class class_; static const Class class_;
@ -873,13 +899,19 @@ IsSimpleTypeDescrClass(const Class* clasp)
clasp == &ReferenceTypeDescr::class_; clasp == &ReferenceTypeDescr::class_;
} }
inline bool
IsComplexTypeDescrClass(const Class* clasp)
{
return clasp == &StructTypeDescr::class_ ||
clasp == &SizedArrayTypeDescr::class_ ||
clasp == &X4TypeDescr::class_;
}
inline bool inline bool
IsSizedTypeDescrClass(const Class* clasp) IsSizedTypeDescrClass(const Class* clasp)
{ {
return IsSimpleTypeDescrClass(clasp) || return IsSimpleTypeDescrClass(clasp) ||
clasp == &StructTypeDescr::class_ || IsComplexTypeDescrClass(clasp);
clasp == &SizedArrayTypeDescr::class_ ||
clasp == &X4TypeDescr::class_;
} }
inline bool inline bool
@ -908,6 +940,13 @@ JSObject::is<js::SizedTypeDescr>() const
return IsSizedTypeDescrClass(getClass()); return IsSizedTypeDescrClass(getClass());
} }
template <>
inline bool
JSObject::is<js::ComplexTypeDescr>() const
{
return IsComplexTypeDescrClass(getClass());
}
template <> template <>
inline bool inline bool
JSObject::is<js::TypeDescr>() const JSObject::is<js::TypeDescr>() const

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

@ -945,18 +945,21 @@ function TypedArrayMap(a, b) {
// Warning: user exposed! // Warning: user exposed!
function TypedArrayMapPar(a, b) { 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)) if (!IsObject(this) || !ObjectIsTypedObject(this))
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS); return callFunction(TypedArrayMap, this, a, b);
var thisType = TYPEDOBJ_TYPE_DESCR(this); var thisType = TYPEDOBJ_TYPE_DESCR(this);
if (!TypeDescrIsArrayType(thisType)) if (!TypeDescrIsArrayType(thisType))
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS); return callFunction(TypedArrayMap, this, a, b);
// Arguments: [depth], func if (typeof a === "number" && IsCallable(b))
if (typeof a === "number" && typeof b === "function")
return MapTypedParImpl(this, a, thisType, b); return MapTypedParImpl(this, a, thisType, b);
else if (typeof a === "function") else if (IsCallable(a))
return MapTypedParImpl(this, 1, thisType, a); return MapTypedParImpl(this, 1, thisType, a);
return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS); return callFunction(TypedArrayMap, this, a, b);
} }
// Warning: user exposed! // Warning: user exposed!
@ -1017,6 +1020,20 @@ function TypedObjectArrayTypeBuildPar(a,b,c) {
// Warning: user exposed! // Warning: user exposed!
function TypedObjectArrayTypeFromPar(a,b,c) { 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); 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."); "Map/From called on non-object or untyped input array.");
assert(TypeDescrIsArrayType(outputType), assert(TypeDescrIsArrayType(outputType),
"Map/From called on non array-type 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); var inArrayType = TypeOfTypedObject(inArray);
@ -1516,6 +1537,12 @@ function MapTypedParImplDepth1(inArray, inArrayType, outArrayType, func) {
outOffset += outGrainTypeSize; 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); MARK_SLICE_DONE(slicesInfo, sliceId);
if (warmup) if (warmup)
return; return;

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

@ -21,23 +21,24 @@
#define JS_DESCR_SLOT_TYPE_REPR 0 // Associated Type Representation #define JS_DESCR_SLOT_TYPE_REPR 0 // Associated Type Representation
#define JS_DESCR_SLOT_ALIGNMENT 1 // Alignment in bytes #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_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 // 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 // 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 // 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 // Slots on struct type objects
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 3 #define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 4
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 4 #define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 5
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 5 #define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 6
// Maximum number of slots for any descriptor // Maximum number of slots for any descriptor
#define JS_DESCR_SLOTS 6 #define JS_DESCR_SLOTS 7
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Slots for type representation objects // Slots for type representation objects

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

@ -1136,7 +1136,8 @@ if test "$GNU_CC"; then
AC_MSG_CHECKING([for --build-id option to ld]) AC_MSG_CHECKING([for --build-id option to ld])
_SAVE_LDFLAGS=$LDFLAGS _SAVE_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS -Wl,--build-id" 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]) AC_MSG_RESULT([no])
LDFLAGS=$_SAVE_LDFLAGS) LDFLAGS=$_SAVE_LDFLAGS)

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

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

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