Merge m-c to b2g-inbound.

This commit is contained in:
Ryan VanderMeulen 2013-09-03 17:44:34 -04:00
commit c6e97adff4
160 changed files with 56095 additions and 40112 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/ # Modifying this file will now automatically clobber the buildbot machines \o/
# #
Bug 909870 - xpidl header generation is somehow busted so we need to clobber on windows Bug 627487 - random test failures caused by bookmark JSON changes

View File

@ -492,6 +492,119 @@ var Output = {
} }
}, },
speechHelper: {
EARCONS: ['chrome://global/content/accessibility/tick.wav'],
delayedActions: [],
earconsToLoad: -1, // -1: not inited, 1 or more: initing, 0: inited
earconBuffers: {},
webaudioEnabled: false,
webspeechEnabled: false,
doDelayedActionsIfLoaded: function doDelayedActionsIfLoaded(aToLoadCount) {
if (aToLoadCount === 0) {
this.outputActions(this.delayedActions);
this.delayedActions = [];
return true;
}
return false;
},
init: function init() {
if (this.earconsToLoad === 0) {
// Already inited.
return;
}
let window = Utils.win;
this.webaudioEnabled = !!window.AudioContext;
this.webspeechEnabled = !!window.speechSynthesis;
this.earconsToLoad = this.webaudioEnabled ? this.EARCONS.length : 0;
if (this.doDelayedActionsIfLoaded(this.earconsToLoad)) {
// Nothing to load
return;
}
this.audioContext = new window.AudioContext();
for (let earcon of this.EARCONS) {
let xhr = new window.XMLHttpRequest();
xhr.open('GET', earcon);
xhr.responseType = 'arraybuffer';
xhr.onerror = () => {
Logger.error('Error getting earcon:', xhr.statusText);
this.doDelayedActionsIfLoaded(--this.earconsToLoad);
};
xhr.onload = () => {
this.audioContext.decodeAudioData(
xhr.response,
(audioBuffer) => {
try {
let earconName = /.*\/(.*)\..*$/.exec(earcon)[1];
this.earconBuffers[earconName] = new WeakMap();
this.earconBuffers[earconName].set(window, audioBuffer);
this.doDelayedActionsIfLoaded(--this.earconsToLoad);
} catch (x) {
Logger.logException(x);
}
},
() => {
this.doDelayedActionsIfLoaded(--this.earconsToLoad);
Logger.error('Error decoding earcon');
});
};
xhr.send();
}
},
output: function output(aActions) {
if (this.earconsToLoad !== 0) {
// We did not load the earcons yet.
this.delayedActions.push.apply(this.delayedActions, aActions);
if (this.earconsToLoad < 0) {
// Loading did not start yet, start it.
this.init();
}
return;
}
this.outputActions(aActions);
},
outputActions: function outputActions(aActions) {
for (let action of aActions) {
let window = Utils.win;
Logger.info('tts.' + action.method,
'"' + action.data + '"',
JSON.stringify(action.options));
if (!action.options.enqueue && this.webspeechEnabled) {
window.speechSynthesis.cancel();
}
if (action.method === 'speak' && this.webspeechEnabled) {
window.speechSynthesis.speak(
new window.SpeechSynthesisUtterance(action.data));
} else if (action.method === 'playEarcon' && this.webaudioEnabled) {
let audioBufferWeakMap = this.earconBuffers[action.data];
if (audioBufferWeakMap) {
let node = this.audioContext.createBufferSource();
node.connect(this.audioContext.destination);
node.buffer = audioBufferWeakMap.get(window);
node.start(0);
}
}
}
}
},
start: function start() { start: function start() {
Cu.import('resource://gre/modules/Geometry.jsm'); Cu.import('resource://gre/modules/Geometry.jsm');
}, },
@ -509,8 +622,7 @@ var Output = {
}, },
Speech: function Speech(aDetails, aBrowser) { Speech: function Speech(aDetails, aBrowser) {
for each (let action in aDetails.actions) this.speechHelper.output(aDetails.actions);
Logger.info('tts.' + action.method, '"' + action.data + '"', JSON.stringify(action.options));
}, },
Visual: function Visual(aDetails, aBrowser) { Visual: function Visual(aDetails, aBrowser) {

View File

@ -5,3 +5,4 @@
toolkit.jar: toolkit.jar:
content/global/accessibility/AccessFu.css (AccessFu.css) content/global/accessibility/AccessFu.css (AccessFu.css)
content/global/accessibility/content-script.js (content-script.js) content/global/accessibility/content-script.js (content-script.js)
content/global/accessibility/tick.wav (tick.wav)

Binary file not shown.

View File

@ -240,6 +240,7 @@
@BINPATH@/components/intl.xpt @BINPATH@/components/intl.xpt
@BINPATH@/components/jar.xpt @BINPATH@/components/jar.xpt
@BINPATH@/components/jsdebugger.xpt @BINPATH@/components/jsdebugger.xpt
@BINPATH@/components/jsdownloads.xpt
@BINPATH@/components/jsdservice.xpt @BINPATH@/components/jsdservice.xpt
@BINPATH@/components/jsinspector.xpt @BINPATH@/components/jsinspector.xpt
@BINPATH@/components/layout_base.xpt @BINPATH@/components/layout_base.xpt

View File

@ -1,4 +1,4 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 0.8.423 Current extension version is: 0.8.478

View File

@ -16,7 +16,7 @@
*/ */
/* jshint esnext:true */ /* jshint esnext:true */
/* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils, /* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils,
dump, NetworkManager */ dump, NetworkManager, PdfJsTelemetry */
'use strict'; 'use strict';
@ -42,6 +42,9 @@ Cu.import('resource://pdf.js/network.js');
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils', XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
'resource://gre/modules/PrivateBrowsingUtils.jsm'); 'resource://gre/modules/PrivateBrowsingUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'PdfJsTelemetry',
'resource://pdf.js/PdfJsTelemetry.jsm');
var Svc = {}; var Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime', XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
'@mozilla.org/mime;1', '@mozilla.org/mime;1',
@ -194,6 +197,12 @@ PdfDataListener.prototype = {
function ChromeActions(domWindow, contentDispositionFilename) { function ChromeActions(domWindow, contentDispositionFilename) {
this.domWindow = domWindow; this.domWindow = domWindow;
this.contentDispositionFilename = contentDispositionFilename; this.contentDispositionFilename = contentDispositionFilename;
this.telemetryState = {
documentInfo: false,
firstPageInfo: false,
streamTypesUsed: [],
startAt: Date.now()
};
} }
ChromeActions.prototype = { ChromeActions.prototype = {
@ -321,12 +330,49 @@ ChromeActions.prototype = {
supportsDocumentColors: function() { supportsDocumentColors: function() {
return getBoolPref('browser.display.use_document_colors', true); return getBoolPref('browser.display.use_document_colors', true);
}, },
reportTelemetry: function (data) {
var probeInfo = JSON.parse(data);
switch (probeInfo.type) {
case 'documentInfo':
if (!this.telemetryState.documentInfo) {
PdfJsTelemetry.onDocumentVersion(probeInfo.version | 0);
PdfJsTelemetry.onDocumentGenerator(probeInfo.generator | 0);
if (probeInfo.formType) {
PdfJsTelemetry.onForm(probeInfo.formType === 'acroform');
}
this.telemetryState.documentInfo = true;
}
break;
case 'pageInfo':
if (!this.telemetryState.firstPageInfo) {
var duration = Date.now() - this.telemetryState.startAt;
PdfJsTelemetry.onTimeToView(duration);
this.telemetryState.firstPageInfo = true;
}
break;
case 'streamInfo':
if (!Array.isArray(probeInfo.streamTypes)) {
break;
}
for (var i = 0; i < probeInfo.streamTypes.length; i++) {
var streamTypeId = probeInfo.streamTypes[i] | 0;
if (streamTypeId >= 0 && streamTypeId < 10 &&
!this.telemetryState.streamTypesUsed[streamTypeId]) {
PdfJsTelemetry.onStreamType(streamTypeId);
this.telemetryState.streamTypesUsed[streamTypeId] = true;
}
}
break;
}
},
fallback: function(url, sendResponse) { fallback: function(url, sendResponse) {
var self = this; var self = this;
var domWindow = this.domWindow; var domWindow = this.domWindow;
var strings = getLocalizedStrings('chrome.properties'); var strings = getLocalizedStrings('chrome.properties');
var message = getLocalizedString(strings, 'unsupported_feature'); var message = getLocalizedString(strings, 'unsupported_feature');
PdfJsTelemetry.onFallback();
var notificationBox = null; var notificationBox = null;
try { try {
// Based on MDN's "Working with windows in chrome code" // Based on MDN's "Working with windows in chrome code"
@ -730,6 +776,9 @@ PdfStreamConverter.prototype = {
false); false);
} }
PdfJsTelemetry.onViewerIsUsed();
PdfJsTelemetry.onDocumentSize(aRequest.contentLength);
if (!rangeRequest) { if (!rangeRequest) {
// Creating storage for PDF data // Creating storage for PDF data
var contentLength = aRequest.contentLength; var contentLength = aRequest.contentLength;

View File

@ -254,7 +254,7 @@ let PdfJs = {
this._pdfStreamConverterFactory.unregister(); this._pdfStreamConverterFactory.unregister();
delete this._pdfStreamConverterFactory; delete this._pdfStreamConverterFactory;
this._pdfRedirectorFactory.unregister; this._pdfRedirectorFactory.unregister();
delete this._pdfRedirectorFactory; delete this._pdfRedirectorFactory;
Svc.pluginHost.unregisterPlayPreviewMimeType(PDF_CONTENT_TYPE); Svc.pluginHost.unregisterPlayPreviewMimeType(PDF_CONTENT_TYPE);

View File

@ -0,0 +1,59 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2013 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
'use strict';
this.EXPORTED_SYMBOLS = ['PdfJsTelemetry'];
const Cu = Components.utils;
Cu.import('resource://gre/modules/Services.jsm');
this.PdfJsTelemetry = {
onViewerIsUsed: function () {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_USED");
histogram.add(true);
},
onFallback: function () {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_FALLBACK_SHOWN");
histogram.add(true);
},
onDocumentSize: function (size) {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_DOCUMENT_SIZE_KB");
histogram.add(size / 1024);
},
onDocumentVersion: function (versionId) {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_DOCUMENT_VERSION");
histogram.add(versionId);
},
onDocumentGenerator: function (generatorId) {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_DOCUMENT_GENERATOR");
histogram.add(generatorId);
},
onForm: function (isAcroform) {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_FORM");
histogram.add(isAcroform);
},
onStreamType: function (streamTypeId) {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_STREAM_TYPES");
histogram.add(streamTypeId);
},
onTimeToView: function (ms) {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_TIME_TO_VIEW_MS");
histogram.add(ms);
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -228,6 +228,25 @@ var Stepper = (function StepperClosure() {
return d; return d;
} }
function glyphsToString(glyphs) {
var out = '';
for (var i = 0; i < glyphs.length; i++) {
if (glyphs[i] === null) {
out += ' ';
} else {
out += glyphs[i].fontChar;
}
}
return out;
}
var glyphCommands = {
'showText': 0,
'showSpacedText': 0,
'nextLineShowText': 0,
'nextLineSetSpacingShowText': 2
};
function Stepper(panel, pageIndex, initialBreakPoints) { function Stepper(panel, pageIndex, initialBreakPoints) {
this.panel = panel; this.panel = panel;
this.breakPoint = 0; this.breakPoint = 0;
@ -281,8 +300,29 @@ var Stepper = (function StepperClosure() {
breakCell.appendChild(cbox); breakCell.appendChild(cbox);
line.appendChild(breakCell); line.appendChild(breakCell);
line.appendChild(c('td', i.toString())); line.appendChild(c('td', i.toString()));
line.appendChild(c('td', operatorList.fnArray[i])); var fn = operatorList.fnArray[i];
line.appendChild(c('td', args.join(', '))); var decArgs = args;
if (fn in glyphCommands) {
var glyphIndex = glyphCommands[fn];
var glyphs = args[glyphIndex];
var decArgs = args.slice();
var newArg;
if (fn === 'showSpacedText') {
newArg = [];
for (var j = 0; j < glyphs.length; j++) {
if (typeof glyphs[j] === 'number') {
newArg.push(glyphs[j]);
} else {
newArg.push(glyphsToString(glyphs[j]));
}
}
} else {
newArg = glyphsToString(glyphs);
}
decArgs[glyphIndex] = newArg;
}
line.appendChild(c('td', fn));
line.appendChild(c('td', JSON.stringify(decArgs)));
} }
}, },
getNextBreakPoint: function getNextBreakPoint() { getNextBreakPoint: function getNextBreakPoint() {

View File

@ -982,7 +982,7 @@ html[dir='rtl'] .outlineItem > a {
} }
canvas { canvas {
margin: auto; margin: 0;
display: block; display: block;
} }
@ -1105,6 +1105,9 @@ canvas {
padding: 3px; padding: 3px;
font-size: 0.8em; font-size: 0.8em;
} }
.loadingInProgress #errorWrapper {
top: 39px;
}
#errorMessageLeft { #errorMessageLeft {
float: left; float: left;

View File

@ -17,7 +17,7 @@
/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar, CustomStyle, /* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar, CustomStyle,
PDFFindController, ProgressBar, TextLayerBuilder, DownloadManager, PDFFindController, ProgressBar, TextLayerBuilder, DownloadManager,
getFileName, getOutputScale, scrollIntoView, getPDFFileNameFromURL, getFileName, getOutputScale, scrollIntoView, getPDFFileNameFromURL,
PDFHistory, noContextMenuHandler */ PDFHistory, ThumbnailView, noContextMenuHandler */
'use strict'; 'use strict';
@ -48,7 +48,7 @@ var FindStates = {
}; };
PDFJS.imageResourcesPath = './images/'; PDFJS.imageResourcesPath = './images/';
PDFJS.workerSrc = '../build/pdf.js'; PDFJS.workerSrc = '../build/pdf.worker.js';
var mozL10n = document.mozL10n || document.webL10n; var mozL10n = document.mozL10n || document.webL10n;
@ -662,6 +662,12 @@ var PDFFindController = {
} }
}, },
reset: function pdfFindControllerReset() {
this.startedTextExtraction = false;
this.extractTextPromises = [];
this.active = false;
},
calcFindMatch: function(pageIndex) { calcFindMatch: function(pageIndex) {
var pageContent = this.pageContents[pageIndex]; var pageContent = this.pageContents[pageIndex];
var query = this.state.query; var query = this.state.query;
@ -969,7 +975,7 @@ var PDFHistory = {
// is opened in the web viewer. // is opened in the web viewer.
this.reInitialized = true; this.reInitialized = true;
} }
window.history.replaceState({ fingerprint: this.fingerprint }, '', ''); window.history.replaceState({ fingerprint: this.fingerprint }, '');
} }
var self = this; var self = this;
@ -1174,9 +1180,9 @@ var PDFHistory = {
} }
} }
if (overwrite || this.uid === 0) { if (overwrite || this.uid === 0) {
window.history.replaceState(this._stateObj(params), '', ''); window.history.replaceState(this._stateObj(params), '');
} else { } else {
window.history.pushState(this._stateObj(params), '', ''); window.history.pushState(this._stateObj(params), '');
} }
this.currentUid = this.uid++; this.currentUid = this.uid++;
this.current = params; this.current = params;
@ -1248,8 +1254,6 @@ var PDFView = {
currentScale: UNKNOWN_SCALE, currentScale: UNKNOWN_SCALE,
currentScaleValue: null, currentScaleValue: null,
initialBookmark: document.location.hash.substring(1), initialBookmark: document.location.hash.substring(1),
startedTextExtraction: false,
pageText: [],
container: null, container: null,
thumbnailContainer: null, thumbnailContainer: null,
initialized: false, initialized: false,
@ -1839,6 +1843,8 @@ var PDFView = {
}; };
} }
PDFFindController.reset();
this.pdfDocument = pdfDocument; this.pdfDocument = pdfDocument;
var errorWrapper = document.getElementById('errorWrapper'); var errorWrapper = document.getElementById('errorWrapper');
@ -1876,8 +1882,6 @@ var PDFView = {
this.pageRotation = 0; this.pageRotation = 0;
var pages = this.pages = []; var pages = this.pages = [];
this.pageText = [];
this.startedTextExtraction = false;
var pagesRefMap = this.pagesRefMap = {}; var pagesRefMap = this.pagesRefMap = {};
var thumbnails = this.thumbnails = []; var thumbnails = this.thumbnails = [];
@ -2030,6 +2034,32 @@ var PDFView = {
console.warn('Warning: AcroForm/XFA is not supported'); console.warn('Warning: AcroForm/XFA is not supported');
PDFView.fallback(); PDFView.fallback();
} }
var versionId = String(info.PDFFormatVersion).slice(-1) | 0;
var generatorId = 0;
var KNOWN_GENERATORS = ["acrobat distiller", "acrobat pdfwritter",
"adobe livecycle", "adobe pdf library", "adobe photoshop", "ghostscript",
"tcpdf", "cairo", "dvipdfm", "dvips", "pdftex", "pdfkit", "itext",
"prince", "quarkxpress", "mac os x", "microsoft", "openoffice", "oracle",
"luradocument", "pdf-xchange", "antenna house", "aspose.cells", "fpdf"];
var generatorId = 0;
if (info.Producer) {
KNOWN_GENERATORS.some(function (generator, s, i) {
if (generator.indexOf(s) < 0) {
return false;
}
generatorId = i + 1;
return true;
}.bind(null, info.Producer.toLowerCase()));
}
var formType = !info.IsAcroFormPresent ? null : info.IsXFAPresent ?
'xfa' : 'acroform';
FirefoxCom.request('reportTelemetry', JSON.stringify({
type: 'documentInfo',
version: versionId,
generator: generatorId,
formType: formType
}));
}); });
}, },
@ -2624,6 +2654,52 @@ var PageView = function pageView(container, id, scale,
link.className = 'internalLink'; link.className = 'internalLink';
} }
function bindNamedAction(link, action) {
link.onclick = function pageViewSetupNamedActionOnClick() {
// See PDF reference, table 8.45 - Named action
switch (action) {
case 'GoToPage':
document.getElementById('pageNumber').focus();
break;
case 'GoBack':
PDFHistory.back();
break;
case 'GoForward':
PDFHistory.forward();
break;
case 'Find':
if (!PDFView.supportsIntegratedFind) {
PDFFindBar.toggle();
}
break;
case 'NextPage':
PDFView.page++;
break;
case 'PrevPage':
PDFView.page--;
break;
case 'LastPage':
PDFView.page = PDFView.pages.length;
break;
case 'FirstPage':
PDFView.page = 1;
break;
default:
break; // No action according to spec
}
return false;
};
link.className = 'internalLink';
}
pdfPage.getAnnotations().then(function(annotationsData) { pdfPage.getAnnotations().then(function(annotationsData) {
viewport = viewport.clone({ dontFlip: true }); viewport = viewport.clone({ dontFlip: true });
for (var i = 0; i < annotationsData.length; i++) { for (var i = 0; i < annotationsData.length; i++) {
@ -2656,7 +2732,11 @@ var PageView = function pageView(container, id, scale,
CustomStyle.setProp('transformOrigin', element, transformOriginStr); CustomStyle.setProp('transformOrigin', element, transformOriginStr);
if (data.subtype === 'Link' && !data.url) { if (data.subtype === 'Link' && !data.url) {
bindLink(element, ('dest' in data) ? data.dest : null); if (data.action) {
bindNamedAction(element, data.action);
} else {
bindLink(element, ('dest' in data) ? data.dest : null);
}
} }
annotationsDiv.appendChild(element); annotationsDiv.appendChild(element);
@ -2884,6 +2964,10 @@ var PageView = function pageView(container, id, scale,
}); });
div.dispatchEvent(event); div.dispatchEvent(event);
FirefoxCom.request('reportTelemetry', JSON.stringify({
type: 'pageInfo'
}));
// TODO add stream types report here
callback(); callback();
} }
@ -2990,6 +3074,7 @@ var PageView = function pageView(container, id, scale,
}; };
}; };
var ThumbnailView = function thumbnailView(container, id, defaultViewport) { var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
var anchor = document.createElement('a'); var anchor = document.createElement('a');
anchor.href = PDFView.getAnchorUrl('#page=' + id); anchor.href = PDFView.getAnchorUrl('#page=' + id);
@ -2999,7 +3084,6 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
return false; return false;
}; };
this.pdfPage = undefined; this.pdfPage = undefined;
this.viewport = defaultViewport; this.viewport = defaultViewport;
this.pdfPageRotate = defaultViewport.rotate; this.pdfPageRotate = defaultViewport.rotate;
@ -3574,6 +3658,7 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
var file = window.location.href.split('#')[0]; var file = window.location.href.split('#')[0];
document.getElementById('openFile').setAttribute('hidden', 'true'); document.getElementById('openFile').setAttribute('hidden', 'true');
// Special debugging flags in the hash section of the URL. // Special debugging flags in the hash section of the URL.
@ -4034,8 +4119,12 @@ window.addEventListener('keydown', function keydown(evt) {
break; break;
case 48: // '0' case 48: // '0'
case 96: // '0' on Numpad of Swedish keyboard case 96: // '0' on Numpad of Swedish keyboard
PDFView.parseScale(DEFAULT_SCALE, true); // keeping it unhandled (to restore page zoom to 100%)
handled = false; // keeping it unhandled (to restore page zoom to 100%) setTimeout(function () {
// ... and resetting the scale after browser adjusts its scale
PDFView.parseScale(DEFAULT_SCALE, true);
});
handled = false;
break; break;
} }
} }

View File

@ -2,8 +2,10 @@ chrome.manifest
components/PdfRedirector.js components/PdfRedirector.js
components/PdfStreamConverter.js components/PdfStreamConverter.js
content/build/pdf.js content/build/pdf.js
content/build/pdf.worker.js
content/network.js content/network.js
content/PdfJs.jsm content/PdfJs.jsm
content/PdfJsTelemetry.jsm
content/web/debugger.js content/web/debugger.js
content/web/images/annotation-check.svg content/web/images/annotation-check.svg
content/web/images/annotation-comment.svg content/web/images/annotation-comment.svg

View File

@ -248,6 +248,7 @@
@BINPATH@/components/jsdservice.xpt @BINPATH@/components/jsdservice.xpt
#endif #endif
@BINPATH@/components/jsdebugger.xpt @BINPATH@/components/jsdebugger.xpt
@BINPATH@/components/jsdownloads.xpt
@BINPATH@/components/jsinspector.xpt @BINPATH@/components/jsinspector.xpt
@BINPATH@/components/layout_base.xpt @BINPATH@/components/layout_base.xpt
#ifdef NS_PRINTING #ifdef NS_PRINTING

View File

@ -10,6 +10,9 @@ Cu.import("resource://gre/modules/Services.jsm");
* JS modules * JS modules
*/ */
XPCOMUtils.defineLazyModuleGetter(this , "FormHistory",
"resource://gre/modules/FormHistory.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm"); "resource://gre/modules/PluralForm.jsm");

View File

@ -143,8 +143,6 @@ var BrowserUI = {
// Login Manager and Form History initialization // Login Manager and Form History initialization
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
messageManager.addMessageListener("Browser:MozApplicationManifest", OfflineApps); messageManager.addMessageListener("Browser:MozApplicationManifest", OfflineApps);
try { try {

View File

@ -3,10 +3,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
function Sanitizer() {} function Sanitizer() {}
Sanitizer.prototype = { Sanitizer.prototype = {
@ -17,17 +13,22 @@ Sanitizer.prototype = {
this.items[aItemName].clear(); this.items[aItemName].clear();
}, },
canClearItem: function (aItemName) canClearItem: function (aItemName, aCallback, aArg)
{ {
return this.items[aItemName].canClear; let canClear = this.items[aItemName].canClear;
if (typeof canClear == "function"){
canClear(aCallback, aArg);
} else {
aCallback(aItemName, canClear, aArg);
}
}, },
_prefDomain: "privacy.item.", _prefDomain: "privacy.item.",
getNameFromPreference: function (aPreferenceName) getNameFromPreference: function (aPreferenceName)
{ {
return aPreferenceName.substr(this._prefDomain.length); return aPreferenceName.substr(this._prefDomain.length);
}, },
/** /**
* Deletes privacy sensitive data in a batch, according to user preferences * Deletes privacy sensitive data in a batch, according to user preferences
* *
@ -39,26 +40,32 @@ Sanitizer.prototype = {
var branch = Services.prefs.getBranch(this._prefDomain); var branch = Services.prefs.getBranch(this._prefDomain);
var errors = null; var errors = null;
for (var itemName in this.items) { for (var itemName in this.items) {
var item = this.items[itemName]; if ("clear" in item && branch.getBoolPref(itemName)) {
if ("clear" in item && item.canClear && branch.getBoolPref(itemName)) {
// Some of these clear() may raise exceptions (see bug #265028) // Some of these clear() may raise exceptions (see bug #265028)
// to sanitize as much as possible, we catch and store them, // to sanitize as much as possible, we catch and store them,
// rather than fail fast. // rather than fail fast.
// Callers should check returned errors and give user feedback // Callers should check returned errors and give user feedback
// about items that could not be sanitized // about items that could not be sanitized
try { let clearCallback = (itemName, aCanClear) => {
item.clear(); let item = this.items[itemName];
} catch(er) { try{
if (!errors) if (aCanClear){
errors = {}; item.clear();
errors[itemName] = er; }
dump("Error sanitizing " + itemName + ": " + er + "\n"); } catch(er){
if (!errors){
errors = {};
}
errors[itemName] = er;
dump("Error sanitizing " + itemName + ":" + er + "\n");
}
} }
this.canClearItem(itemName, clearCallback);
} }
} }
return errors; return errors;
}, },
items: { items: {
// Clear Sync account before passwords so that Sync still has access to the // Clear Sync account before passwords so that Sync still has access to the
// credentials to clean up device-specific records on the server. Also // credentials to clean up device-specific records on the server. Also
@ -88,20 +95,20 @@ Sanitizer.prototype = {
imageCache.clearCache(false); // true=chrome, false=content imageCache.clearCache(false); // true=chrome, false=content
} catch(er) {} } catch(er) {}
}, },
get canClear() get canClear()
{ {
return true; return true;
} }
}, },
cookies: { cookies: {
clear: function () clear: function ()
{ {
var cookieMgr = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager); var cookieMgr = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
cookieMgr.removeAll(); cookieMgr.removeAll();
}, },
get canClear() get canClear()
{ {
return true; return true;
@ -185,18 +192,21 @@ Sanitizer.prototype = {
searchBar.textbox.editor.transactionManager.clear(); searchBar.textbox.editor.transactionManager.clear();
} }
} }
FormHistory.update({op : "remove"});
var formHistory = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
formHistory.removeAllEntries();
}, },
get canClear() canClear : function(aCallback, aArg)
{ {
var formHistory = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2); let count = 0;
return formHistory.hasEntries; let countDone = {
handleResult : function(aResult) { count = aResult; },
handleError : function(aError) { Components.utils.reportError(aError); },
handleCompletion : function(aReason) { aCallback("formdata", aReason == 0 && count > 0, aArg); }
};
FormHistory.count({}, countDone);
} }
}, },
downloads: { downloads: {
clear: function () clear: function ()
{ {
@ -210,14 +220,14 @@ Sanitizer.prototype = {
return dlMgr.canCleanUp; return dlMgr.canCleanUp;
} }
}, },
passwords: { passwords: {
clear: function () clear: function ()
{ {
var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
pwmgr.removeAllLogins(); pwmgr.removeAllLogins();
}, },
get canClear() get canClear()
{ {
var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
@ -225,7 +235,7 @@ Sanitizer.prototype = {
return (count > 0); return (count > 0);
} }
}, },
sessions: { sessions: {
clear: function () clear: function ()
{ {
@ -237,7 +247,7 @@ Sanitizer.prototype = {
var authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].getService(Ci.nsIHttpAuthManager); var authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].getService(Ci.nsIHttpAuthManager);
authMgr.clearAll(); authMgr.clearAll();
}, },
get canClear() get canClear()
{ {
return true; return true;

View File

@ -6,8 +6,7 @@
"use strict"; "use strict";
function clearFormHistory() { function clearFormHistory() {
var formHistory = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2); FormHistory.update({ op : "remove" });
formHistory.removeAllEntries();
} }
function test() { function test() {

View File

@ -82,13 +82,6 @@ public interface Actions {
void drag(int startingX, int endingX, int startingY, int endingY); void drag(int startingX, int endingX, int startingY, int endingY);
/**
* This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
* TODO : Remove this when Robotium is updated
*/
void clickLongOnScreen(float x, float y);
/** /**
* Run a sql query on the specified database * Run a sql query on the specified database
*/ */

View File

@ -460,41 +460,6 @@ public class FennecNativeActions implements Actions {
mSolo.drag(startingX, endingX, startingY, endingY, 10); mSolo.drag(startingX, endingX, startingY, endingY, 10);
} }
/**
* This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
* TODO : Remove this when Robotium is updated
*/
public void clickLongOnScreen(float x, float y) {
boolean successfull = false;
int retry = 0;
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
while(!successfull && retry < 10) {
try{
mInstr.sendPointerSync(event);
successfull = true;
}catch(SecurityException e){
FennecNativeDriver.log(LogLevel.ERROR, e);
retry++;
}
}
mAsserter.ok(successfull, "Trying to click on long on screen at (" + x + "," + y + ")", "Was able to click long on screen");
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x + 1.0f, y + 1.0f, 0);
mInstr.sendPointerSync(event);
mSolo.sleep(((int)(ViewConfiguration.getLongPressTimeout() * 2.5f)));
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
mInstr.sendPointerSync(event);
mSolo.sleep(500);
}
public Cursor querySql(String dbPath, String sql) { public Cursor querySql(String dbPath, String sql) {
try { try {
return (Cursor)mQuerySql.invoke(mRobocopApi, dbPath, sql); return (Cursor)mQuerySql.invoke(mRobocopApi, dbPath, sql);

View File

@ -15,7 +15,7 @@ include $(DEPTH)/config/autoconf.mk
ANDROID_APK_NAME := robocop-debug ANDROID_APK_NAME := robocop-debug
ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.6.jar ROBOTIUM_PATH = $(srcdir)/robotium-solo-4.2.jar
JAVAFILES = \ JAVAFILES = \
R.java \ R.java \

View File

@ -4,7 +4,7 @@ Robotium is an open source tool licensed under the Apache 2.0 license and the or
source can be found here: source can be found here:
http://code.google.com/p/robotium/ http://code.google.com/p/robotium/
We are including robotium-solo-3.6.jar as a binary and are not modifying it in any way We are including robotium-solo-4.2.jar as a binary and are not modifying it in any way
from the original download found at: from the original download found at:
http://code.google.com/p/robotium/ http://code.google.com/p/robotium/

Binary file not shown.

View File

@ -1733,6 +1733,16 @@ case "$host" in
;; ;;
esac esac
dnl Check for using a custom <inttypes.h> implementation
dnl ========================================================
AC_MSG_CHECKING(for custom <inttypes.h> implementation)
if test "$MOZ_CUSTOM_INTTYPES_H"; then
AC_DEFINE_UNQUOTED(MOZ_CUSTOM_INTTYPES_H, "$MOZ_CUSTOM_INTTYPES_H")
AC_MSG_RESULT(using $MOZ_CUSTOM_INTTYPES_H)
else
AC_MSG_RESULT(none specified)
fi
dnl Get mozilla version from central milestone file dnl Get mozilla version from central milestone file
MOZILLA_VERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir` MOZILLA_VERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir`
MOZILLA_UAVERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir -uaversion` MOZILLA_UAVERSION=`$PERL $srcdir/config/milestone.pl -topsrcdir $srcdir -uaversion`

View File

@ -61,7 +61,6 @@ EXPORTS += [
'nsINodeList.h', 'nsINodeList.h',
'nsIScriptElement.h', 'nsIScriptElement.h',
'nsIStyleSheetLinkingElement.h', 'nsIStyleSheetLinkingElement.h',
'nsIXPathEvaluatorInternal.h',
'nsLineBreaker.h', 'nsLineBreaker.h',
'nsReferencedElement.h', 'nsReferencedElement.h',
'nsTreeSanitizer.h', 'nsTreeSanitizer.h',

View File

@ -109,6 +109,7 @@ class ProcessingInstruction;
class Touch; class Touch;
class TreeWalker; class TreeWalker;
class UndoManager; class UndoManager;
class XPathEvaluator;
template<typename> class OwningNonNull; template<typename> class OwningNonNull;
template<typename> class Sequence; template<typename> class Sequence;
@ -2171,6 +2172,8 @@ protected:
return mContentType; return mContentType;
} }
mozilla::dom::XPathEvaluator* XPathEvaluator();
nsCString mReferrer; nsCString mReferrer;
nsString mLastModified; nsString mLastModified;
@ -2426,6 +2429,8 @@ protected:
uint8_t mDefaultElementType; uint8_t mDefaultElementType;
uint32_t mInSyncOperationCount; uint32_t mInSyncOperationCount;
nsRefPtr<mozilla::dom::XPathEvaluator> mXPathEvaluator;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID) NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)

View File

@ -1,43 +0,0 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsIXPathEvaluatorInternal_h__
#define nsIXPathEvaluatorInternal_h__
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsStringGlue.h"
class nsIDOMDocument;
class nsIDOMXPathExpression;
class nsIDOMXPathNSResolver;
#define NS_IXPATHEVALUATORINTERNAL_IID \
{0xb4b72daa, 0x65d6, 0x440f, \
{ 0xb6, 0x08, 0xe2, 0xee, 0x9a, 0x82, 0xf3, 0x13 }}
class nsIXPathEvaluatorInternal : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXPATHEVALUATORINTERNAL_IID)
/**
* Sets the document this evaluator corresponds to
*/
NS_IMETHOD SetDocument(nsIDOMDocument* aDocument) = 0;
NS_IMETHOD CreateExpression(const nsAString &aExpression,
nsIDOMXPathNSResolver *aResolver,
nsTArray<nsString> *aNamespaceURIs,
nsTArray<nsCString> *aContractIDs,
nsCOMArray<nsISupports> *aState,
nsIDOMXPathExpression **aResult) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIXPathEvaluatorInternal,
NS_IXPATHEVALUATORINTERNAL_IID)
#endif //nsIXPathEvaluatorInternal_h__

View File

@ -27,6 +27,7 @@ LOCAL_INCLUDES += \
-I$(topsrcdir)/content/xbl/src \ -I$(topsrcdir)/content/xbl/src \
-I$(topsrcdir)/content/xml/content/src \ -I$(topsrcdir)/content/xml/content/src \
-I$(topsrcdir)/content/xml/document/src \ -I$(topsrcdir)/content/xml/document/src \
-I$(topsrcdir)/content/xslt/src/xpath \
-I$(topsrcdir)/content/xul/content/src \ -I$(topsrcdir)/content/xul/content/src \
-I$(topsrcdir)/content/xul/document/src \ -I$(topsrcdir)/content/xul/document/src \
-I$(topsrcdir)/dom/base \ -I$(topsrcdir)/dom/base \

View File

@ -99,10 +99,8 @@
#include "nsBidiUtils.h" #include "nsBidiUtils.h"
#include "nsIDOMUserDataHandler.h" #include "nsIDOMUserDataHandler.h"
#include "nsIDOMXPathEvaluator.h"
#include "nsIDOMXPathExpression.h" #include "nsIDOMXPathExpression.h"
#include "nsIDOMXPathNSResolver.h" #include "nsIDOMXPathNSResolver.h"
#include "nsIXPathEvaluatorInternal.h"
#include "nsIParserService.h" #include "nsIParserService.h"
#include "nsContentCreatorFunctions.h" #include "nsContentCreatorFunctions.h"
@ -213,6 +211,7 @@
#include "nsIHttpChannelInternal.h" #include "nsIHttpChannelInternal.h"
#include "nsISecurityConsoleMessage.h" #include "nsISecurityConsoleMessage.h"
#include "nsCharSeparatedTokenizer.h" #include "nsCharSeparatedTokenizer.h"
#include "mozilla/dom/XPathEvaluator.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@ -1582,23 +1581,11 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMXPathEvaluator)
NS_INTERFACE_TABLE_END NS_INTERFACE_TABLE_END
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument) NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument)
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver, NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
new nsNode3Tearoff(this)) new nsNode3Tearoff(this))
if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
if (!mXPathEvaluatorTearoff) {
nsresult rv;
mXPathEvaluatorTearoff =
do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID,
static_cast<nsIDocument *>(this), &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
return mXPathEvaluatorTearoff->QueryInterface(aIID, aInstancePtr);
}
else
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
@ -1784,7 +1771,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleAttrStyleSheet) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleAttrStyleSheet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXPathEvaluatorTearoff) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXPathEvaluator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref)
@ -1871,7 +1858,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
} }
tmp->mFirstChild = nullptr; tmp->mFirstChild = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mXPathEvaluatorTearoff) NS_IMPL_CYCLE_COLLECTION_UNLINK(mXPathEvaluator)
tmp->mCachedRootElement = nullptr; // Avoid a dangling pointer tmp->mCachedRootElement = nullptr; // Avoid a dangling pointer
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref)
@ -11285,31 +11272,14 @@ nsIDocument::CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver, nsIDOMXPathNSResolver* aResolver,
ErrorResult& rv) ErrorResult& rv)
{ {
nsCOMPtr<nsIDOMXPathEvaluator> evaluator = do_QueryInterface(this); return XPathEvaluator()->CreateExpression(aExpression, aResolver, rv);
if (!evaluator) {
rv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIDOMXPathExpression> expr;
rv = evaluator->CreateExpression(aExpression, aResolver, getter_AddRefs(expr));
return expr.forget();
} }
already_AddRefed<nsIDOMXPathNSResolver> already_AddRefed<nsIDOMXPathNSResolver>
nsIDocument::CreateNSResolver(nsINode* aNodeResolver, nsIDocument::CreateNSResolver(nsINode* aNodeResolver,
ErrorResult& rv) ErrorResult& rv)
{ {
nsCOMPtr<nsIDOMXPathEvaluator> evaluator = do_QueryInterface(this); return XPathEvaluator()->CreateNSResolver(aNodeResolver, rv);
if (!evaluator) {
rv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIDOMNode> nodeResolver = do_QueryInterface(aNodeResolver);
nsCOMPtr<nsIDOMXPathNSResolver> res;
rv = evaluator->CreateNSResolver(nodeResolver, getter_AddRefs(res));
return res.forget();
} }
already_AddRefed<nsISupports> already_AddRefed<nsISupports>
@ -11317,19 +11287,34 @@ nsIDocument::Evaluate(const nsAString& aExpression, nsINode* aContextNode,
nsIDOMXPathNSResolver* aResolver, uint16_t aType, nsIDOMXPathNSResolver* aResolver, uint16_t aType,
nsISupports* aResult, ErrorResult& rv) nsISupports* aResult, ErrorResult& rv)
{ {
nsCOMPtr<nsIDOMXPathEvaluator> evaluator = do_QueryInterface(this); return XPathEvaluator()->Evaluate(aExpression, aContextNode, aResolver, aType,
if (!evaluator) { aResult, rv);
rv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIDOMNode> contextNode = do_QueryInterface(aContextNode);
nsCOMPtr<nsISupports> res;
rv = evaluator->Evaluate(aExpression, contextNode, aResolver, aType,
aResult, getter_AddRefs(res));
return res.forget();
} }
NS_IMETHODIMP
nsDocument::CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
nsIDOMXPathExpression** aResult)
{
return XPathEvaluator()->CreateExpression(aExpression, aResolver, aResult);
}
NS_IMETHODIMP
nsDocument::CreateNSResolver(nsIDOMNode* aNodeResolver,
nsIDOMXPathNSResolver** aResult)
{
return XPathEvaluator()->CreateNSResolver(aNodeResolver, aResult);
}
NS_IMETHODIMP
nsDocument::Evaluate(const nsAString& aExpression, nsIDOMNode* aContextNode,
nsIDOMXPathNSResolver* aResolver, uint16_t aType,
nsISupports* aInResult, nsISupports** aResult)
{
return XPathEvaluator()->Evaluate(aExpression, aContextNode, aResolver, aType,
aInResult, aResult);
}
// This is just a hack around the fact that window.document is not // This is just a hack around the fact that window.document is not
// [Unforgeable] yet. // [Unforgeable] yet.
JSObject* JSObject*
@ -11381,6 +11366,15 @@ nsIDocument::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aScope)
return obj; return obj;
} }
XPathEvaluator*
nsIDocument::XPathEvaluator()
{
if (!mXPathEvaluator) {
mXPathEvaluator = new dom::XPathEvaluator(this);
}
return mXPathEvaluator;
}
bool bool
MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData) MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
{ {

View File

@ -68,6 +68,7 @@
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "nsIDOMXPathEvaluator.h"
#define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0) #define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0)
#define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1) #define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1)
@ -504,7 +505,8 @@ class nsDocument : public nsIDocument,
public nsIRadioGroupContainer, public nsIRadioGroupContainer,
public nsIApplicationCacheContainer, public nsIApplicationCacheContainer,
public nsStubMutationObserver, public nsStubMutationObserver,
public nsIObserver public nsIObserver,
public nsIDOMXPathEvaluator
{ {
public: public:
typedef mozilla::dom::Element Element; typedef mozilla::dom::Element Element;
@ -784,6 +786,8 @@ public:
// nsIObserver // nsIObserver
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMXPATHEVALUATOR
virtual nsresult Init(); virtual nsresult Init();
virtual nsresult CreateElem(const nsAString& aName, nsIAtom *aPrefix, virtual nsresult CreateElem(const nsAString& aName, nsIAtom *aPrefix,
@ -1343,8 +1347,6 @@ private:
nsDocument(const nsDocument& aOther); nsDocument(const nsDocument& aOther);
nsDocument& operator=(const nsDocument& aOther); nsDocument& operator=(const nsDocument& aOther);
nsCOMPtr<nsISupports> mXPathEvaluatorTearoff;
// The layout history state that should be used by nodes in this // The layout history state that should be used by nodes in this
// document. We only actually store a pointer to it when: // document. We only actually store a pointer to it when:
// 1) We have no script global object. // 1) We have no script global object.

View File

@ -25,6 +25,17 @@ public:
nsCOMPtr<nsIAtom> mPrevAttrValue; nsCOMPtr<nsIAtom> mPrevAttrValue;
nsCOMPtr<nsIAtom> mNewAttrValue; nsCOMPtr<nsIAtom> mNewAttrValue;
unsigned short mAttrChange; unsigned short mAttrChange;
void AssignMutationEventData(const nsMutationEvent& aEvent, bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
mRelatedNode = aEvent.mRelatedNode;
mAttrName = aEvent.mAttrName;
mPrevAttrValue = aEvent.mPrevAttrValue;
mNewAttrValue = aEvent.mNewAttrValue;
mAttrChange = aEvent.mAttrChange;
}
}; };
#define NS_MUTATION_START 1800 #define NS_MUTATION_START 1800

View File

@ -520,17 +520,6 @@ nsDOMEvent::DuplicatePrivateData()
newEvent = guiEvent; newEvent = guiEvent;
break; break;
} }
case NS_SCROLLBAR_EVENT:
{
nsScrollbarEvent* oldScrollbarEvent =
static_cast<nsScrollbarEvent*>(mEvent);
nsScrollbarEvent* scrollbarEvent =
new nsScrollbarEvent(false, msg, nullptr);
scrollbarEvent->AssignGUIEventData(*scrollbarEvent, true);
scrollbarEvent->position = oldScrollbarEvent->position;
newEvent = scrollbarEvent;
break;
}
case NS_INPUT_EVENT: case NS_INPUT_EVENT:
{ {
nsInputEvent* oldInputEvent = static_cast<nsInputEvent*>(mEvent); nsInputEvent* oldInputEvent = static_cast<nsInputEvent*>(mEvent);
@ -561,15 +550,7 @@ nsDOMEvent::DuplicatePrivateData()
nsDragEvent* oldDragEvent = static_cast<nsDragEvent*>(mEvent); nsDragEvent* oldDragEvent = static_cast<nsDragEvent*>(mEvent);
nsDragEvent* dragEvent = nsDragEvent* dragEvent =
new nsDragEvent(false, msg, nullptr); new nsDragEvent(false, msg, nullptr);
dragEvent->AssignInputEventData(*oldDragEvent, true); dragEvent->AssignDragEventData(*oldDragEvent, true);
dragEvent->dataTransfer = oldDragEvent->dataTransfer;
dragEvent->clickCount = oldDragEvent->clickCount;
dragEvent->acceptActivation = oldDragEvent->acceptActivation;
dragEvent->relatedTarget = oldDragEvent->relatedTarget;
dragEvent->button = oldDragEvent->button;
dragEvent->buttons = oldDragEvent->buttons;
static_cast<nsMouseEvent*>(dragEvent)->inputSource =
static_cast<nsMouseEvent*>(oldDragEvent)->inputSource;
newEvent = dragEvent; newEvent = dragEvent;
break; break;
} }
@ -577,8 +558,7 @@ nsDOMEvent::DuplicatePrivateData()
{ {
nsClipboardEvent* oldClipboardEvent = static_cast<nsClipboardEvent*>(mEvent); nsClipboardEvent* oldClipboardEvent = static_cast<nsClipboardEvent*>(mEvent);
nsClipboardEvent* clipboardEvent = new nsClipboardEvent(false, msg); nsClipboardEvent* clipboardEvent = new nsClipboardEvent(false, msg);
clipboardEvent->AssignEventData(*oldClipboardEvent, true); clipboardEvent->AssignClipboardEventData(*oldClipboardEvent, true);
clipboardEvent->clipboardData = oldClipboardEvent->clipboardData;
newEvent = clipboardEvent; newEvent = clipboardEvent;
break; break;
} }
@ -587,8 +567,7 @@ nsDOMEvent::DuplicatePrivateData()
nsScriptErrorEvent* oldScriptErrorEvent = nsScriptErrorEvent* oldScriptErrorEvent =
static_cast<nsScriptErrorEvent*>(mEvent); static_cast<nsScriptErrorEvent*>(mEvent);
nsScriptErrorEvent* scriptErrorEvent = new nsScriptErrorEvent(false, msg); nsScriptErrorEvent* scriptErrorEvent = new nsScriptErrorEvent(false, msg);
scriptErrorEvent->AssignEventData(*oldScriptErrorEvent, true); scriptErrorEvent->AssignScriptErrorEventData(*oldScriptErrorEvent, true);
scriptErrorEvent->lineNr = oldScriptErrorEvent->lineNr;
newEvent = scriptErrorEvent; newEvent = scriptErrorEvent;
break; break;
} }
@ -596,7 +575,7 @@ nsDOMEvent::DuplicatePrivateData()
{ {
nsTextEvent* oldTextEvent = static_cast<nsTextEvent*>(mEvent); nsTextEvent* oldTextEvent = static_cast<nsTextEvent*>(mEvent);
nsTextEvent* textEvent = new nsTextEvent(false, msg, nullptr); nsTextEvent* textEvent = new nsTextEvent(false, msg, nullptr);
textEvent->AssignGUIEventData(*oldTextEvent, true); textEvent->AssignTextEventData(*oldTextEvent, true);
newEvent = textEvent; newEvent = textEvent;
break; break;
} }
@ -606,8 +585,7 @@ nsDOMEvent::DuplicatePrivateData()
new nsCompositionEvent(false, msg, nullptr); new nsCompositionEvent(false, msg, nullptr);
nsCompositionEvent* oldCompositionEvent = nsCompositionEvent* oldCompositionEvent =
static_cast<nsCompositionEvent*>(mEvent); static_cast<nsCompositionEvent*>(mEvent);
compositionEvent->AssignGUIEventData(*oldCompositionEvent, true); compositionEvent->AssignCompositionEventData(*oldCompositionEvent, true);
compositionEvent->data = oldCompositionEvent->data;
newEvent = compositionEvent; newEvent = compositionEvent;
break; break;
} }
@ -617,14 +595,7 @@ nsDOMEvent::DuplicatePrivateData()
static_cast<nsMouseScrollEvent*>(mEvent); static_cast<nsMouseScrollEvent*>(mEvent);
nsMouseScrollEvent* mouseScrollEvent = nsMouseScrollEvent* mouseScrollEvent =
new nsMouseScrollEvent(false, msg, nullptr); new nsMouseScrollEvent(false, msg, nullptr);
mouseScrollEvent->AssignInputEventData(*oldMouseScrollEvent, true); mouseScrollEvent->AssignMouseScrollEventData(*oldMouseScrollEvent, true);
mouseScrollEvent->isHorizontal = oldMouseScrollEvent->isHorizontal;
mouseScrollEvent->delta = oldMouseScrollEvent->delta;
mouseScrollEvent->relatedTarget = oldMouseScrollEvent->relatedTarget;
mouseScrollEvent->button = oldMouseScrollEvent->button;
mouseScrollEvent->buttons = oldMouseScrollEvent->buttons;
static_cast<nsMouseEvent_base*>(mouseScrollEvent)->inputSource =
static_cast<nsMouseEvent_base*>(oldMouseScrollEvent)->inputSource;
newEvent = mouseScrollEvent; newEvent = mouseScrollEvent;
break; break;
} }
@ -634,24 +605,7 @@ nsDOMEvent::DuplicatePrivateData()
static_cast<widget::WheelEvent*>(mEvent); static_cast<widget::WheelEvent*>(mEvent);
widget::WheelEvent* wheelEvent = widget::WheelEvent* wheelEvent =
new widget::WheelEvent(false, msg, nullptr); new widget::WheelEvent(false, msg, nullptr);
wheelEvent->AssignInputEventData(*oldWheelEvent, true); wheelEvent->AssignWheelEventData(*oldWheelEvent, true);
wheelEvent->deltaX = oldWheelEvent->deltaX;
wheelEvent->deltaY = oldWheelEvent->deltaY;
wheelEvent->deltaZ = oldWheelEvent->deltaZ;
wheelEvent->deltaMode = oldWheelEvent->deltaMode;
wheelEvent->relatedTarget = oldWheelEvent->relatedTarget;
wheelEvent->button = oldWheelEvent->button;
wheelEvent->buttons = oldWheelEvent->buttons;
wheelEvent->modifiers = oldWheelEvent->modifiers;
wheelEvent->inputSource = oldWheelEvent->inputSource;
wheelEvent->customizedByUserPrefs = oldWheelEvent->customizedByUserPrefs;
wheelEvent->isMomentum = oldWheelEvent->isMomentum;
wheelEvent->isPixelOnlyDevice = oldWheelEvent->isPixelOnlyDevice;
wheelEvent->lineOrPageDeltaX = oldWheelEvent->lineOrPageDeltaX;
wheelEvent->lineOrPageDeltaY = oldWheelEvent->lineOrPageDeltaY;
wheelEvent->scrollType = oldWheelEvent->scrollType;
wheelEvent->overflowDeltaX = oldWheelEvent->overflowDeltaX;
wheelEvent->overflowDeltaY = oldWheelEvent->overflowDeltaY;
newEvent = wheelEvent; newEvent = wheelEvent;
break; break;
} }
@ -661,8 +615,7 @@ nsDOMEvent::DuplicatePrivateData()
static_cast<nsScrollPortEvent*>(mEvent); static_cast<nsScrollPortEvent*>(mEvent);
nsScrollPortEvent* scrollPortEvent = nsScrollPortEvent* scrollPortEvent =
new nsScrollPortEvent(false, msg, nullptr); new nsScrollPortEvent(false, msg, nullptr);
scrollPortEvent->AssignGUIEventData(*oldScrollPortEvent, true); scrollPortEvent->AssignScrollPortEventData(*oldScrollPortEvent, true);
scrollPortEvent->orient = oldScrollPortEvent->orient;
newEvent = scrollPortEvent; newEvent = scrollPortEvent;
break; break;
} }
@ -672,8 +625,7 @@ nsDOMEvent::DuplicatePrivateData()
static_cast<nsScrollAreaEvent*>(mEvent); static_cast<nsScrollAreaEvent*>(mEvent);
nsScrollAreaEvent* scrollAreaEvent = nsScrollAreaEvent* scrollAreaEvent =
new nsScrollAreaEvent(false, msg, nullptr); new nsScrollAreaEvent(false, msg, nullptr);
scrollAreaEvent->AssignGUIEventData(*oldScrollAreaEvent, true); scrollAreaEvent->AssignScrollAreaEventData(*oldScrollAreaEvent, true);
scrollAreaEvent->mArea = oldScrollAreaEvent->mArea;
newEvent = scrollAreaEvent; newEvent = scrollAreaEvent;
break; break;
} }
@ -682,12 +634,7 @@ nsDOMEvent::DuplicatePrivateData()
nsMutationEvent* mutationEvent = new nsMutationEvent(false, msg); nsMutationEvent* mutationEvent = new nsMutationEvent(false, msg);
nsMutationEvent* oldMutationEvent = nsMutationEvent* oldMutationEvent =
static_cast<nsMutationEvent*>(mEvent); static_cast<nsMutationEvent*>(mEvent);
mutationEvent->AssignEventData(*oldMutationEvent, true); mutationEvent->AssignMutationEventData(*oldMutationEvent, true);
mutationEvent->mRelatedNode = oldMutationEvent->mRelatedNode;
mutationEvent->mAttrName = oldMutationEvent->mAttrName;
mutationEvent->mPrevAttrValue = oldMutationEvent->mPrevAttrValue;
mutationEvent->mNewAttrValue = oldMutationEvent->mNewAttrValue;
mutationEvent->mAttrChange = oldMutationEvent->mAttrChange;
newEvent = mutationEvent; newEvent = mutationEvent;
break; break;
} }
@ -695,7 +642,7 @@ nsDOMEvent::DuplicatePrivateData()
{ {
nsFormEvent* oldFormEvent = static_cast<nsFormEvent*>(mEvent); nsFormEvent* oldFormEvent = static_cast<nsFormEvent*>(mEvent);
nsFormEvent* formEvent = new nsFormEvent(false, msg); nsFormEvent* formEvent = new nsFormEvent(false, msg);
formEvent->AssignEventData(*oldFormEvent, true); formEvent->AssignFormEventData(*oldFormEvent, true);
newEvent = formEvent; newEvent = formEvent;
break; break;
} }
@ -703,9 +650,7 @@ nsDOMEvent::DuplicatePrivateData()
{ {
nsFocusEvent* newFocusEvent = new nsFocusEvent(false, msg); nsFocusEvent* newFocusEvent = new nsFocusEvent(false, msg);
nsFocusEvent* oldFocusEvent = static_cast<nsFocusEvent*>(mEvent); nsFocusEvent* oldFocusEvent = static_cast<nsFocusEvent*>(mEvent);
newFocusEvent->AssignGUIEventData(*oldFocusEvent, true); newFocusEvent->AssignFocusEventData(*oldFocusEvent, true);
newFocusEvent->fromRaise = oldFocusEvent->fromRaise;
newFocusEvent->isRefocus = oldFocusEvent->isRefocus;
newEvent = newFocusEvent; newEvent = newFocusEvent;
break; break;
} }
@ -715,7 +660,7 @@ nsDOMEvent::DuplicatePrivateData()
nsCommandEvent* commandEvent = nsCommandEvent* commandEvent =
new nsCommandEvent(false, mEvent->userType, new nsCommandEvent(false, mEvent->userType,
oldCommandEvent->command, nullptr); oldCommandEvent->command, nullptr);
commandEvent->AssignGUIEventData(*oldCommandEvent, true); commandEvent->AssignCommandEventData(*oldCommandEvent, true);
newEvent = commandEvent; newEvent = commandEvent;
break; break;
} }
@ -723,7 +668,7 @@ nsDOMEvent::DuplicatePrivateData()
{ {
nsUIEvent* oldUIEvent = static_cast<nsUIEvent*>(mEvent); nsUIEvent* oldUIEvent = static_cast<nsUIEvent*>(mEvent);
nsUIEvent* uiEvent = new nsUIEvent(false, msg, oldUIEvent->detail); nsUIEvent* uiEvent = new nsUIEvent(false, msg, oldUIEvent->detail);
uiEvent->AssignEventData(*oldUIEvent, true); uiEvent->AssignUIEventData(*oldUIEvent, true);
newEvent = uiEvent; newEvent = uiEvent;
break; break;
} }
@ -741,7 +686,7 @@ nsDOMEvent::DuplicatePrivateData()
nsUIEvent* oldUIEvent = static_cast<nsUIEvent*>(mEvent); nsUIEvent* oldUIEvent = static_cast<nsUIEvent*>(mEvent);
nsUIEvent* uiEvent = new nsUIEvent(false, msg, 0); nsUIEvent* uiEvent = new nsUIEvent(false, msg, 0);
uiEvent->eventStructType = NS_SMIL_TIME_EVENT; uiEvent->eventStructType = NS_SMIL_TIME_EVENT;
uiEvent->AssignGUIEventData(*oldUIEvent, true); uiEvent->AssignUIEventData(*oldUIEvent, true);
newEvent = uiEvent; newEvent = uiEvent;
break; break;
} }
@ -751,10 +696,8 @@ nsDOMEvent::DuplicatePrivateData()
static_cast<nsSimpleGestureEvent*>(mEvent); static_cast<nsSimpleGestureEvent*>(mEvent);
nsSimpleGestureEvent* simpleGestureEvent = nsSimpleGestureEvent* simpleGestureEvent =
new nsSimpleGestureEvent(false, msg, nullptr, 0, 0.0); new nsSimpleGestureEvent(false, msg, nullptr, 0, 0.0);
simpleGestureEvent->AssignInputEventData(*oldSimpleGestureEvent, true); simpleGestureEvent->
simpleGestureEvent->direction = oldSimpleGestureEvent->direction; AssignSimpleGestureEventData(*oldSimpleGestureEvent, true);
simpleGestureEvent->delta = oldSimpleGestureEvent->delta;
simpleGestureEvent->clickCount = oldSimpleGestureEvent->clickCount;
newEvent = simpleGestureEvent; newEvent = simpleGestureEvent;
break; break;
} }
@ -767,7 +710,7 @@ nsDOMEvent::DuplicatePrivateData()
oldTransitionEvent->propertyName, oldTransitionEvent->propertyName,
oldTransitionEvent->elapsedTime, oldTransitionEvent->elapsedTime,
oldTransitionEvent->pseudoElement); oldTransitionEvent->pseudoElement);
transitionEvent->AssignEventData(*oldTransitionEvent, true); transitionEvent->AssignTransitionEventData(*oldTransitionEvent, true);
newEvent = transitionEvent; newEvent = transitionEvent;
break; break;
} }
@ -780,7 +723,7 @@ nsDOMEvent::DuplicatePrivateData()
oldAnimationEvent->animationName, oldAnimationEvent->animationName,
oldAnimationEvent->elapsedTime, oldAnimationEvent->elapsedTime,
oldAnimationEvent->pseudoElement); oldAnimationEvent->pseudoElement);
animationEvent->AssignEventData(*oldAnimationEvent, true); animationEvent->AssignAnimationEventData(*oldAnimationEvent, true);
newEvent = animationEvent; newEvent = animationEvent;
break; break;
} }
@ -788,7 +731,7 @@ nsDOMEvent::DuplicatePrivateData()
{ {
nsTouchEvent* oldTouchEvent = static_cast<nsTouchEvent*>(mEvent); nsTouchEvent* oldTouchEvent = static_cast<nsTouchEvent*>(mEvent);
nsTouchEvent* touchEvent = new nsTouchEvent(false, oldTouchEvent); nsTouchEvent* touchEvent = new nsTouchEvent(false, oldTouchEvent);
touchEvent->AssignInputEventData(*oldTouchEvent, true); touchEvent->AssignTouchEventData(*oldTouchEvent, true);
newEvent = touchEvent; newEvent = touchEvent;
break; break;
} }

View File

@ -460,6 +460,9 @@ nsDOMUIEvent::ComputeModifierState(const nsAString& aModifiersList)
bool bool
nsDOMUIEvent::GetModifierStateInternal(const nsAString& aKey) nsDOMUIEvent::GetModifierStateInternal(const nsAString& aKey)
{ {
if (!NS_IS_INPUT_EVENT(mEvent)) {
MOZ_CRASH("mEvent must be nsInputEvent or derived class");
}
nsInputEvent* inputEvent = static_cast<nsInputEvent*>(mEvent); nsInputEvent* inputEvent = static_cast<nsInputEvent*>(mEvent);
if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SHIFT)) { if (aKey.EqualsLiteral(NS_DOM_KEYNAME_SHIFT)) {
return inputEvent->IsShift(); return inputEvent->IsShift();

View File

@ -444,11 +444,8 @@ PannerNodeEngine::ComputeConeGain()
ThreeDPoint sourceToListener = mListenerPosition - mPosition; ThreeDPoint sourceToListener = mListenerPosition - mPosition;
sourceToListener.Normalize(); sourceToListener.Normalize();
ThreeDPoint normalizedSourceOrientation = mOrientation;
normalizedSourceOrientation.Normalize();
// Angle between the source orientation vector and the source-listener vector // Angle between the source orientation vector and the source-listener vector
double dotProduct = sourceToListener.DotProduct(normalizedSourceOrientation); double dotProduct = sourceToListener.DotProduct(mOrientation);
double angle = 180 * acos(dotProduct) / M_PI; double angle = 180 * acos(dotProduct) / M_PI;
double absAngle = fabs(angle); double absAngle = fabs(angle);

View File

@ -0,0 +1,245 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/XPathEvaluator.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsXPathExpression.h"
#include "nsXPathNSResolver.h"
#include "nsXPathResult.h"
#include "nsContentCID.h"
#include "txExpr.h"
#include "txExprParser.h"
#include "nsError.h"
#include "txURIUtils.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsDOMString.h"
#include "nsINameSpaceManager.h"
#include "nsContentUtils.h"
#include "mozilla/dom/XPathEvaluatorBinding.h"
extern nsresult
TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID,
nsIAtom *aName, nsISupports *aState,
FunctionCall **aFunction);
namespace mozilla {
namespace dom {
// txIParseContext implementation
class XPathEvaluatorParseContext : public txIParseContext
{
public:
XPathEvaluatorParseContext(nsIDOMXPathNSResolver* aResolver,
bool aIsCaseSensitive)
: mResolver(aResolver),
mLastError(NS_OK),
mIsCaseSensitive(aIsCaseSensitive)
{
}
nsresult getError()
{
return mLastError;
}
nsresult resolveNamespacePrefix(nsIAtom* aPrefix, int32_t& aID);
nsresult resolveFunctionCall(nsIAtom* aName, int32_t aID,
FunctionCall** aFunction);
bool caseInsensitiveNameTests();
void SetErrorOffset(uint32_t aOffset);
private:
nsIDOMXPathNSResolver* mResolver;
nsresult mLastError;
bool mIsCaseSensitive;
};
NS_IMPL_ISUPPORTS1(XPathEvaluator, nsIDOMXPathEvaluator)
XPathEvaluator::XPathEvaluator(nsIDocument* aDocument)
: mDocument(do_GetWeakReference(aDocument))
{
}
NS_IMETHODIMP
XPathEvaluator::CreateNSResolver(nsIDOMNode *aNodeResolver,
nsIDOMXPathNSResolver **aResult)
{
NS_ENSURE_ARG(aNodeResolver);
if (!nsContentUtils::CanCallerAccess(aNodeResolver))
return NS_ERROR_DOM_SECURITY_ERR;
*aResult = new nsXPathNSResolver(aNodeResolver);
NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*aResult);
return NS_OK;
}
NS_IMETHODIMP
XPathEvaluator::Evaluate(const nsAString & aExpression,
nsIDOMNode *aContextNode,
nsIDOMXPathNSResolver *aResolver,
uint16_t aType,
nsISupports *aInResult,
nsISupports **aResult)
{
nsCOMPtr<nsIDOMXPathExpression> expression;
nsresult rv = CreateExpression(aExpression, aResolver,
getter_AddRefs(expression));
NS_ENSURE_SUCCESS(rv, rv);
return expression->Evaluate(aContextNode, aType, aInResult, aResult);
}
NS_IMETHODIMP
XPathEvaluator::CreateExpression(const nsAString & aExpression,
nsIDOMXPathNSResolver *aResolver,
nsIDOMXPathExpression **aResult)
{
nsresult rv;
if (!mRecycler) {
nsRefPtr<txResultRecycler> recycler = new txResultRecycler;
NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY);
rv = recycler->init();
NS_ENSURE_SUCCESS(rv, rv);
mRecycler = recycler;
}
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
XPathEvaluatorParseContext pContext(aResolver, !(doc && doc->IsHTML()));
nsAutoPtr<Expr> expression;
rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext,
getter_Transfers(expression));
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_NAMESPACE_ERR) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
return NS_ERROR_DOM_INVALID_EXPRESSION_ERR;
}
nsCOMPtr<nsIDOMDocument> document = do_QueryReferent(mDocument);
*aResult = new nsXPathExpression(expression, mRecycler, document);
if (!*aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aResult);
return NS_OK;
}
JSObject*
XPathEvaluator::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return dom::XPathEvaluatorBinding::Wrap(aCx, aScope, this);
}
/* static */
already_AddRefed<XPathEvaluator>
XPathEvaluator::Constructor(const GlobalObject& aGlobal,
ErrorResult& rv)
{
nsRefPtr<XPathEvaluator> newObj = new XPathEvaluator(nullptr);
return newObj.forget();
}
already_AddRefed<nsIDOMXPathExpression>
XPathEvaluator::CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
ErrorResult& rv)
{
nsCOMPtr<nsIDOMXPathExpression> expr;
rv = CreateExpression(aExpression, aResolver, getter_AddRefs(expr));
return expr.forget();
}
already_AddRefed<nsIDOMXPathNSResolver>
XPathEvaluator::CreateNSResolver(nsINode* aNodeResolver,
ErrorResult& rv)
{
nsCOMPtr<nsIDOMNode> nodeResolver = do_QueryInterface(aNodeResolver);
nsCOMPtr<nsIDOMXPathNSResolver> res;
rv = CreateNSResolver(nodeResolver, getter_AddRefs(res));
return res.forget();
}
already_AddRefed<nsISupports>
XPathEvaluator::Evaluate(const nsAString& aExpression, nsINode* aContextNode,
nsIDOMXPathNSResolver* aResolver, uint16_t aType,
nsISupports* aResult, ErrorResult& rv)
{
nsCOMPtr<nsIDOMNode> contextNode = do_QueryInterface(aContextNode);
nsCOMPtr<nsISupports> res;
rv = Evaluate(aExpression, contextNode, aResolver, aType,
aResult, getter_AddRefs(res));
return res.forget();
}
/*
* Implementation of txIParseContext private to XPathEvaluator, based on a
* nsIDOMXPathNSResolver
*/
nsresult XPathEvaluatorParseContext::resolveNamespacePrefix
(nsIAtom* aPrefix, int32_t& aID)
{
aID = kNameSpaceID_Unknown;
if (!mResolver) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
nsAutoString prefix;
if (aPrefix) {
aPrefix->ToString(prefix);
}
nsVoidableString ns;
nsresult rv = mResolver->LookupNamespaceURI(prefix, ns);
NS_ENSURE_SUCCESS(rv, rv);
if (DOMStringIsNull(ns)) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
if (ns.IsEmpty()) {
aID = kNameSpaceID_None;
return NS_OK;
}
// get the namespaceID for the URI
return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID);
}
nsresult
XPathEvaluatorParseContext::resolveFunctionCall(nsIAtom* aName,
int32_t aID,
FunctionCall** aFn)
{
return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
}
bool XPathEvaluatorParseContext::caseInsensitiveNameTests()
{
return !mIsCaseSensitive;
}
void
XPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset)
{
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef mozilla_dom_XPathEvaluator_h
#define mozilla_dom_XPathEvaluator_h
#include "nsIDOMXPathEvaluator.h"
#include "nsIWeakReference.h"
#include "nsAutoPtr.h"
#include "nsString.h"
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsIDocument.h"
class nsINode;
class txResultRecycler;
namespace mozilla {
namespace dom {
class GlobalObject;
/**
* A class for evaluating an XPath expression string
*/
class XPathEvaluator MOZ_FINAL : public nsIDOMXPathEvaluator
{
public:
XPathEvaluator(nsIDocument* aDocument = nullptr);
NS_DECL_ISUPPORTS
// nsIDOMXPathEvaluator interface
NS_DECL_NSIDOMXPATHEVALUATOR
// WebIDL API
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope);
already_AddRefed<nsIDocument> GetParentObject()
{
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
return doc.forget();
}
static already_AddRefed<XPathEvaluator>
Constructor(const GlobalObject& aGlobal, ErrorResult& rv);
already_AddRefed<nsIDOMXPathExpression>
CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
ErrorResult& rv);
already_AddRefed<nsIDOMXPathNSResolver>
CreateNSResolver(nsINode* aNodeResolver, ErrorResult& rv);
already_AddRefed<nsISupports>
Evaluate(const nsAString& aExpression, nsINode* aContextNode,
nsIDOMXPathNSResolver* aResolver, uint16_t aType,
nsISupports* aResult, ErrorResult& rv);
private:
nsWeakPtr mDocument;
nsRefPtr<txResultRecycler> mRecycler;
};
inline nsISupports*
ToSupports(XPathEvaluator* e)
{
return static_cast<nsIDOMXPathEvaluator*>(e);
}
/* d0a75e02-b5e7-11d5-a7f2-df109fb8a1fc */
#define TRANSFORMIIX_XPATH_EVALUATOR_CID \
{ 0xd0a75e02, 0xb5e7, 0x11d5, { 0xa7, 0xf2, 0xdf, 0x10, 0x9f, 0xb8, 0xa1, 0xfc } }
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_XPathEvaluator_h */

View File

@ -6,8 +6,12 @@
MODULE = 'transformiix' MODULE = 'transformiix'
EXPORTS.mozilla.dom += [
'XPathEvaluator.h',
]
CPP_SOURCES += [ CPP_SOURCES += [
'nsXPathEvaluator.cpp', 'XPathEvaluator.cpp',
'nsXPathExpression.cpp', 'nsXPathExpression.cpp',
'nsXPathNSResolver.cpp', 'nsXPathNSResolver.cpp',
'nsXPathResult.cpp', 'nsXPathResult.cpp',

View File

@ -1,337 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsXPathEvaluator.h"
#include "nsCOMPtr.h"
#include "nsIAtom.h"
#include "nsXPathExpression.h"
#include "nsXPathNSResolver.h"
#include "nsXPathResult.h"
#include "nsContentCID.h"
#include "txExpr.h"
#include "txExprParser.h"
#include "nsError.h"
#include "txURIUtils.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsDOMString.h"
#include "nsINameSpaceManager.h"
#include "nsContentUtils.h"
#include "mozilla/dom/XPathEvaluatorBinding.h"
using namespace mozilla;
using namespace mozilla::dom;
// txIParseContext implementation
class nsXPathEvaluatorParseContext : public txIParseContext
{
public:
nsXPathEvaluatorParseContext(nsIDOMXPathNSResolver* aResolver,
nsTArray<int32_t> *aNamespaceIDs,
nsTArray<nsCString> *aContractIDs,
nsCOMArray<nsISupports> *aState,
bool aIsCaseSensitive)
: mResolver(aResolver),
mNamespaceIDs(aNamespaceIDs),
mContractIDs(aContractIDs),
mState(aState),
mLastError(NS_OK),
mIsCaseSensitive(aIsCaseSensitive)
{
NS_ASSERTION(mContractIDs ||
(!mNamespaceIDs || mNamespaceIDs->Length() == 0),
"Need contract IDs if there are namespaces.");
}
nsresult getError()
{
return mLastError;
}
nsresult resolveNamespacePrefix(nsIAtom* aPrefix, int32_t& aID);
nsresult resolveFunctionCall(nsIAtom* aName, int32_t aID,
FunctionCall** aFunction);
bool caseInsensitiveNameTests();
void SetErrorOffset(uint32_t aOffset);
private:
nsIDOMXPathNSResolver* mResolver;
nsTArray<int32_t> *mNamespaceIDs;
nsTArray<nsCString> *mContractIDs;
nsCOMArray<nsISupports> *mState;
nsresult mLastError;
bool mIsCaseSensitive;
};
NS_IMPL_AGGREGATED(nsXPathEvaluator)
NS_INTERFACE_MAP_BEGIN_AGGREGATED(nsXPathEvaluator)
NS_INTERFACE_MAP_ENTRY(nsIDOMXPathEvaluator)
NS_INTERFACE_MAP_ENTRY(nsIXPathEvaluatorInternal)
NS_INTERFACE_MAP_END
nsXPathEvaluator::nsXPathEvaluator(nsISupports *aOuter)
{
NS_INIT_AGGREGATED(aOuter);
}
nsresult
nsXPathEvaluator::Init()
{
nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(fOuter);
return document ? SetDocument(document) : NS_OK;
}
NS_IMETHODIMP
nsXPathEvaluator::CreateExpression(const nsAString & aExpression,
nsIDOMXPathNSResolver *aResolver,
nsIDOMXPathExpression **aResult)
{
return CreateExpression(aExpression, aResolver, (nsTArray<int32_t>*)nullptr,
nullptr, nullptr, aResult);
}
NS_IMETHODIMP
nsXPathEvaluator::CreateNSResolver(nsIDOMNode *aNodeResolver,
nsIDOMXPathNSResolver **aResult)
{
NS_ENSURE_ARG(aNodeResolver);
if (!nsContentUtils::CanCallerAccess(aNodeResolver))
return NS_ERROR_DOM_SECURITY_ERR;
*aResult = new nsXPathNSResolver(aNodeResolver);
NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*aResult);
return NS_OK;
}
NS_IMETHODIMP
nsXPathEvaluator::Evaluate(const nsAString & aExpression,
nsIDOMNode *aContextNode,
nsIDOMXPathNSResolver *aResolver,
uint16_t aType,
nsISupports *aInResult,
nsISupports **aResult)
{
nsCOMPtr<nsIDOMXPathExpression> expression;
nsresult rv = CreateExpression(aExpression, aResolver,
getter_AddRefs(expression));
NS_ENSURE_SUCCESS(rv, rv);
return expression->Evaluate(aContextNode, aType, aInResult, aResult);
}
NS_IMETHODIMP
nsXPathEvaluator::SetDocument(nsIDOMDocument* aDocument)
{
mDocument = do_GetWeakReference(aDocument);
return NS_OK;
}
NS_IMETHODIMP
nsXPathEvaluator::CreateExpression(const nsAString & aExpression,
nsIDOMXPathNSResolver *aResolver,
nsTArray<nsString> *aNamespaceURIs,
nsTArray<nsCString> *aContractIDs,
nsCOMArray<nsISupports> *aState,
nsIDOMXPathExpression **aResult)
{
nsTArray<int32_t> namespaceIDs;
if (aNamespaceURIs) {
uint32_t count = aNamespaceURIs->Length();
if (!aContractIDs || aContractIDs->Length() != count) {
return NS_ERROR_FAILURE;
}
if (!namespaceIDs.SetLength(count)) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t i;
for (i = 0; i < count; ++i) {
if (aContractIDs->ElementAt(i).IsEmpty()) {
return NS_ERROR_FAILURE;
}
nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURIs->ElementAt(i), namespaceIDs[i]);
}
}
return CreateExpression(aExpression, aResolver, &namespaceIDs, aContractIDs,
aState, aResult);
}
nsresult
nsXPathEvaluator::CreateExpression(const nsAString & aExpression,
nsIDOMXPathNSResolver *aResolver,
nsTArray<int32_t> *aNamespaceIDs,
nsTArray<nsCString> *aContractIDs,
nsCOMArray<nsISupports> *aState,
nsIDOMXPathExpression **aResult)
{
nsresult rv;
if (!mRecycler) {
nsRefPtr<txResultRecycler> recycler = new txResultRecycler;
NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY);
rv = recycler->init();
NS_ENSURE_SUCCESS(rv, rv);
mRecycler = recycler;
}
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
nsXPathEvaluatorParseContext pContext(aResolver, aNamespaceIDs,
aContractIDs, aState,
!(doc && doc->IsHTML()));
nsAutoPtr<Expr> expression;
rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext,
getter_Transfers(expression));
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_DOM_NAMESPACE_ERR) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
return NS_ERROR_DOM_INVALID_EXPRESSION_ERR;
}
nsCOMPtr<nsIDOMDocument> document = do_QueryReferent(mDocument);
*aResult = new nsXPathExpression(expression, mRecycler, document);
if (!*aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(*aResult);
return NS_OK;
}
JSObject*
nsXPathEvaluator::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return dom::XPathEvaluatorBinding::Wrap(aCx, aScope, this);
}
/* static */
already_AddRefed<nsXPathEvaluator>
nsXPathEvaluator::Constructor(const GlobalObject& aGlobal,
ErrorResult& rv)
{
nsRefPtr<nsXPathEvaluator> newObj = new nsXPathEvaluator(nullptr);
newObj->Init();
return newObj.forget();
}
already_AddRefed<nsIDOMXPathExpression>
nsXPathEvaluator::CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
ErrorResult& rv)
{
nsCOMPtr<nsIDOMXPathExpression> expr;
rv = CreateExpression(aExpression, aResolver, getter_AddRefs(expr));
return expr.forget();
}
already_AddRefed<nsIDOMXPathNSResolver>
nsXPathEvaluator::CreateNSResolver(nsINode* aNodeResolver,
ErrorResult& rv)
{
nsCOMPtr<nsIDOMNode> nodeResolver = do_QueryInterface(aNodeResolver);
nsCOMPtr<nsIDOMXPathNSResolver> res;
rv = CreateNSResolver(nodeResolver, getter_AddRefs(res));
return res.forget();
}
already_AddRefed<nsISupports>
nsXPathEvaluator::Evaluate(const nsAString& aExpression, nsINode* aContextNode,
nsIDOMXPathNSResolver* aResolver, uint16_t aType,
nsISupports* aResult, ErrorResult& rv)
{
nsCOMPtr<nsIDOMNode> contextNode = do_QueryInterface(aContextNode);
nsCOMPtr<nsISupports> res;
rv = Evaluate(aExpression, contextNode, aResolver, aType,
aResult, getter_AddRefs(res));
return res.forget();
}
/*
* Implementation of txIParseContext private to nsXPathEvaluator, based on a
* nsIDOMXPathNSResolver
*/
nsresult nsXPathEvaluatorParseContext::resolveNamespacePrefix
(nsIAtom* aPrefix, int32_t& aID)
{
aID = kNameSpaceID_Unknown;
if (!mResolver) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
nsAutoString prefix;
if (aPrefix) {
aPrefix->ToString(prefix);
}
nsVoidableString ns;
nsresult rv = mResolver->LookupNamespaceURI(prefix, ns);
NS_ENSURE_SUCCESS(rv, rv);
if (DOMStringIsNull(ns)) {
return NS_ERROR_DOM_NAMESPACE_ERR;
}
if (ns.IsEmpty()) {
aID = kNameSpaceID_None;
return NS_OK;
}
// get the namespaceID for the URI
return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID);
}
extern nsresult
TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID,
nsIAtom *aName, nsISupports *aState,
FunctionCall **aFunction);
nsresult
nsXPathEvaluatorParseContext::resolveFunctionCall(nsIAtom* aName,
int32_t aID,
FunctionCall** aFn)
{
nsresult rv = NS_ERROR_XPATH_UNKNOWN_FUNCTION;
uint32_t i, count = mNamespaceIDs ? mNamespaceIDs->Length() : 0;
for (i = 0; i < count; ++i) {
if (mNamespaceIDs->ElementAt(i) == aID) {
nsISupports *state = mState ? mState->SafeObjectAt(i) : nullptr;
rv = TX_ResolveFunctionCallXPCOM(mContractIDs->ElementAt(i), aID,
aName, state, aFn);
if (NS_SUCCEEDED(rv)) {
break;
}
}
}
return rv;
}
bool nsXPathEvaluatorParseContext::caseInsensitiveNameTests()
{
return !mIsCaseSensitive;
}
void
nsXPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset)
{
}

View File

@ -1,90 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#ifndef nsXPathEvaluator_h__
#define nsXPathEvaluator_h__
#include "nsIDOMXPathEvaluator.h"
#include "nsIXPathEvaluatorInternal.h"
#include "nsIWeakReference.h"
#include "nsAutoPtr.h"
#include "nsString.h"
#include "txResultRecycler.h"
#include "nsAgg.h"
#include "nsTArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
namespace mozilla {
namespace dom {
class GlobalObject;
}
}
class nsINode;
/**
* A class for evaluating an XPath expression string
*/
class nsXPathEvaluator MOZ_FINAL : public nsIDOMXPathEvaluator,
public nsIXPathEvaluatorInternal
{
public:
nsXPathEvaluator(nsISupports *aOuter);
nsresult Init();
// nsISupports interface (support aggregation)
NS_DECL_AGGREGATED
// nsIDOMXPathEvaluator interface
NS_DECL_NSIDOMXPATHEVALUATOR
// nsIXPathEvaluatorInternal interface
NS_IMETHOD SetDocument(nsIDOMDocument* aDocument) MOZ_OVERRIDE;
NS_IMETHOD CreateExpression(const nsAString &aExpression,
nsIDOMXPathNSResolver *aResolver,
nsTArray<nsString> *aNamespaceURIs,
nsTArray<nsCString> *aContractIDs,
nsCOMArray<nsISupports> *aState,
nsIDOMXPathExpression **aResult) MOZ_OVERRIDE;
// WebIDL API
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope);
static already_AddRefed<nsXPathEvaluator>
Constructor(const mozilla::dom::GlobalObject& aGlobal,
mozilla::ErrorResult& rv);
already_AddRefed<nsIDOMXPathExpression>
CreateExpression(const nsAString& aExpression,
nsIDOMXPathNSResolver* aResolver,
mozilla::ErrorResult& rv);
already_AddRefed<nsIDOMXPathNSResolver>
CreateNSResolver(nsINode* aNodeResolver, mozilla::ErrorResult& rv);
already_AddRefed<nsISupports>
Evaluate(const nsAString& aExpression, nsINode* aContextNode,
nsIDOMXPathNSResolver* aResolver, uint16_t aType,
nsISupports* aResult, mozilla::ErrorResult& rv);
private:
nsresult CreateExpression(const nsAString & aExpression,
nsIDOMXPathNSResolver *aResolver,
nsTArray<int32_t> *aNamespaceIDs,
nsTArray<nsCString> *aContractIDs,
nsCOMArray<nsISupports> *aState,
nsIDOMXPathExpression **aResult);
nsWeakPtr mDocument;
nsRefPtr<txResultRecycler> mRecycler;
};
inline nsISupports*
ToSupports(nsXPathEvaluator* e)
{
return static_cast<nsIDOMXPathEvaluator*>(e);
}
/* d0a75e02-b5e7-11d5-a7f2-df109fb8a1fc */
#define TRANSFORMIIX_XPATH_EVALUATOR_CID \
{ 0xd0a75e02, 0xb5e7, 0x11d5, { 0xa7, 0xf2, 0xdf, 0x10, 0x9f, 0xb8, 0xa1, 0xfc } }
#endif

View File

@ -3493,7 +3493,7 @@ XULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
// transcluded script completes. Compile and execute the script // transcluded script completes. Compile and execute the script
// if the load was successful, then continue building content // if the load was successful, then continue building content
// from the prototype. // from the prototype.
nsresult rv; nsresult rv = aStatus;
NS_ASSERTION(mCurrentScriptProto && mCurrentScriptProto->mSrcLoading, NS_ASSERTION(mCurrentScriptProto && mCurrentScriptProto->mSrcLoading,
"script source not loading on unichar stream complete?"); "script source not loading on unichar stream complete?");

View File

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MessageChannel.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/MessageChannelBinding.h"
#include "mozilla/dom/MessagePort.h"
#include "nsContentUtils.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(MessageChannel, mWindow, mPort1, mPort2)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
namespace {
bool gPrefInitialized = false;
bool gPrefEnabled = false;
}
/* static */ bool
MessageChannel::PrefEnabled()
{
if (!gPrefInitialized) {
Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled");
gPrefInitialized = true;
}
return gPrefEnabled;
}
MessageChannel::MessageChannel(nsPIDOMWindow* aWindow)
: mWindow(aWindow)
{
MOZ_COUNT_CTOR(MessageChannel);
SetIsDOMBinding();
mPort1 = new MessagePort(mWindow);
mPort2 = new MessagePort(mWindow);
mPort1->Entangle(mPort2);
mPort2->Entangle(mPort1);
}
MessageChannel::~MessageChannel()
{
MOZ_COUNT_DTOR(MessageChannel);
}
JSObject*
MessageChannel::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MessageChannelBinding::Wrap(aCx, aScope, this);
}
/* static */ already_AddRefed<MessageChannel>
MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<MessageChannel> channel = new MessageChannel(window);
return channel.forget();
}
} // namespace dom
} // namespace mozilla

72
dom/base/MessageChannel.h Normal file
View File

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_dom_MessageChannel_h
#define mozilla_dom_MessageChannel_h
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "nsCOMPtr.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class MessagePort;
class MessageChannel MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessageChannel)
static bool PrefEnabled();
public:
MessageChannel(nsPIDOMWindow* aWindow);
~MessageChannel();
nsPIDOMWindow*
GetParentObject() const
{
return mWindow;
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
static already_AddRefed<MessageChannel>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
MessagePort*
Port1() const
{
return mPort1;
}
MessagePort*
Port2() const
{
return mPort2;
}
private:
nsCOMPtr<nsPIDOMWindow> mWindow;
nsRefPtr<MessagePort> mPort1;
nsRefPtr<MessagePort> mPort2;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MessageChannel_h

476
dom/base/MessagePort.cpp Normal file
View File

@ -0,0 +1,476 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MessagePort.h"
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "nsGlobalWindow.h"
#include "nsContentUtils.h"
#include "nsEventDispatcher.h"
#include "nsPresContext.h"
#include "nsDOMEvent.h"
#include "nsIDocument.h"
#include "nsIDOMFile.h"
#include "nsIDOMFileList.h"
#include "nsIDOMMessageEvent.h"
#include "nsIPresShell.h"
namespace mozilla {
namespace dom {
class DispatchEventRunnable : public nsRunnable
{
friend class MessagePort;
public:
DispatchEventRunnable(MessagePort* aPort)
: mPort(aPort)
{
}
NS_IMETHOD
Run()
{
nsRefPtr<DispatchEventRunnable> mKungFuDeathGrip(this);
mPort->mDispatchRunnable = nullptr;
mPort->Dispatch();
return NS_OK;
}
private:
nsRefPtr<MessagePort> mPort;
};
class PostMessageRunnable : public nsRunnable
{
friend class MessagePort;
public:
NS_DECL_NSIRUNNABLE
PostMessageRunnable()
: mMessage(nullptr)
, mMessageLen(0)
{
}
~PostMessageRunnable()
{
// Ensure that the buffer is freed
if (mMessage) {
JSAutoStructuredCloneBuffer buffer;
buffer.adopt(mMessage, mMessageLen);
}
}
void SetJSData(JSAutoStructuredCloneBuffer& aBuffer)
{
NS_ASSERTION(!mMessage && mMessageLen == 0, "Don't call twice!");
aBuffer.steal(&mMessage, &mMessageLen);
}
bool StoreISupports(nsISupports* aSupports)
{
mSupportsArray.AppendElement(aSupports);
return true;
}
void Dispatch(MessagePort* aPort)
{
mPort = aPort;
NS_DispatchToCurrentThread(this);
}
private:
nsRefPtr<MessagePort> mPort;
uint64_t* mMessage;
size_t mMessageLen;
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
};
namespace {
struct StructuredCloneInfo
{
PostMessageRunnable* mEvent;
MessagePort* mPort;
};
static JSObject*
PostMessageReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader,
uint32_t tag,
uint32_t data,
void* closure)
{
NS_ASSERTION(closure, "Must have closure!");
if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
NS_ASSERTION(!data, "Data should be empty");
nsISupports* supports;
if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
if (global) {
JS::Rooted<JS::Value> val(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
val.address(),
getter_AddRefs(wrapper)))) {
return JSVAL_TO_OBJECT(val);
}
}
}
}
if (tag == SCTAG_DOM_MESSAGEPORT) {
NS_ASSERTION(!data, "Data should be empty");
MessagePort* port;
if (JS_ReadBytes(reader, &port, sizeof(port))) {
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
if (global) {
JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
if (JS_WrapObject(cx, obj.address())) {
return obj;
}
}
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
if (runtimeCallbacks) {
return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
}
return nullptr;
}
static bool
PostMessageWriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JS::Handle<JSObject*> obj,
void *closure)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
if (wrappedNative) {
uint32_t scTag = 0;
nsISupports* supports = wrappedNative->Native();
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
if (blob) {
scTag = SCTAG_DOM_BLOB;
}
nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
if (list) {
scTag = SCTAG_DOM_FILELIST;
}
if (scTag) {
return JS_WriteUint32Pair(writer, scTag, 0) &&
JS_WriteBytes(writer, &supports, sizeof(supports)) &&
scInfo->mEvent->StoreISupports(supports);
}
}
MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, cx, obj, port);
if (NS_SUCCEEDED(rv)) {
nsRefPtr<MessagePort> newPort = port->Clone(scInfo->mPort->GetOwner());
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
scInfo->mEvent->StoreISupports(newPort);
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
if (runtimeCallbacks) {
return runtimeCallbacks->write(cx, writer, obj, nullptr);
}
return false;
}
JSStructuredCloneCallbacks kPostMessageCallbacks = {
PostMessageReadStructuredClone,
PostMessageWriteStructuredClone,
nullptr
};
} // anonymous namespace
NS_IMETHODIMP
PostMessageRunnable::Run()
{
MOZ_ASSERT(mPort);
// Ensure that the buffer is freed even if we fail to post the message
JSAutoStructuredCloneBuffer buffer;
buffer.adopt(mMessage, mMessageLen);
mMessage = nullptr;
mMessageLen = 0;
// Get the JSContext for the target window
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(mPort->GetOwner());
NS_ENSURE_STATE(sgo);
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
: nsContentUtils::GetSafeJSContext());
MOZ_ASSERT(cx);
// Deserialize the structured clone data
JS::Rooted<JS::Value> messageData(cx);
{
StructuredCloneInfo scInfo;
scInfo.mEvent = this;
scInfo.mPort = mPort;
if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks,
&scInfo)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
}
// Create the event
nsIDocument* doc = mPort->GetOwner()->GetExtantDoc();
if (!doc) {
return NS_OK;
}
ErrorResult error;
nsRefPtr<nsDOMEvent> event =
doc->CreateEvent(NS_LITERAL_STRING("MessageEvent"), error);
if (error.Failed()) {
return NS_OK;
}
nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
false /* non-bubbling */,
true /* cancelable */,
messageData,
EmptyString(),
EmptyString(),
mPort->GetOwner());
if (NS_FAILED(rv)) {
return NS_OK;
}
message->SetTrusted(true);
bool status;
mPort->DispatchEvent(event, &status);
return status ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEntangledPort)
// Custom unlink loop because this array contains nsRunnable objects
// which are not cycle colleactable.
while (!tmp->mMessageQueue.IsEmpty()) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mPort);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mSupportsArray);
tmp->mMessageQueue.RemoveElementAt(0);
}
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEntangledPort)
// Custom unlink loop because this array contains nsRunnable objects
// which are not cycle colleactable.
for (uint32_t i = 0, len = tmp->mMessageQueue.Length(); i < len; ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mPort);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mSupportsArray);
}
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(MessagePort, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MessagePort, nsDOMEventTargetHelper)
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
: nsDOMEventTargetHelper(aWindow)
, mMessageQueueEnabled(false)
{
MOZ_COUNT_CTOR(MessagePort);
SetIsDOMBinding();
}
MessagePort::~MessagePort()
{
MOZ_COUNT_DTOR(MessagePort);
Close();
}
JSObject*
MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MessagePortBinding::Wrap(aCx, aScope, this);
}
void
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<JS::Handle<JS::Value> >& aTransfer,
ErrorResult& aRv)
{
nsRefPtr<PostMessageRunnable> event = new PostMessageRunnable();
// We *must* clone the data here, or the JS::Value could be modified
// by script
JSAutoStructuredCloneBuffer buffer;
StructuredCloneInfo scInfo;
scInfo.mEvent = event;
scInfo.mPort = this;
JS::Handle<JS::Value> transferable = aTransfer.WasPassed()
? aTransfer.Value()
: JS::UndefinedHandleValue;
if (!buffer.write(aCx, aMessage, transferable, &kPostMessageCallbacks,
&scInfo)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
event->SetJSData(buffer);
if (!mEntangledPort) {
return;
}
mEntangledPort->mMessageQueue.AppendElement(event);
mEntangledPort->Dispatch();
}
void
MessagePort::Start()
{
if (mMessageQueueEnabled) {
return;
}
mMessageQueueEnabled = true;
Dispatch();
}
void
MessagePort::Dispatch()
{
if (!mMessageQueueEnabled || mMessageQueue.IsEmpty() || mDispatchRunnable) {
return;
}
nsRefPtr<PostMessageRunnable> event = mMessageQueue.ElementAt(0);
mMessageQueue.RemoveElementAt(0);
event->Dispatch(this);
mDispatchRunnable = new DispatchEventRunnable(this);
NS_DispatchToCurrentThread(mDispatchRunnable);
}
void
MessagePort::Close()
{
if (!mEntangledPort) {
return;
}
// This avoids loops.
nsRefPtr<MessagePort> port = mEntangledPort;
mEntangledPort = nullptr;
// Let's disentangle the 2 ports symmetrically.
port->Close();
}
EventHandlerNonNull*
MessagePort::GetOnmessage()
{
if (NS_IsMainThread()) {
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
}
return GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
}
void
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback, ErrorResult& aRv)
{
if (NS_IsMainThread()) {
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback, aRv);
} else {
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback, aRv);
}
// When using onmessage, the call to start() is implied.
Start();
}
void
MessagePort::Entangle(MessagePort* aMessagePort)
{
MOZ_ASSERT(aMessagePort);
MOZ_ASSERT(aMessagePort != this);
Close();
mEntangledPort = aMessagePort;
}
already_AddRefed<MessagePort>
MessagePort::Clone(nsPIDOMWindow* aWindow)
{
nsRefPtr<MessagePort> newPort = new MessagePort(aWindow->GetCurrentInnerWindow());
// Move all the events in the port message queue of original port.
newPort->mMessageQueue.SwapElements(mMessageQueue);
if (mEntangledPort) {
nsRefPtr<MessagePort> port = mEntangledPort;
mEntangledPort = nullptr;
newPort->Entangle(port);
port->Entangle(newPort);
}
return newPort.forget();
}
} // namespace dom
} // namespace mozilla

86
dom/base/MessagePort.h Normal file
View File

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_dom_MessagePort_h
#define mozilla_dom_MessagePort_h
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsDOMEventTargetHelper.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class DispatchEventRunnable;
class PostMessageRunnable;
class MessagePort MOZ_FINAL : public nsDOMEventTargetHelper
{
friend class DispatchEventRunnable;
friend class PostMessageRunnable;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
nsDOMEventTargetHelper)
MessagePort(nsPIDOMWindow* aWindow);
~MessagePort();
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<JS::Handle<JS::Value> >& aTransfer,
ErrorResult& aRv);
void
Start();
void
Close();
// The 'message' event handler has to call |Start()| method, so we
// cannot use IMPL_EVENT_HANDLER macro here.
EventHandlerNonNull*
GetOnmessage();
void
SetOnmessage(EventHandlerNonNull* aCallback, ErrorResult& aRv);
// Non WebIDL methods
// This method entangles this MessagePort with another one.
// If it is already entangled, it's disentangled first and enatangle to the
// new one.
void
Entangle(MessagePort* aMessagePort);
// Duplicate this message port. This method is used by the Structured Clone
// Algorithm and makes the new MessagePort active with the entangled
// MessagePort of this object.
already_AddRefed<MessagePort>
Clone(nsPIDOMWindow* aWindow);
private:
// Dispatch events from the Message Queue using a nsRunnable.
void Dispatch();
nsRefPtr<DispatchEventRunnable> mDispatchRunnable;
nsRefPtr<MessagePort> mEntangledPort;
nsTArray<nsRefPtr<PostMessageRunnable> > mMessageQueue;
bool mMessageQueueEnabled;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MessagePort_h

View File

@ -28,6 +28,7 @@ enum StructuredCloneTags {
// These tags are used for both main thread and workers. // These tags are used for both main thread and workers.
SCTAG_DOM_IMAGEDATA, SCTAG_DOM_IMAGEDATA,
SCTAG_DOM_MESSAGEPORT,
SCTAG_DOM_MAX SCTAG_DOM_MAX
}; };

View File

@ -55,6 +55,8 @@ EXPORTS.mozilla.dom += [
'DOMCursor.h', 'DOMCursor.h',
'DOMError.h', 'DOMError.h',
'DOMRequest.h', 'DOMRequest.h',
'MessageChannel.h',
'MessagePort.h',
'ScreenOrientation.h', 'ScreenOrientation.h',
'StructuredCloneTags.h', 'StructuredCloneTags.h',
'URL.h', 'URL.h',
@ -67,6 +69,8 @@ CPP_SOURCES += [
'DOMError.cpp', 'DOMError.cpp',
'DOMRequest.cpp', 'DOMRequest.cpp',
'Navigator.cpp', 'Navigator.cpp',
'MessageChannel.cpp',
'MessagePort.cpp',
'nsContentPermissionHelper.cpp', 'nsContentPermissionHelper.cpp',
'nsDOMClassInfo.cpp', 'nsDOMClassInfo.cpp',
'nsDOMException.cpp', 'nsDOMException.cpp',

View File

@ -189,6 +189,9 @@
#include "prenv.h" #include "prenv.h"
#include "prprf.h" #include "prprf.h"
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/indexedDB/IDBFactory.h" #include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/dom/quota/QuotaManager.h"
@ -6750,6 +6753,7 @@ namespace {
struct StructuredCloneInfo { struct StructuredCloneInfo {
PostMessageEvent* event; PostMessageEvent* event;
bool subsumes; bool subsumes;
nsPIDOMWindow* window;
}; };
static JSObject* static JSObject*
@ -6779,6 +6783,21 @@ PostMessageReadStructuredClone(JSContext* cx,
} }
} }
if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MESSAGEPORT) {
NS_ASSERTION(!data, "Data should be empty");
MessagePort* port;
if (JS_ReadBytes(reader, &port, sizeof(port))) {
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
if (global) {
JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
if (JS_WrapObject(cx, obj.address())) {
return obj;
}
}
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks = const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx); js::GetContextStructuredCloneCallbacks(cx);
@ -6819,6 +6838,18 @@ PostMessageWriteStructuredClone(JSContext* cx,
scInfo->event->StoreISupports(supports); scInfo->event->StoreISupports(supports);
} }
if (MessageChannel::PrefEnabled()) {
MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, cx, obj, port);
if (NS_SUCCEEDED(rv) && scInfo->subsumes) {
nsRefPtr<MessagePort> newPort = port->Clone(scInfo->window);
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
scInfo->event->StoreISupports(newPort);
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks = const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx); js::GetContextStructuredCloneCallbacks(cx);
@ -6910,6 +6941,7 @@ PostMessageEvent::Run()
{ {
StructuredCloneInfo scInfo; StructuredCloneInfo scInfo;
scInfo.event = this; scInfo.event = this;
scInfo.window = targetWindow;
if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks, if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks,
&scInfo)) { &scInfo)) {
@ -7056,6 +7088,7 @@ nsGlobalWindow::PostMessageMoz(const JS::Value& aMessage,
JSAutoStructuredCloneBuffer buffer; JSAutoStructuredCloneBuffer buffer;
StructuredCloneInfo scInfo; StructuredCloneInfo scInfo;
scInfo.event = event; scInfo.event = event;
scInfo.window = this;
nsIPrincipal* principal = GetPrincipal(); nsIPrincipal* principal = GetPrincipal();
if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes))) if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)))

View File

@ -31,6 +31,17 @@ MOCHITEST_FILES = \
test_Image_constructor.html \ test_Image_constructor.html \
test_setting_opener.html \ test_setting_opener.html \
test_error.html \ test_error.html \
test_messageChannel.html \
test_messageChannel_cloning.html \
iframe_messageChannel_cloning.html \
test_messageChannel_post.html \
iframe_messageChannel_post.html \
test_messageChannel_transferable.html \
test_messageChannel_start.html \
test_messageChannel_pingpong.html \
iframe_messageChannel_pingpong.html \
test_messageChannel_unshipped.html \
test_messageChannel_pref.html \
$(NULL) $(NULL)
MOCHITEST_CHROME_FILES = \ MOCHITEST_CHROME_FILES = \

View File

@ -0,0 +1,22 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript">
function ok(a, msg) {
window.parent.postMessage({ status: a ? "OK" : "KO", message: msg }, "*");
}
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
ok (evt.data, "Data received");
ok (evt.data.port instanceof MessagePort, "Data contains a MessagePort");
var a = new MessageChannel();
window.parent.postMessage({ status: "FINISH", port: a.port2 }, '*');
}
</script>
</body>
</html>

View File

@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript">
function ok(what, msg) {
window.parent.postMessage({type: what ? 'OK' : 'KO', msg: msg }, '*');
}
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.type == 'PORT') {
var port = evt.data.port;
var counter = 0;
port.onmessage = function(evt) {
if (counter++ == 0) {
ok(!(evt.data % 2), "The number " + evt.data + " has been received correctly by the iframe");
window.parent.postMessage({ type: 'PORT', port: port }, '*');
}
else {
ok(false, "Wrong message!");
}
}
} else {
ok(false, "Unknown message");
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript">
var port;
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
port = evt.data.port;
port.addEventListener('message', receivePostMessage, false);
function receivePostMessage(evt) {
port.postMessage(evt.data);
}
port.start();
window.parent.postMessage({ status: "READY" }, '*');
}
</script>
</body>
</html>

View File

@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - basic support</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe name="x" id="x"></iframe>
<iframe name="y" id="y"></iframe>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTest() {
/** Test for Bug 677638 **/
var a = new MessageChannel();
ok(a, "MessageChannel created");
var port1 = a.port1;
ok(port1, "MessageChannel.port1 exists");
is(port1, a.port1, "MessageChannel.port1 is port1");
var port2 = a.port2;
ok(port2, "MessageChannel.port1 exists");
is(port2, a.port2, "MessageChannel.port2 is port2");
[ 'postMessage', 'start', 'close' ].forEach(function(e) {
ok(e in port1, "MessagePort1." + e + " exists");
ok(e in port2, "MessagePort2." + e + " exists");
});
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
// This test checks if MessagePorts can be shared with iframes
function test_iframe() {
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.status == 'OK') {
ok(true, evt.data.message);
} else if (evt.data.status == 'KO') {
ok(false, evt.data.message);
} else if (evt.data.status == 'FINISH') {
ok (evt.data.port instanceof MessagePort, "Data contains a MessagePort");
window.removeEventListener('message', receiveMessage);
runTest();
} else {
ok(false, "Unknown message");
}
}
var a = new MessageChannel();
ok(a, "MessageChannel created");
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_cloning.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ port: a.port2 }, '*');
}
}
var tests = [
test_iframe
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,77 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTest() {
var MAX = 100;
var a = new MessageChannel();
ok(a, "MessageChannel created");
// Populate the message queue of this port.
for (var i = 0; i < MAX; ++i) {
a.port1.postMessage(i);
}
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
// This test sends the port from this window to the iframe and viceversa.
if (evt.data.type == 'PORT') {
var port = evt.data.port;
var counter = 0;
port.onmessage = function(evt) {
// only 1 message should be received by this port.
if (counter++ == 0) {
ok(evt.data % 2, "The number " + evt.data + " has been received correctly by the main window");
if (evt.data < MAX - 1) {
ifr.contentWindow.postMessage({ type: 'PORT', port: port }, '*');
} else {
SimpleTest.finish();
}
} else {
ok(false, "Wrong message!");
}
}
} else if (evt.data.type == 'OK') {
ok(true, evt.data.msg);
} else if (evt.data.type == 'KO') {
ok(false, evt.data.msg);
} else {
ok(false, "Unknown message");
}
}
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_pingpong.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ type: 'PORT', port: a.port2 }, '*');
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function start() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.status == 'READY') {
runTest();
} else {
ok(false, "Unknown message");
}
}
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_post.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ port: a.port2 }, '*');
}
var tests = [ 42,
null,
undefined,
"hello world",
new Blob([]),
true ];
a.port1.onmessage = function(evt) {
ok(tests.length, "We are waiting for a message");
is(tests[0], evt.data, "Value ok: " + tests[0]);
tests.shift();
runTest();
}
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
a.port1.postMessage(tests[0]);
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, start);
</script>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - pref</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTest(what) {
var status;
try {
status = MessageChannel;
ok(what, "Should MessageChannel exist?");
} catch(e) {
ok(!what, "Should MessageChannel exist?");
}
try {
status = MessagePort;
ok(what, "Should MessagePort exist?");
} catch(e) {
ok(!what, "Should MessagePort exist?");
}
}
SimpleTest.waitForExplicitFinish();
runTest(false);
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]},
function() { runTest(true); SimpleTest.finish(); });
</script>
</body>
</html>

View File

@ -0,0 +1,234 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - start/close</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
function testOnMessage() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
a.port1.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
a.port2.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
}
function testAddEventListener() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
a.port1.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
a.port2.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
setTimeout(runTests, 0);
}
function testAddEventListenerAndStart() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
a.port1.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port1.start();
a.port2.start();
}
function testAddEventListener1AndStart() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 1;
a.port1.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
a.port1.start();
}
function testAddEventListener2AndStart() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 1;
a.port1.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
a.port2.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.start();
}
function testTimer() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
setTimeout(function() {
var events = 2;
a.port1.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
a.port2.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
}, 200);
}
function testAddEventListenerAndStartWrongOrder() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
a.port1.start();
a.port1.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.start();
a.port2.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
}
function testOnMessageClone() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
addEventListener('message', testOnMessageCloneCb, false);
function testOnMessageCloneCb(evt) {
a.port1.onmessage = function(evt) {
ok(true, "This method should be called");
testOnMessageCloneFinish();
}
evt.data.onmessage = function(evt) {
ok(true, "This method should be called");
testOnMessageCloneFinish();
}
a.port2.onmessage = function(evt) {
ok(false, "This method should not be called");
}
}
function testOnMessageCloneFinish() {
if (!--events) {
removeEventListener('message', testOnMessageCloneCb);
runTests();
}
}
postMessage(a.port2, '*');
}
var tests = [
testOnMessage,
testAddEventListener,
testAddEventListenerAndStart,
testAddEventListener1AndStart,
testAddEventListener2AndStart,
testTimer,
testAddEventListenerAndStartWrongOrder,
testOnMessageClone,
];
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTests);
</script>
</body>
</html>

View File

@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function start() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.status == 'READY') {
runTest();
} else {
ok(false, "Unknown message");
}
}
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_post.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ port: a.port2 }, '*');
}
a.port1.addEventListener('message', receivePortMessage, false);
function receivePortMessage(evt) {
is(evt.data.ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
SimpleTest.finish();
}
// Start() is not implicity invoked when addEventListener is used.
a.port1.start();
var size = 1024 * 1024 * 32;
var ab = new ArrayBuffer(size);
is(ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
function runTest() {
a.port1.postMessage({ab: ab, cb: ab}, [ab]);
ok(ab.byteLength == 0, "PostMessage - The size is: 0 == " + ab.byteLength)
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, start);
</script>
</body>
</html>

View File

@ -0,0 +1,123 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - unshipped message port queue</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function test_orderedMessages() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
var b = new MessageChannel();
ok(b, "MessageChannel created");
var expectedNumber = 1;
function testEvent(number, id) {
is(expectedNumber, number, "This is the right number!");
ok(!((expectedNumber - id) % 4), "From the right port: " + expectedNumber + " " + id);
expectedNumber++;
if (expectedNumber >100) {
runTests();
}
}
a.port1.onmessage = function(evt) {
testEvent(evt.data, 2);
};
a.port2.onmessage = function(evt) {
testEvent(evt.data, 1);
};
b.port1.onmessage = function(evt) {
testEvent(evt.data, 4);
};
b.port2.onmessage = function(evt) {
testEvent(evt.data, 3);
};
for (var i = 0; i < 100;) {
a.port1.postMessage(++i);
a.port2.postMessage(++i);
b.port1.postMessage(++i);
b.port2.postMessage(++i);
}
}
function test_unstarted() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
var b = new MessageChannel();
ok(b, "MessageChannel created");
var expectedNumber = 1;
function testEvent(number, id) {
is(expectedNumber, number, "This is the right number!");
ok(!((expectedNumber - id) % 3), "From the right port: " + expectedNumber + " " + id);
expectedNumber++;
// 102 because it's the first multiple of 3.
if (expectedNumber > 102) {
runTests();
}
}
a.port1.onmessage = function(evt) {
testEvent(evt.data, 2);
};
a.port2.onmessage = function(evt) {
testEvent(evt.data, 1);
};
b.port1.addEventListener("message", function() {
ok(false, "shouldn't be called");
});
b.port2.onmessage = function(evt) {
testEvent(evt.data, 3);
};
for (var i = 0; i < 100;) {
a.port1.postMessage(++i);
a.port2.postMessage(++i);
b.port1.postMessage(++i);
b.port2.postMessage(1000);
}
}
var tests = [
test_orderedMessages,
test_unstarted
];
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTests);
</script>
</body>
</html>

View File

@ -1459,8 +1459,6 @@ DOMInterfaces = {
}, },
'XPathEvaluator': { 'XPathEvaluator': {
'nativeType': 'nsXPathEvaluator',
'headerFile': 'nsXPathEvaluator.h',
'wrapperCache': False 'wrapperCache': False
}, },

View File

@ -48,7 +48,7 @@ const ContentPanning = {
// If we are using an AsyncPanZoomController for the parent frame, // If we are using an AsyncPanZoomController for the parent frame,
// it will handle subframe scrolling too. We don't need to listen for // it will handle subframe scrolling too. We don't need to listen for
// these events. // these events.
if (!docShell.asyncPanZoomEnabled) { if (!this._asyncPanZoomForViewportFrame) {
let els = Cc["@mozilla.org/eventlistenerservice;1"] let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService); .getService(Ci.nsIEventListenerService);
@ -140,11 +140,23 @@ const ContentPanning = {
let oldTarget = this.target; let oldTarget = this.target;
[this.target, this.scrollCallback] = this.getPannable(this.pointerDownTarget); [this.target, this.scrollCallback] = this.getPannable(this.pointerDownTarget);
// If we have a pointer down target, we may need to fill in for EventStateManager // If we found a target, that means we have found a scrollable subframe. In
// in setting the active state on the target element. Set a timer to // this case, and if we are using async panning and zooming on the parent
// frame, inform the pan/zoom controller that it should not attempt to
// handle any touch events it gets until the next batch (meaning the next
// time we get a touch end).
if (this.target != null && this._asyncPanZoomForViewportFrame) {
this.detectingScrolling = true;
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.notifyObservers(docShell, 'detect-scrollable-subframe', null);
}
// If we have a pointer down target and we're not async
// pan/zooming, we may need to fill in for EventStateManager in
// setting the active state on the target element. Set a timer to
// ensure the pointer-down target is active. (If it's already // ensure the pointer-down target is active. (If it's already
// active, the timer is a no-op.) // active, the timer is a no-op.)
if (this.pointerDownTarget !== null) { if (this.pointerDownTarget !== null && !this.detectingScrolling) {
// If there's no possibility this is a drag/pan, activate now. // If there's no possibility this is a drag/pan, activate now.
// Otherwise wait a little bit to see if the gesture isn't a // Otherwise wait a little bit to see if the gesture isn't a
// tap. // tap.
@ -214,6 +226,12 @@ const ContentPanning = {
this.pointerDownTarget = null; this.pointerDownTarget = null;
}, },
// True when there's an async pan-zoom controll watching the
// outermost scrollable frame, and we're waiting to see whether
// we're going to take over from it and synchronously scroll an
// inner scrollable frame.
detectingScrolling: false,
onTouchMove: function cp_onTouchMove(evt) { onTouchMove: function cp_onTouchMove(evt) {
if (!this.dragging) if (!this.dragging)
return; return;
@ -242,6 +260,27 @@ const ContentPanning = {
} }
let isPan = KineticPanning.isPan(); let isPan = KineticPanning.isPan();
if (!isPan && this.detectingScrolling) {
// If panning distance is not large enough and we're waiting to
// see whether we should use the sync scroll fallback or not,
// don't attempt scrolling.
return;
}
let isScroll = this.scrollCallback(delta.scale(-1));
if (this.detectingScrolling) {
this.detectingScrolling = false;
// Stop async-pan-zooming if the user is panning the subframe.
if (isScroll) {
// We're going to drive synchronously scrolling an inner frame.
Services.obs.notifyObservers(docShell, 'cancel-default-pan-zoom', null);
} else {
// Let AsyncPanZoomController handle the scrolling gesture.
this.scrollCallback = null;
return;
}
}
// If we've detected a pan gesture, cancel the active state of the // If we've detected a pan gesture, cancel the active state of the
// current target. // current target.
@ -317,6 +356,13 @@ const ContentPanning = {
node = node.parentNode; node = node.parentNode;
} }
if (ContentPanning._asyncPanZoomForViewportFrame &&
nodeContent === content) {
// The parent context is asynchronously panning and zooming our
// root scrollable frame, so don't use our synchronous fallback.
return null;
}
if (nodeContent.scrollMaxX || nodeContent.scrollMaxY) { if (nodeContent.scrollMaxX || nodeContent.scrollMaxY) {
return nodeContent; return nodeContent;
} }
@ -438,6 +484,10 @@ const ContentPanning = {
this._domUtils.setContentState(elt, kStateActive); this._domUtils.setContentState(elt, kStateActive);
}, },
get _asyncPanZoomForViewportFrame() {
return docShell.asyncPanZoomEnabled;
},
_recvViewportChange: function(data) { _recvViewportChange: function(data) {
let metrics = data.json; let metrics = data.json;
this._viewport = new Rect(metrics.x, metrics.y, this._viewport = new Rect(metrics.x, metrics.y,
@ -549,6 +599,7 @@ const ContentPanning = {
_finishPanning: function() { _finishPanning: function() {
this._resetActive(); this._resetActive();
this.dragging = false; this.dragging = false;
this.detectingScrolling = false;
delete this.primaryPointerId; delete this.primaryPointerId;
this._activationTimer.cancel(); this._activationTimer.cancel();

View File

@ -1,4 +1,3 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT # THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
DIRS += [ DIRS += [

View File

@ -12,8 +12,13 @@ include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES := \ MOCHITEST_FILES := \
test_Document-open.html.json \ test_Document-open.html.json \
test_addRange.html.json \ test_addRange.html.json \
test_collapse.html.json \
test_collapseToStartEnd.html.json \
test_extend.html.json \
test_getSelection.html.json \ test_getSelection.html.json \
test_interfaces.html.json \ test_interfaces.html.json \
test_removeAllRanges.html.json \
test_selectAllChildren.html.json \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -1,4 +1,3 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT # THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
DIRS += [ DIRS += [

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
{
"Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] collapseToStart()":true,
"Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] collapseToEnd()":true,
"Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] collapseToStart()":true,
"Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] collapseToEnd()":true,
"Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] collapseToStart()":true,
"Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] collapseToEnd()":true,
"Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] collapseToStart()":true,
"Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] collapseToEnd()":true,
"Range 21 [foreignDoc.head, 1, foreignDoc.head, 1] collapseToStart()":true,
"Range 21 [foreignDoc.head, 1, foreignDoc.head, 1] collapseToEnd()":true,
"Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] collapseToStart()":true,
"Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] collapseToEnd()":true,
"Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] collapseToStart()":true,
"Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] collapseToEnd()":true,
"Range 41 [foreignDoc, 0, foreignDoc, 0] collapseToStart()":true,
"Range 41 [foreignDoc, 0, foreignDoc, 0] collapseToEnd()":true,
"Range 42 [foreignDoc, 1, foreignComment, 2] collapseToStart()":true,
"Range 42 [foreignDoc, 1, foreignComment, 2] collapseToEnd()":true,
"Range 43 [foreignDoc.body, 0, foreignTextNode, 36] collapseToStart()":true,
"Range 43 [foreignDoc.body, 0, foreignTextNode, 36] collapseToEnd()":true,
"Range 44 [xmlDoc, 0, xmlDoc, 0] collapseToStart()":true,
"Range 44 [xmlDoc, 0, xmlDoc, 0] collapseToEnd()":true,
"Range 45 [xmlDoc, 1, xmlComment, 0] collapseToStart()":true,
"Range 45 [xmlDoc, 1, xmlComment, 0] collapseToEnd()":true,
"Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] collapseToStart()":true,
"Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] collapseToEnd()":true,
"Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] collapseToStart()":true,
"Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] collapseToEnd()":true,
"Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] collapseToStart()":true,
"Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] collapseToEnd()":true,
"Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] collapseToStart()":true,
"Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] collapseToEnd()":true,
"Range 53 [detachedForeignComment, 0, detachedForeignComment, 1] collapseToStart()":true,
"Range 53 [detachedForeignComment, 0, detachedForeignComment, 1] collapseToEnd()":true,
"Range 54 [detachedForeignComment, 4, detachedForeignComment, 4] collapseToStart()":true,
"Range 54 [detachedForeignComment, 4, detachedForeignComment, 4] collapseToEnd()":true,
"Range 55 [detachedXmlComment, 2, detachedXmlComment, 6] collapseToStart()":true,
"Range 55 [detachedXmlComment, 2, detachedXmlComment, 6] collapseToEnd()":true,
"Range 57 [foreignDocfrag, 0, foreignDocfrag, 0] collapseToStart()":true,
"Range 57 [foreignDocfrag, 0, foreignDocfrag, 0] collapseToEnd()":true,
"Range 58 [xmlDocfrag, 0, xmlDocfrag, 0] collapseToStart()":true,
"Range 58 [xmlDocfrag, 0, xmlDocfrag, 0] collapseToEnd()":true
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
{
"Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] backwards":true,
"Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] backwards":true,
"Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] backwards":true,
"Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] backwards":true,
"Range 21 [foreignDoc.head, 1, foreignDoc.head, 1] backwards":true,
"Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] backwards":true,
"Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] backwards":true,
"Range 41 [foreignDoc, 0, foreignDoc, 0] backwards":true,
"Range 42 [foreignDoc, 1, foreignComment, 2] backwards":true,
"Range 43 [foreignDoc.body, 0, foreignTextNode, 36] backwards":true,
"Range 44 [xmlDoc, 0, xmlDoc, 0] backwards":true,
"Range 45 [xmlDoc, 1, xmlComment, 0] backwards":true,
"Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] backwards":true,
"Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] backwards":true,
"Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] backwards":true,
"Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] backwards":true,
"Range 53 [detachedForeignComment, 0, detachedForeignComment, 1] backwards":true,
"Range 54 [detachedForeignComment, 4, detachedForeignComment, 4] backwards":true,
"Range 55 [detachedXmlComment, 2, detachedXmlComment, 6] backwards":true,
"Range 57 [foreignDocfrag, 0, foreignDocfrag, 0] backwards":true,
"Range 58 [xmlDocfrag, 0, xmlDocfrag, 0] backwards":true
}

File diff suppressed because it is too large Load Diff

View File

@ -105,8 +105,10 @@ NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
static const CSSSize kDefaultViewportSize(980, 480); static const CSSSize kDefaultViewportSize(980, 480);
static const char CANCEL_DEFAULT_PAN_ZOOM[] = "cancel-default-pan-zoom";
static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect"; static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
static const char BEFORE_FIRST_PAINT[] = "before-first-paint"; static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
static const char DETECT_SCROLLABLE_SUBFRAME[] = "detect-scrollable-subframe";
static bool sCpowsEnabled = false; static bool sCpowsEnabled = false;
@ -383,7 +385,13 @@ TabChild::Observe(nsISupports *aSubject,
const char *aTopic, const char *aTopic,
const PRUnichar *aData) const PRUnichar *aData)
{ {
if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) { if (!strcmp(aTopic, CANCEL_DEFAULT_PAN_ZOOM)) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
if (tabChild == this) {
mRemoteFrame->CancelDefaultPanZoom();
}
} else if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject)); nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell)); nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
if (tabChild == this) { if (tabChild == this) {
@ -428,6 +436,12 @@ TabChild::Observe(nsISupports *aSubject,
HandlePossibleViewportChange(); HandlePossibleViewportChange();
} }
} }
} else if (!strcmp(aTopic, DETECT_SCROLLABLE_SUBFRAME)) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
if (tabChild == this) {
mRemoteFrame->DetectScrollableSubframe();
}
} }
return NS_OK; return NS_OK;
@ -2165,8 +2179,10 @@ TabChild::RecvDestroy()
nsCOMPtr<nsIObserverService> observerService = nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID); do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
observerService->RemoveObserver(this, CANCEL_DEFAULT_PAN_ZOOM);
observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT); observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
observerService->RemoveObserver(this, BEFORE_FIRST_PAINT); observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
observerService->RemoveObserver(this, DETECT_SCROLLABLE_SUBFRAME);
const InfallibleTArray<PIndexedDBChild*>& idbActors = const InfallibleTArray<PIndexedDBChild*>& idbActors =
ManagedPIndexedDBChild(); ManagedPIndexedDBChild();
@ -2301,12 +2317,18 @@ TabChild::InitRenderingState()
do_GetService(NS_OBSERVERSERVICE_CONTRACTID); do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (observerService) { if (observerService) {
observerService->AddObserver(this,
CANCEL_DEFAULT_PAN_ZOOM,
false);
observerService->AddObserver(this, observerService->AddObserver(this,
BROWSER_ZOOM_TO_RECT, BROWSER_ZOOM_TO_RECT,
false); false);
observerService->AddObserver(this, observerService->AddObserver(this,
BEFORE_FIRST_PAINT, BEFORE_FIRST_PAINT,
false); false);
observerService->AddObserver(this,
DETECT_SCROLLABLE_SUBFRAME,
false);
} }
// This state can't really change during the lifetime of the child. // This state can't really change during the lifetime of the child.

View File

@ -0,0 +1,14 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* For more information on this interface, please see
* http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
*/
[Constructor, Pref="dom.messageChannel.enabled"]
interface MessageChannel {
readonly attribute MessagePort port1;
readonly attribute MessagePort port2;
};

View File

@ -0,0 +1,23 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* For more information on this interface, please see
* http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
*/
[Pref="dom.messageChannel.enabled"]
interface MessagePort : EventTarget {
// TODO void postMessage(any message, optional sequence<Transferable> transfer);
[Throws]
void postMessage(any message, optional any transfer);
void start();
void close();
// event handlers
[SetterThrows]
attribute EventHandler onmessage;
};
// MessagePort implements Transferable;

View File

@ -195,7 +195,9 @@ webidl_files = \
MediaStreamAudioSourceNode.webidl \ MediaStreamAudioSourceNode.webidl \
MediaStreamEvent.webidl \ MediaStreamEvent.webidl \
MediaStreamTrack.webidl \ MediaStreamTrack.webidl \
MessageChannel.webidl \
MessageEvent.webidl \ MessageEvent.webidl \
MessagePort.webidl \
MimeType.webidl \ MimeType.webidl \
MimeTypeArray.webidl \ MimeTypeArray.webidl \
MobileMessageManager.webidl \ MobileMessageManager.webidl \

View File

@ -294,7 +294,12 @@ private:
return false; return false;
} }
return worker->PostMessage(aCx, message, transferable); if (!worker->PostMessage(aCx, message, transferable)) {
return false;
}
JS_RVAL(aCx, aVp).setUndefined();
return true;
} }
}; };

View File

@ -853,7 +853,12 @@ private:
return false; return false;
} }
return scope->mWorker->PostMessageToParent(aCx, message, transferable); if (!scope->mWorker->PostMessageToParent(aCx, message, transferable)) {
return false;
}
JS_RVAL(aCx, aVp).setUndefined();
return true;
} }
}; };

View File

@ -106,6 +106,8 @@ MOCHITEST_FILES = \
content_worker.js \ content_worker.js \
test_url.html \ test_url.html \
url_worker.js \ url_worker.js \
test_bug911085.html \
bug911085_worker.js \
$(NULL) $(NULL)
# Bug 842386 - Disabled on OSX due to intermittent failures. # Bug 842386 - Disabled on OSX due to intermittent failures.

View File

@ -0,0 +1,3 @@
onmessage = function(evt) {
postMessage(postMessage('ignore') == undefined);
}

View File

@ -0,0 +1,32 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test for bug 911085</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">
var worker = new Worker("bug911085_worker.js");
worker.onmessage = function(event) {
if (event.data == 'ignore') return;
ok(event.data, "postMessage() returns 'undefined' in workers");
SimpleTest.finish();
};
is(worker.postMessage(42), undefined, "PostMessage() returns 'undefined' on main thread");
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -35,11 +35,12 @@ function runTest() {
var i = document.getElementById("i"); var i = document.getElementById("i");
i.focus(); i.focus();
var win = i.contentWindow;
var doc = i.contentDocument; var doc = i.contentDocument;
var t = doc.getElementById("t"); var t = doc.getElementById("t");
t.focus(); t.focus();
// put the caret at the end // put the caret at the end
getSelection().collapse(t.firstChild, 11); win.getSelection().collapse(t.firstChild, 11);
// Simulate pression Option+Delete on Mac // Simulate pression Option+Delete on Mac
// We do things this way because not every platform can invoke this // We do things this way because not every platform can invoke this

View File

@ -360,6 +360,24 @@ APZCTreeManager::UpdateCompositionBounds(const ScrollableLayerGuid& aGuid,
} }
} }
void
APZCTreeManager::CancelDefaultPanZoom(const ScrollableLayerGuid& aGuid)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->CancelDefaultPanZoom();
}
}
void
APZCTreeManager::DetectScrollableSubframe(const ScrollableLayerGuid& aGuid)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->DetectScrollableSubframe();
}
}
void void
APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid, APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
const CSSRect& aRect) const CSSRect& aRect)

View File

@ -168,6 +168,22 @@ public:
void UpdateCompositionBounds(const ScrollableLayerGuid& aGuid, void UpdateCompositionBounds(const ScrollableLayerGuid& aGuid,
const ScreenIntRect& aCompositionBounds); const ScreenIntRect& aCompositionBounds);
/**
* We are scrolling a subframe, so disable our machinery until we hit
* a touch end or a new touch start. This prevents us from accidentally
* panning both the subframe and the parent frame.
*
* XXX/bug 775452: We should eventually be supporting async scrollable
* subframes.
*/
void CancelDefaultPanZoom(const ScrollableLayerGuid& aGuid);
/**
* We have found a scrollable subframe, so we need to delay the scrolling
* gesture executed and let subframe do the scrolling first.
*/
void DetectScrollableSubframe(const ScrollableLayerGuid& aGuid);
/** /**
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
* in. The actual animation is done on the compositor thread after being set * in. The actual animation is done on the compositor thread after being set

View File

@ -212,7 +212,9 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
mLastAsyncScrollOffset(0, 0), mLastAsyncScrollOffset(0, 0),
mCurrentAsyncScrollOffset(0, 0), mCurrentAsyncScrollOffset(0, 0),
mAsyncScrollTimeoutTask(nullptr), mAsyncScrollTimeoutTask(nullptr),
mHandlingTouchQueue(false) mDisableNextTouchBatch(false),
mHandlingTouchQueue(false),
mDelayPanning(false)
{ {
MOZ_COUNT_CTOR(AsyncPanZoomController); MOZ_COUNT_CTOR(AsyncPanZoomController);
@ -310,12 +312,29 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent)
nsEventStatus rv = nsEventStatus_eIgnore; nsEventStatus rv = nsEventStatus_eIgnore;
nsRefPtr<GestureEventListener> listener = GetGestureEventListener(); nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
if (listener) { if (listener && !mDisableNextTouchBatch) {
rv = listener->HandleInputEvent(aEvent); rv = listener->HandleInputEvent(aEvent);
if (rv == nsEventStatus_eConsumeNoDefault) if (rv == nsEventStatus_eConsumeNoDefault)
return rv; return rv;
} }
if (mDelayPanning && aEvent.mInputType == MULTITOUCH_INPUT) {
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_MOVE) {
// Let BrowserElementScrolling perform panning gesture first.
SetState(WAITING_LISTENERS);
mTouchQueue.AppendElement(multiTouchInput);
if (!mTouchListenerTimeoutTask) {
mTouchListenerTimeoutTask =
NewRunnableMethod(this, &AsyncPanZoomController::TimeoutTouchListeners);
PostDelayedTask(mTouchListenerTimeoutTask, gTouchListenerTimeout);
}
return nsEventStatus_eConsumeNoDefault;
}
}
switch (aEvent.mInputType) { switch (aEvent.mInputType) {
case MULTITOUCH_INPUT: { case MULTITOUCH_INPUT: {
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput(); const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
@ -397,6 +416,10 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
} }
nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent) { nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent) {
if (mDisableNextTouchBatch) {
return nsEventStatus_eIgnore;
}
switch (mState) { switch (mState) {
case FLING: case FLING:
case NOTHING: case NOTHING:
@ -436,6 +459,11 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
} }
nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) { nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
if (mDisableNextTouchBatch) {
mDisableNextTouchBatch = false;
return nsEventStatus_eIgnore;
}
{ {
ReentrantMonitorAutoEnter lock(mMonitor); ReentrantMonitorAutoEnter lock(mMonitor);
SendAsyncScrollEvent(); SendAsyncScrollEvent();
@ -1157,6 +1185,18 @@ void AsyncPanZoomController::UpdateCompositionBounds(const ScreenIntRect& aCompo
} }
} }
void AsyncPanZoomController::CancelDefaultPanZoom() {
mDisableNextTouchBatch = true;
nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
if (listener) {
listener->CancelGesture();
}
}
void AsyncPanZoomController::DetectScrollableSubframe() {
mDelayPanning = true;
}
void AsyncPanZoomController::ZoomToRect(CSSRect aRect) { void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
SetState(ANIMATING_ZOOM); SetState(ANIMATING_ZOOM);
@ -1236,7 +1276,7 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) {
} }
void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) { void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) {
if (!mFrameMetrics.mMayHaveTouchListeners) { if (!mFrameMetrics.mMayHaveTouchListeners && !mDelayPanning) {
mTouchQueue.Clear(); mTouchQueue.Clear();
return; return;
} }
@ -1248,12 +1288,21 @@ void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) {
if (mState == WAITING_LISTENERS) { if (mState == WAITING_LISTENERS) {
if (!aPreventDefault) { if (!aPreventDefault) {
SetState(NOTHING); // Delayed scrolling gesture is pending at TOUCHING state.
if (mDelayPanning) {
SetState(TOUCHING);
} else {
SetState(NOTHING);
}
} }
mHandlingTouchQueue = true; mHandlingTouchQueue = true;
while (!mTouchQueue.IsEmpty()) { while (!mTouchQueue.IsEmpty()) {
// we need to reset mDelayPanning before handling scrolling gesture.
if (!aPreventDefault && mTouchQueue[0].mType == MultiTouchInput::MULTITOUCH_MOVE) {
mDelayPanning = false;
}
if (!aPreventDefault) { if (!aPreventDefault) {
HandleInputEvent(mTouchQueue[0]); HandleInputEvent(mTouchQueue[0]);
} }

View File

@ -109,6 +109,22 @@ public:
*/ */
void UpdateCompositionBounds(const ScreenIntRect& aCompositionBounds); void UpdateCompositionBounds(const ScreenIntRect& aCompositionBounds);
/**
* We are scrolling a subframe, so disable our machinery until we hit
* a touch end or a new touch start. This prevents us from accidentally
* panning both the subframe and the parent frame.
*
* XXX/bug 775452: We should eventually be supporting async scrollable
* subframes.
*/
void CancelDefaultPanZoom();
/**
* We have found a scrollable subframe, so we need to delay the scrolling
* gesture executed and let subframe do the scrolling first.
*/
void DetectScrollableSubframe();
/** /**
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
* in. The actual animation is done on the compositor thread after being set * in. The actual animation is done on the compositor thread after being set
@ -564,12 +580,22 @@ private:
// ensures the last mozbrowserasyncscroll event is always been fired. // ensures the last mozbrowserasyncscroll event is always been fired.
CancelableTask* mAsyncScrollTimeoutTask; CancelableTask* mAsyncScrollTimeoutTask;
// Flag used to determine whether or not we should disable handling of the
// next batch of touch events. This is used for sync scrolling of subframes.
bool mDisableNextTouchBatch;
// Flag used to determine whether or not we should try to enter the // Flag used to determine whether or not we should try to enter the
// WAITING_LISTENERS state. This is used in the case that we are processing a // WAITING_LISTENERS state. This is used in the case that we are processing a
// queued up event block. If set, this means that we are handling this queue // queued up event block. If set, this means that we are handling this queue
// and we don't want to queue the events back up again. // and we don't want to queue the events back up again.
bool mHandlingTouchQueue; bool mHandlingTouchQueue;
// Flag used to determine whether or not we should try scrolling by
// BrowserElementScrolling first. If set, we delay delivering
// touchmove events to GestureListener until BrowserElementScrolling
// decides whether it wants to handle panning for this touch series.
bool mDelayPanning;
friend class Axis; friend class Axis;
/* The functions and members in this section are used to build a tree /* The functions and members in this section are used to build a tree

View File

@ -246,7 +246,9 @@ void nsRegion::Init()
mRectListHead.prev = mRectListHead.next = &mRectListHead; mRectListHead.prev = mRectListHead.next = &mRectListHead;
mCurRect = &mRectListHead; mCurRect = &mRectListHead;
mRectCount = 0; mRectCount = 0;
mBoundRect.SetRect (0, 0, 0, 0); MOZ_ASSERT(mBoundRect.x == 0 && mBoundRect.y == 0 &&
mBoundRect.width == 0 && mBoundRect.height == 0,
"Caller must have initialized mBoundRect");
} }
inline void nsRegion::InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect) inline void nsRegion::InsertBefore (RgnRect* aNewRect, RgnRect* aRelativeRect)

View File

@ -12,7 +12,7 @@
#include "base/port.h" // Types that only need exist on certain systems #include "base/port.h" // Types that only need exist on certain systems
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include <stdint.h> #include "mozilla/IntegerPrintfMacros.h"
// A type to represent a Unicode code-point value. As of Unicode 4.0, // A type to represent a Unicode code-point value. As of Unicode 4.0,
// such values require up to 21 bits. // such values require up to 21 bits.
@ -35,15 +35,10 @@ const int64_t kint64max = (( int64_t) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
// Platform- and hardware-dependent printf specifiers // Platform- and hardware-dependent printf specifiers
# if defined(OS_POSIX) # if defined(OS_POSIX)
# define __STDC_FORMAT_MACROS 1
# include <inttypes.h> // for 64-bit integer format macros
# define PRId64L "I64d" # define PRId64L "I64d"
# define PRIu64L "I64u" # define PRIu64L "I64u"
# define PRIx64L "I64x" # define PRIx64L "I64x"
# elif defined(OS_WIN) # elif defined(OS_WIN)
# define PRId64 "I64d"
# define PRIu64 "I64u"
# define PRIx64 "I64x"
# define PRId64L L"I64d" # define PRId64L L"I64d"
# define PRIu64L L"I64u" # define PRIu64L L"I64u"
# define PRIx64L L"I64x" # define PRIx64L L"I64x"

View File

@ -15,9 +15,17 @@
/* /*
* The c99 defining the limit macros (UINT32_MAX for example), says: * The c99 defining the limit macros (UINT32_MAX for example), says:
* C++ implementations should define these macros only when __STDC_LIMIT_MACROS *
* is defined before <stdint.h> is included. * C++ implementations should define these macros only when
* __STDC_LIMIT_MACROS is defined before <stdint.h> is included.
*
* The same also occurs with __STDC_CONSTANT_MACROS for the constant macros
* (INT8_C for example) used to specify a literal constant of the proper type,
* and with __STDC_FORMAT_MACROS for the format macros (PRId32 for example) used
* with the fprintf function family.
*/ */
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#define __STDC_FORMAT_MACROS
#endif /* js_RequiredDefines_h */ #endif /* js_RequiredDefines_h */

View File

@ -1359,6 +1359,16 @@ case "$host" in
;; ;;
esac esac
dnl Check for using a custom <inttypes.h> implementation
dnl ========================================================
AC_MSG_CHECKING(for custom <inttypes.h> implementation)
if test "$MOZ_CUSTOM_INTTYPES_H"; then
AC_DEFINE_UNQUOTED(MOZ_CUSTOM_INTTYPES_H, "$MOZ_CUSTOM_INTTYPES_H")
AC_MSG_RESULT(using $MOZ_CUSTOM_INTTYPES_H)
else
AC_MSG_RESULT(none specified)
fi
MOZ_DOING_LTO(lto_is_enabled) MOZ_DOING_LTO(lto_is_enabled)
dnl ======================================================== dnl ========================================================

View File

@ -138,6 +138,11 @@ var ignoreFunctions = {
"PR_ErrorInstallTable" : true, "PR_ErrorInstallTable" : true,
"PR_SetThreadPrivate" : true, "PR_SetThreadPrivate" : true,
"JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead
// These are a little overzealous -- these destructors *can* GC if they end
// up wrapping a pending exception. See bug 898815 for the heavyweight fix.
"void js::AutoCompartment::~AutoCompartment(int32)" : true,
"void JSAutoCompartment::~JSAutoCompartment(int32)" : true,
}; };
function ignoreGCFunction(fun) function ignoreGCFunction(fun)

View File

@ -2796,6 +2796,9 @@ template <>
Parser<SyntaxParseHandler>::bindLet(BindData<SyntaxParseHandler> *data, Parser<SyntaxParseHandler>::bindLet(BindData<SyntaxParseHandler> *data,
HandlePropertyName name, Parser<SyntaxParseHandler> *parser) HandlePropertyName name, Parser<SyntaxParseHandler> *parser)
{ {
if (!parser->checkStrictBinding(name, data->pn))
return false;
return true; return true;
} }

View File

@ -2229,7 +2229,8 @@ class FunctionCompiler
*loopEntry = NULL; *loopEntry = NULL;
return true; return true;
} }
*loopEntry = MBasicBlock::NewPendingLoopHeader(mirGraph(), info(), curBlock_, NULL); *loopEntry = MBasicBlock::NewAsmJS(mirGraph(), info(), curBlock_,
MBasicBlock::PENDING_LOOP_HEADER);
if (!*loopEntry) if (!*loopEntry)
return false; return false;
mirGraph().addBlock(*loopEntry); mirGraph().addBlock(*loopEntry);
@ -2287,7 +2288,8 @@ class FunctionCompiler
if (curBlock_) { if (curBlock_) {
JS_ASSERT(curBlock_->loopDepth() == loopStack_.length() + 1); JS_ASSERT(curBlock_->loopDepth() == loopStack_.length() + 1);
curBlock_->end(MGoto::New(loopEntry)); curBlock_->end(MGoto::New(loopEntry));
loopEntry->setBackedge(curBlock_); if (!loopEntry->setBackedgeAsmJS(curBlock_))
return false;
} }
curBlock_ = afterLoop; curBlock_ = afterLoop;
if (curBlock_) if (curBlock_)
@ -2309,7 +2311,8 @@ class FunctionCompiler
if (cond->isConstant()) { if (cond->isConstant()) {
if (ToBoolean(cond->toConstant()->value())) { if (ToBoolean(cond->toConstant()->value())) {
curBlock_->end(MGoto::New(loopEntry)); curBlock_->end(MGoto::New(loopEntry));
loopEntry->setBackedge(curBlock_); if (!loopEntry->setBackedgeAsmJS(curBlock_))
return false;
curBlock_ = NULL; curBlock_ = NULL;
} else { } else {
MBasicBlock *afterLoop; MBasicBlock *afterLoop;
@ -2323,7 +2326,8 @@ class FunctionCompiler
if (!newBlock(curBlock_, &afterLoop, afterLoopStmt)) if (!newBlock(curBlock_, &afterLoop, afterLoopStmt))
return false; return false;
curBlock_->end(MTest::New(cond, loopEntry, afterLoop)); curBlock_->end(MTest::New(cond, loopEntry, afterLoop));
loopEntry->setBackedge(curBlock_); if (!loopEntry->setBackedgeAsmJS(curBlock_))
return false;
curBlock_ = afterLoop; curBlock_ = afterLoop;
} }
} }
@ -2449,7 +2453,7 @@ class FunctionCompiler
bool newBlockWithDepth(MBasicBlock *pred, unsigned loopDepth, MBasicBlock **block, ParseNode *pn) bool newBlockWithDepth(MBasicBlock *pred, unsigned loopDepth, MBasicBlock **block, ParseNode *pn)
{ {
*block = MBasicBlock::New(mirGraph(), info(), pred, /* pc = */ NULL, MBasicBlock::NORMAL); *block = MBasicBlock::NewAsmJS(mirGraph(), info(), pred, MBasicBlock::NORMAL);
if (!*block) if (!*block)
return false; return false;
noteBasicBlockPosition(*block, pn); noteBasicBlockPosition(*block, pn);
@ -3782,12 +3786,6 @@ CheckConditional(FunctionCompiler &f, ParseNode *ternary, MDefinition **def, Typ
f.pushPhiInput(elseDef); f.pushPhiInput(elseDef);
// next statement is actually not the else expr, but this is the closest stmt to the next
// one that is directly reachable
if (!f.joinIfElse(thenBlocks, elseExpr))
return false;
*def = f.popPhiOutput();
if (thenType.isInt() && elseType.isInt()) { if (thenType.isInt() && elseType.isInt()) {
*type = Type::Int; *type = Type::Int;
} else if (thenType.isDouble() && elseType.isDouble()) { } else if (thenType.isDouble() && elseType.isDouble()) {
@ -3797,6 +3795,10 @@ CheckConditional(FunctionCompiler &f, ParseNode *ternary, MDefinition **def, Typ
"current types are %s and %s", thenType.toChars(), elseType.toChars()); "current types are %s and %s", thenType.toChars(), elseType.toChars());
} }
if (!f.joinIfElse(thenBlocks, elseExpr))
return false;
*def = f.popPhiOutput();
return true; return true;
} }
@ -4311,12 +4313,9 @@ CheckIf(FunctionCompiler &f, ParseNode *ifStmt)
MBasicBlock *thenBlock, *elseBlock; MBasicBlock *thenBlock, *elseBlock;
ParseNode *elseBlockStmt = NULL;
// The second block given to branchAndStartThen contains either the else statement if // The second block given to branchAndStartThen contains either the else statement if
// there is one, or the join block; so we need to give the next statement accordingly. // there is one, or the join block; so we need to give the next statement accordingly.
elseBlockStmt = elseStmt; ParseNode *elseBlockStmt = elseStmt ? elseStmt : nextStmt;
if (elseBlockStmt == NULL)
elseBlockStmt = nextStmt;
if (!f.branchAndStartThen(condDef, &thenBlock, &elseBlock, thenStmt, elseBlockStmt)) if (!f.branchAndStartThen(condDef, &thenBlock, &elseBlock, thenStmt, elseBlockStmt))
return false; return false;

View File

@ -5568,8 +5568,12 @@ CodeGenerator::link()
IonCode *code = (executionMode == SequentialExecution) IonCode *code = (executionMode == SequentialExecution)
? linker.newCodeForIonScript(cx) ? linker.newCodeForIonScript(cx)
: linker.newCode(cx, JSC::ION_CODE); : linker.newCode(cx, JSC::ION_CODE);
if (!code) if (!code) {
// Use js_free instead of IonScript::Destroy: the cache list and
// backedge list are still uninitialized.
js_free(ionScript);
return false; return false;
}
JSScript *script = gen->info().script(); JSScript *script = gen->info().script();
JS_ASSERT(!HasIonScript(script, executionMode)); JS_ASSERT(!HasIonScript(script, executionMode));

View File

@ -1228,14 +1228,15 @@ OptimizeMIR(MIRGenerator *mir)
if (mir->shouldCancel("Phi reverse mapping")) if (mir->shouldCancel("Phi reverse mapping"))
return false; return false;
// This pass also removes copies. if (!mir->compilingAsmJS()) {
if (!ApplyTypeInformation(mir, graph)) if (!ApplyTypeInformation(mir, graph))
return false; return false;
IonSpewPass("Apply types"); IonSpewPass("Apply types");
AssertExtendedGraphCoherency(graph); AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Apply types")) if (mir->shouldCancel("Apply types"))
return false; return false;
}
if (graph.entryBlock()->info().executionMode() == ParallelExecution) { if (graph.entryBlock()->info().executionMode() == ParallelExecution) {
ParallelSafetyAnalysis analysis(mir, graph); ParallelSafetyAnalysis analysis(mir, graph);
@ -1361,7 +1362,7 @@ OptimizeMIR(MIRGenerator *mir)
// Passes after this point must not move instructions; these analyses // Passes after this point must not move instructions; these analyses
// depend on knowing the final order in which instructions will execute. // depend on knowing the final order in which instructions will execute.
if (js_IonOptions.edgeCaseAnalysis) { if (js_IonOptions.edgeCaseAnalysis && !mir->compilingAsmJS()) {
EdgeCaseAnalysis edgeCaseAnalysis(mir, graph); EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
if (!edgeCaseAnalysis.analyzeLate()) if (!edgeCaseAnalysis.analyzeLate())
return false; return false;
@ -1372,14 +1373,16 @@ OptimizeMIR(MIRGenerator *mir)
return false; return false;
} }
// Note: check elimination has to run after all other passes that move if (!mir->compilingAsmJS()) {
// instructions. Since check uses are replaced with the actual index, code // Note: check elimination has to run after all other passes that move
// motion after this pass could incorrectly move a load or store before its // instructions. Since check uses are replaced with the actual index,
// bounds check. // code motion after this pass could incorrectly move a load or store
if (!EliminateRedundantChecks(graph)) // before its bounds check.
return false; if (!EliminateRedundantChecks(graph))
IonSpewPass("Bounds Check Elimination"); return false;
AssertGraphCoherency(graph); IonSpewPass("Bounds Check Elimination");
AssertGraphCoherency(graph);
}
return true; return true;
} }

View File

@ -625,12 +625,6 @@ MUnbox::printOpcode(FILE *fp) const
} }
} }
MPhi *
MPhi::New(uint32_t slot)
{
return new MPhi(slot);
}
void void
MPhi::removeOperand(size_t index) MPhi::removeOperand(size_t index)
{ {

View File

@ -3845,7 +3845,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
uint32_t capacity_; uint32_t capacity_;
#endif #endif
MPhi(uint32_t slot) MPhi(uint32_t slot, MIRType resultType)
: slot_(slot), : slot_(slot),
hasBackedgeType_(false), hasBackedgeType_(false),
triedToSpecialize_(false), triedToSpecialize_(false),
@ -3855,7 +3855,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
, capacity_(0) , capacity_(0)
#endif #endif
{ {
setResultType(MIRType_Value); setResultType(resultType);
} }
protected: protected:
@ -3865,7 +3865,9 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
public: public:
INSTRUCTION_HEADER(Phi) INSTRUCTION_HEADER(Phi)
static MPhi *New(uint32_t slot); static MPhi *New(uint32_t slot, MIRType resultType = MIRType_Value) {
return new MPhi(slot, resultType);
}
void setOperand(size_t index, MDefinition *operand) { void setOperand(size_t index, MDefinition *operand) {
// Note: after the initial IonBuilder pass, it is OK to change phi // Note: after the initial IonBuilder pass, it is OK to change phi

View File

@ -159,6 +159,8 @@ MBasicBlock *
MBasicBlock::New(MIRGraph &graph, CompileInfo &info, MBasicBlock::New(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, jsbytecode *entryPc, Kind kind) MBasicBlock *pred, jsbytecode *entryPc, Kind kind)
{ {
JS_ASSERT(entryPc != NULL);
MBasicBlock *block = new MBasicBlock(graph, info, entryPc, kind); MBasicBlock *block = new MBasicBlock(graph, info, entryPc, kind);
if (!block->init()) if (!block->init())
return NULL; return NULL;
@ -212,7 +214,9 @@ MBasicBlock::NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info,
MBasicBlock * MBasicBlock *
MBasicBlock::NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred) MBasicBlock::NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred)
{ {
return MBasicBlock::New(graph, info, pred, pred->pc(), SPLIT_EDGE); return pred->pc()
? MBasicBlock::New(graph, info, pred, pred->pc(), SPLIT_EDGE)
: MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE);
} }
MBasicBlock * MBasicBlock *
@ -235,6 +239,40 @@ MBasicBlock::NewAbortPar(MIRGraph &graph, CompileInfo &info,
return block; return block;
} }
MBasicBlock *
MBasicBlock::NewAsmJS(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred, Kind kind)
{
MBasicBlock *block = new MBasicBlock(graph, info, /* entryPC = */ NULL, kind);
if (!block->init())
return NULL;
if (pred) {
block->stackPosition_ = pred->stackPosition_;
if (block->kind_ == PENDING_LOOP_HEADER) {
for (size_t i = 0; i < block->stackPosition_; i++) {
MDefinition *predSlot = pred->getSlot(i);
JS_ASSERT(predSlot->type() != MIRType_Value);
MPhi *phi = MPhi::New(i, predSlot->type());
JS_ALWAYS_TRUE(phi->reserveLength(2));
phi->addInput(predSlot);
block->addPhi(phi);
block->setSlot(i, phi);
}
} else {
block->copySlots(pred);
}
if (!block->predecessors_.append(pred))
return NULL;
}
return block;
}
MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind) MBasicBlock::MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind)
: earlyAbort_(false), : earlyAbort_(false),
graph_(graph), graph_(graph),
@ -291,27 +329,23 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
stackPosition_ -= popped; stackPosition_ -= popped;
if (kind_ != PENDING_LOOP_HEADER) if (kind_ != PENDING_LOOP_HEADER)
copySlots(pred); copySlots(pred);
} else if (pc()) { } else {
uint32_t stackDepth = info().script()->analysis()->getCode(pc()).stackDepth; uint32_t stackDepth = info().script()->analysis()->getCode(pc()).stackDepth;
stackPosition_ = info().firstStackSlot() + stackDepth; stackPosition_ = info().firstStackSlot() + stackDepth;
JS_ASSERT(stackPosition_ >= popped); JS_ASSERT(stackPosition_ >= popped);
stackPosition_ -= popped; stackPosition_ -= popped;
} else {
stackPosition_ = info().firstStackSlot();
} }
JS_ASSERT(info_.nslots() >= stackPosition_); JS_ASSERT(info_.nslots() >= stackPosition_);
JS_ASSERT(!entryResumePoint_); JS_ASSERT(!entryResumePoint_);
if (pc()) { // Propagate the caller resume point from the inherited block.
// Propagate the caller resume point from the inherited block. MResumePoint *callerResumePoint = pred ? pred->callerResumePoint() : NULL;
MResumePoint *callerResumePoint = pred ? pred->callerResumePoint() : NULL;
// Create a resume point using our initial stack state. // Create a resume point using our initial stack state.
entryResumePoint_ = new MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt); entryResumePoint_ = new MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt);
if (!entryResumePoint_->init()) if (!entryResumePoint_->init())
return false; return false;
}
if (pred) { if (pred) {
if (!predecessors_.append(pred)) if (!predecessors_.append(pred))
@ -324,14 +358,13 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
return false; return false;
addPhi(phi); addPhi(phi);
setSlot(i, phi); setSlot(i, phi);
if (entryResumePoint()) entryResumePoint()->setOperand(i, phi);
entryResumePoint()->setOperand(i, phi);
} }
} else if (entryResumePoint()) { } else {
for (size_t i = 0; i < stackDepth(); i++) for (size_t i = 0; i < stackDepth(); i++)
entryResumePoint()->setOperand(i, getSlot(i)); entryResumePoint()->setOperand(i, getSlot(i));
} }
} else if (entryResumePoint()) { } else {
/* /*
* Don't leave the operands uninitialized for the caller, as it may not * Don't leave the operands uninitialized for the caller, as it may not
* initialize them later on. * initialize them later on.
@ -796,7 +829,11 @@ MBasicBlock::addPredecessorPopN(MBasicBlock *pred, uint32_t popped)
return false; return false;
} else { } else {
// Otherwise, create a new phi node. // Otherwise, create a new phi node.
MPhi *phi = MPhi::New(i); MPhi *phi;
if (mine->type() == other->type())
phi = MPhi::New(i, mine->type());
else
phi = MPhi::New(i);
addPhi(phi); addPhi(phi);
// Prime the phi for each predecessor, so input(x) comes from // Prime the phi for each predecessor, so input(x) comes from
@ -859,7 +896,7 @@ MBasicBlock::setBackedge(MBasicBlock *pred)
// Predecessors must be finished, and at the correct stack depth. // Predecessors must be finished, and at the correct stack depth.
JS_ASSERT(lastIns_); JS_ASSERT(lastIns_);
JS_ASSERT(pred->lastIns_); JS_ASSERT(pred->lastIns_);
JS_ASSERT_IF(entryResumePoint(), pred->stackDepth() == entryResumePoint()->stackDepth()); JS_ASSERT(pred->stackDepth() == entryResumePoint()->stackDepth());
// We must be a pending loop header // We must be a pending loop header
JS_ASSERT(kind_ == PENDING_LOOP_HEADER); JS_ASSERT(kind_ == PENDING_LOOP_HEADER);
@ -911,6 +948,53 @@ MBasicBlock::setBackedge(MBasicBlock *pred)
return AbortReason_NoAbort; return AbortReason_NoAbort;
} }
bool
MBasicBlock::setBackedgeAsmJS(MBasicBlock *pred)
{
// Predecessors must be finished, and at the correct stack depth.
JS_ASSERT(lastIns_);
JS_ASSERT(pred->lastIns_);
JS_ASSERT(stackDepth() == pred->stackDepth());
// We must be a pending loop header
JS_ASSERT(kind_ == PENDING_LOOP_HEADER);
// Add exit definitions to each corresponding phi at the entry.
for (MPhiIterator phi = phisBegin(); phi != phisEnd(); phi++) {
MPhi *entryDef = *phi;
MDefinition *exitDef = pred->getSlot(entryDef->slot());
// Assert that we already placed phis for each slot.
JS_ASSERT(entryDef->block() == this);
// Assert that the phi already has the correct type.
JS_ASSERT(entryDef->type() == exitDef->type());
JS_ASSERT(entryDef->type() != MIRType_Value);
if (entryDef == exitDef) {
// If the exit def is the same as the entry def, make a redundant
// phi. Since loop headers have exactly two incoming edges, we
// know that that's just the first input.
//
// Note that we eliminate later rather than now, to avoid any
// weirdness around pending continue edges which might still hold
// onto phis.
exitDef = entryDef->getOperand(0);
}
// MBasicBlock::NewAsmJS calls reserveLength(2) for loop header phis.
entryDef->addInput(exitDef);
JS_ASSERT(entryDef->slot() < pred->stackDepth());
setSlot(entryDef->slot(), entryDef);
}
// We are now a loop header proper
kind_ = LOOP_HEADER;
return predecessors_.append(pred);
}
void void
MBasicBlock::clearLoopHeader() MBasicBlock::clearLoopHeader()
{ {

View File

@ -80,6 +80,8 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
static MBasicBlock *NewAbortPar(MIRGraph &graph, CompileInfo &info, static MBasicBlock *NewAbortPar(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, jsbytecode *entryPc, MBasicBlock *pred, jsbytecode *entryPc,
MResumePoint *resumePoint); MResumePoint *resumePoint);
static MBasicBlock *NewAsmJS(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, Kind kind);
bool dominates(MBasicBlock *other); bool dominates(MBasicBlock *other);
@ -196,6 +198,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
// the current loop as necessary. If the backedge introduces new types for // the current loop as necessary. If the backedge introduces new types for
// phis at the loop header, returns a disabling abort. // phis at the loop header, returns a disabling abort.
AbortReason setBackedge(MBasicBlock *block); AbortReason setBackedge(MBasicBlock *block);
bool setBackedgeAsmJS(MBasicBlock *block);
// Resets a LOOP_HEADER block to a NORMAL block. This is needed when // Resets a LOOP_HEADER block to a NORMAL block. This is needed when
// optimizations remove the backedge. // optimizations remove the backedge.

View File

@ -77,6 +77,7 @@ function testCollapsed(id, vPercent, startAt, expected) {
var c = document.getElementById("c" + id); var c = document.getElementById("c" + id);
var target = document.getElementById("target" + id); var target = document.getElementById("target" + id);
if (target.contentDocument) { if (target.contentDocument) {
selection = target.contentWindow.getSelection().QueryInterface(Components.interfaces.nsISelectionPrivate);
target = target.contentDocument.getElementById("target" + id); target = target.contentDocument.getElementById("target" + id);
} }
selection.collapse(target.parentNode, 0); selection.collapse(target.parentNode, 0);

Some files were not shown because too many files have changed in this diff Show More