Merge mozilla-inbound to mozilla-central. a=merge

This commit is contained in:
Cosmin Sabou 2018-09-11 13:06:37 +03:00
commit de7676288a
127 changed files with 2801 additions and 2230 deletions

View File

@ -58,15 +58,13 @@ var CaptivePortalWatcher = {
this._captivePortalDetected();
// Automatically open a captive portal tab if there's no other browser window.
let windows = Services.wm.getEnumerator("navigator:browser");
if (windows.getNext() == window && !windows.hasMoreElements()) {
if (BrowserWindowTracker.windowCount == 1) {
this.ensureCaptivePortalTab();
}
} else if (cps.state == cps.UNKNOWN) {
// We trigger a portal check after delayed startup to avoid doing a network
// request before first paint.
this._delayedRecheckPending = true;
Services.obs.addObserver(this, "browser-delayed-startup-finished");
}
XPCOMUtils.defineLazyPreferenceGetter(this, "PORTAL_RECHECK_DELAY_MS",
@ -78,22 +76,18 @@ var CaptivePortalWatcher = {
Services.obs.removeObserver(this, "captive-portal-login-abort");
Services.obs.removeObserver(this, "captive-portal-login-success");
if (this._delayedRecheckPending) {
Services.obs.removeObserver(this, "browser-delayed-startup-finished");
}
this._cancelDelayedCaptivePortal();
},
if (this._delayedCaptivePortalDetectedInProgress) {
Services.obs.removeObserver(this, "xul-window-visible");
delayedStartup() {
if (this._delayedRecheckPending) {
delete this._delayedRecheckPending;
cps.recheckCaptivePortal();
}
},
observe(aSubject, aTopic, aData) {
switch (aTopic) {
case "browser-delayed-startup-finished":
Services.obs.removeObserver(this, "browser-delayed-startup-finished");
delete this._delayedRecheckPending;
cps.recheckCaptivePortal();
break;
case "captive-portal-login":
this._captivePortalDetected();
break;
@ -101,8 +95,8 @@ var CaptivePortalWatcher = {
case "captive-portal-login-success":
this._captivePortalGone();
break;
case "xul-window-visible":
this._delayedCaptivePortalDetected();
case "delayed-captive-portal-handled":
this._cancelDelayedCaptivePortal();
break;
}
},
@ -113,9 +107,10 @@ var CaptivePortalWatcher = {
}
let win = BrowserWindowTracker.getTopWindow();
// Used by tests: ignore the main test window in order to enable testing of
// the case where we have no open windows.
if (win && win.document.documentElement.getAttribute("ignorecaptiveportal")) {
if (win.document.documentElement.getAttribute("ignorecaptiveportal")) {
win = null;
}
@ -123,9 +118,10 @@ var CaptivePortalWatcher = {
// This is so that if a different application was focused, when the user
// (re-)focuses a browser window, we open the tab immediately in that window
// so they can log in before continuing to browse.
if (win != Services.ww.activeWindow) {
if (win != Services.focus.activeWindow) {
this._delayedCaptivePortalDetectedInProgress = true;
Services.obs.addObserver(this, "xul-window-visible");
window.addEventListener("activate", this, { once: true });
Services.obs.addObserver(this, "delayed-captive-portal-handled");
}
this._showNotification();
@ -141,24 +137,14 @@ var CaptivePortalWatcher = {
return;
}
let win = BrowserWindowTracker.getTopWindow();
// Used by tests: ignore the main test window in order to enable testing of
// the case where we have no open windows.
if (win && win.document.documentElement.getAttribute("ignorecaptiveportal")) {
win = null;
}
if (win != Services.ww.activeWindow) {
// The window that got focused was not a browser window.
if (window.document.documentElement.getAttribute("ignorecaptiveportal")) {
return;
}
Services.obs.removeObserver(this, "xul-window-visible");
this._delayedCaptivePortalDetectedInProgress = false;
if (win != window) {
// Some other browser window got focus, we don't have to do anything.
return;
}
Services.obs.notifyObservers(null, "delayed-captive-portal-handled");
// Trigger a portal recheck. The user may have logged into the portal via
// another client, or changed networks.
cps.recheckCaptivePortal();
@ -185,31 +171,42 @@ var CaptivePortalWatcher = {
},
_captivePortalGone() {
if (this._delayedCaptivePortalDetectedInProgress) {
Services.obs.removeObserver(this, "xul-window-visible");
this._delayedCaptivePortalDetectedInProgress = false;
}
this._cancelDelayedCaptivePortal();
this._removeNotification();
},
_cancelDelayedCaptivePortal() {
if (this._delayedCaptivePortalDetectedInProgress) {
this._delayedCaptivePortalDetectedInProgress = false;
Services.obs.removeObserver(this, "delayed-captive-portal-handled");
window.removeEventListener("activate", this);
}
},
handleEvent(aEvent) {
if (aEvent.type != "TabSelect" || !this._captivePortalTab || !this._captivePortalNotification) {
return;
}
switch (aEvent.type) {
case "activate":
this._delayedCaptivePortalDetected();
break;
case "TabSelect":
if (!this._captivePortalTab || !this._captivePortalNotification) {
break;
}
let tab = this._captivePortalTab.get();
let n = this._captivePortalNotification;
if (!tab || !n) {
return;
}
let tab = this._captivePortalTab.get();
let n = this._captivePortalNotification;
if (!tab || !n) {
break;
}
let doc = tab.ownerDocument;
let button = n.querySelector("button.notification-button");
if (doc.defaultView.gBrowser.selectedTab == tab) {
button.style.visibility = "hidden";
} else {
button.style.visibility = "visible";
let doc = tab.ownerDocument;
let button = n.querySelector("button.notification-button");
if (doc.defaultView.gBrowser.selectedTab == tab) {
button.style.visibility = "hidden";
} else {
button.style.visibility = "visible";
}
break;
}
},

View File

@ -1559,6 +1559,8 @@ var gBrowserInit = {
}
});
CaptivePortalWatcher.delayedStartup();
this.delayedStartupFinished = true;
_resolveDelayedStartup();

View File

@ -24,7 +24,7 @@ let testCasesForBothSuccessAndAbort = [
await freePortal(aSuccess);
ensureNoPortalTab(win);
ensureNoPortalNotification(win);
await closeWindowAndWaitForXulWindowVisible(win);
await closeWindowAndWaitForWindowActivate(win);
},
/**
@ -57,7 +57,7 @@ let testCasesForBothSuccessAndAbort = [
ensureNoPortalTab(win2);
ensureNoPortalNotification(win2);
await closeWindowAndWaitForXulWindowVisible(win2);
await closeWindowAndWaitForWindowActivate(win2);
// No need to wait for xul-window-visible: after win2 is closed, focus
// is restored to the default window and win1 remains in the background.
await BrowserTestUtils.closeWindow(win1);
@ -77,7 +77,7 @@ let testCasesForBothSuccessAndAbort = [
await freePortal(aSuccess);
ensureNoPortalTab(win);
ensureNoPortalNotification(win);
await closeWindowAndWaitForXulWindowVisible(win);
await closeWindowAndWaitForWindowActivate(win);
},
/**
@ -95,7 +95,7 @@ let testCasesForBothSuccessAndAbort = [
});
ensureNoPortalTab(win);
ensureNoPortalNotification(win);
await closeWindowAndWaitForXulWindowVisible(win);
await closeWindowAndWaitForWindowActivate(win);
},
/**
@ -113,8 +113,8 @@ let testCasesForBothSuccessAndAbort = [
await freePortal(aSuccess);
ensureNoPortalNotification(win1);
ensureNoPortalNotification(win2);
await closeWindowAndWaitForXulWindowVisible(win2);
await closeWindowAndWaitForXulWindowVisible(win1);
await closeWindowAndWaitForWindowActivate(win2);
await closeWindowAndWaitForWindowActivate(win1);
},
];

View File

@ -21,7 +21,7 @@ let testcases = [
await freePortal(true);
ensurePortalTab(win);
ensureNoPortalNotification(win);
await closeWindowAndWaitForXulWindowVisible(win);
await closeWindowAndWaitForWindowActivate(win);
},
/**
@ -82,7 +82,7 @@ let testcases = [
await freePortal(true);
ensureNoPortalTab(win);
ensureNoPortalNotification(win);
await closeWindowAndWaitForXulWindowVisible(win);
await closeWindowAndWaitForWindowActivate(win);
},
];

View File

@ -60,7 +60,9 @@ async function focusWindowAndWaitForPortalUI(aLongRecheck, win) {
if (!win) {
win = await BrowserTestUtils.openNewBrowserWindow();
}
await SimpleTest.promiseFocus(win);
let windowActivePromise = waitForBrowserWindowActive(win);
win.focus();
await windowActivePromise;
// After a new window is opened, CaptivePortalWatcher asks for a recheck, and
// waits for it to complete. We need to manually tell it a recheck completed.
@ -128,26 +130,35 @@ function ensureNoPortalNotification(win) {
/**
* Some tests open a new window and close it later. When the window is closed,
* the original window opened by mochitest gains focus, generating a
* xul-window-visible notification. If the next test also opens a new window
* before this notification has a chance to fire, CaptivePortalWatcher picks
* the original window opened by mochitest gains focus, generating an
* activate event. If the next test also opens a new window
* before this event has a chance to fire, CaptivePortalWatcher picks
* up the first one instead of the one from the new window. To avoid this
* unfortunate intermittent timing issue, we wait for the notification from
* unfortunate intermittent timing issue, we wait for the event from
* the original window every time we close a window that we opened.
*/
function waitForXulWindowVisible() {
function waitForBrowserWindowActive(win) {
return new Promise(resolve => {
Services.obs.addObserver(function observe() {
Services.obs.removeObserver(observe, "xul-window-visible");
if (Services.focus.activeWindow == win) {
resolve();
}, "xul-window-visible");
} else {
win.addEventListener("activate", () => {
resolve();
}, { once: true });
}
});
}
async function closeWindowAndWaitForXulWindowVisible(win) {
let p = waitForXulWindowVisible();
async function closeWindowAndWaitForWindowActivate(win) {
let activationPromises = [];
for (let w of BrowserWindowTracker.orderedWindows) {
if (w != win &&
!win.document.documentElement.getAttribute("ignorecaptiveportal")) {
activationPromises.push(waitForBrowserWindowActive(win));
}
}
await BrowserTestUtils.closeWindow(win);
await p;
await Promise.race(activationPromises);
}
/**
@ -157,6 +168,6 @@ async function closeWindowAndWaitForXulWindowVisible(win) {
*/
async function openWindowAndWaitForFocus() {
let win = await BrowserTestUtils.openNewBrowserWindow();
await SimpleTest.promiseFocus(win);
await waitForBrowserWindowActive(win);
return win;
}

View File

@ -43,6 +43,7 @@ skip-if = os != "win" # Windows-specific handler application selection dialog
[browser_connection_bug1445991.js]
skip-if = (verify && debug && (os == 'linux' || os == 'mac'))
[browser_connection_dnsoverhttps.js]
skip-if = ccov # Skipping test on all ccov platforms
[browser_contentblocking.js]
[browser_cookies_exceptions.js]
[browser_defaultbrowser_alwayscheck.js]

View File

@ -66,7 +66,7 @@ add_task(async function test_windows_are_restored_in_reversed_z_order() {
await promiseBrowserState(gBrowserState);
let indexedTabLabels = [...gTestURLsMap.values()];
let tabsRestoredLabels = [...BrowserWindowTracker.orderedWindows].map(window => window.gBrowser.selectedTab.label);
let tabsRestoredLabels = BrowserWindowTracker.orderedWindows.map(window => window.gBrowser.selectedTab.label);
Assert.equal(tabsRestoredLabels[0], indexedTabLabels[2], "First restored tab should be last used tab");
Assert.equal(tabsRestoredLabels[1], indexedTabLabels[1], "Second restored tab is correct");

View File

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 2.0.815
Current extension version is: 2.0.843
Taken from upstream commit: d6927376
Taken from upstream commit: bf368f3a

View File

@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap
"use strict";
var pdfjsVersion = '2.0.815';
var pdfjsBuild = 'd6927376';
var pdfjsVersion = '2.0.843';
var pdfjsBuild = 'bf368f3a';
var pdfjsSharedUtil = __w_pdfjs_require__(1);
var pdfjsDisplayAPI = __w_pdfjs_require__(7);
var pdfjsDisplayTextLayer = __w_pdfjs_require__(19);
@ -4226,7 +4226,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
}
return worker.messageHandler.sendWithPromise('GetDocRequest', {
docId,
apiVersion: '2.0.815',
apiVersion: '2.0.843',
source: {
data: source.data,
url: source.url,
@ -5553,8 +5553,8 @@ var InternalRenderTask = function InternalRenderTaskClosure() {
}();
var version, build;
{
exports.version = version = '2.0.815';
exports.build = build = 'd6927376';
exports.version = version = '2.0.843';
exports.build = build = 'bf368f3a';
}
exports.getDocument = getDocument;
exports.LoopbackPort = LoopbackPort;
@ -6354,7 +6354,7 @@ var CanvasGraphics = function CanvasGraphicsClosure() {
if (canvasCtx) {
addContextCurrentTransform(canvasCtx);
}
this.cachedGetSinglePixelWidth = null;
this._cachedGetSinglePixelWidth = null;
}
function putBinaryImageData(ctx, imgData) {
if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {
@ -6829,12 +6829,12 @@ var CanvasGraphics = function CanvasGraphicsClosure() {
this.current = this.stateStack.pop();
this.ctx.restore();
this.pendingClip = null;
this.cachedGetSinglePixelWidth = null;
this._cachedGetSinglePixelWidth = null;
}
},
transform: function CanvasGraphics_transform(a, b, c, d, e, f) {
this.ctx.transform(a, b, c, d, e, f);
this.cachedGetSinglePixelWidth = null;
this._cachedGetSinglePixelWidth = null;
},
constructPath: function CanvasGraphics_constructPath(ops, args) {
var ctx = this.ctx;
@ -7177,7 +7177,7 @@ var CanvasGraphics = function CanvasGraphicsClosure() {
if (scale === 0 || lineWidth === 0) {
var fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
this.cachedGetSinglePixelWidth = null;
this._cachedGetSinglePixelWidth = null;
lineWidth = this.getSinglePixelWidth() * MIN_WIDTH_FACTOR;
}
} else {
@ -7269,7 +7269,7 @@ var CanvasGraphics = function CanvasGraphicsClosure() {
if (isTextInvisible || fontSize === 0) {
return;
}
this.cachedGetSinglePixelWidth = null;
this._cachedGetSinglePixelWidth = null;
ctx.save();
ctx.transform.apply(ctx, current.textMatrix);
ctx.translate(current.x, current.y);
@ -7737,14 +7737,12 @@ var CanvasGraphics = function CanvasGraphicsClosure() {
}
ctx.beginPath();
},
getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
if (this.cachedGetSinglePixelWidth === null) {
this.ctx.save();
var inverse = this.ctx.mozCurrentTransformInverse;
this.ctx.restore();
this.cachedGetSinglePixelWidth = Math.sqrt(Math.max(inverse[0] * inverse[0] + inverse[1] * inverse[1], inverse[2] * inverse[2] + inverse[3] * inverse[3]));
getSinglePixelWidth(scale) {
if (this._cachedGetSinglePixelWidth === null) {
const inverse = this.ctx.mozCurrentTransformInverse;
this._cachedGetSinglePixelWidth = Math.sqrt(Math.max(inverse[0] * inverse[0] + inverse[1] * inverse[1], inverse[2] * inverse[2] + inverse[3] * inverse[3]));
}
return this.cachedGetSinglePixelWidth;
return this._cachedGetSinglePixelWidth;
},
getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) {
var transform = this.ctx.mozCurrentTransform;
@ -10015,8 +10013,8 @@ var renderTextLayer = function renderTextLayerClosure() {
let fontFamily = textDiv.style.fontFamily;
if (fontSize !== this._layoutTextLastFontSize || fontFamily !== this._layoutTextLastFontFamily) {
this._layoutTextCtx.font = fontSize + ' ' + fontFamily;
this._lastFontSize = fontSize;
this._lastFontFamily = fontFamily;
this._layoutTextLastFontSize = fontSize;
this._layoutTextLastFontFamily = fontFamily;
}
let width = this._layoutTextCtx.measureText(textDiv.textContent).width;
let transform = '';

View File

@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap
"use strict";
var pdfjsVersion = '2.0.815';
var pdfjsBuild = 'd6927376';
var pdfjsVersion = '2.0.843';
var pdfjsBuild = 'bf368f3a';
var pdfjsCoreWorker = __w_pdfjs_require__(1);
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
@ -327,7 +327,7 @@ var WorkerMessageHandler = {
var cancelXHRs = null;
var WorkerTasks = [];
let apiVersion = docParams.apiVersion;
let workerVersion = '2.0.815';
let workerVersion = '2.0.843';
if (apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
}
@ -22285,7 +22285,7 @@ exports.CMapFactory = CMapFactory;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getFontType = exports.ProblematicCharRanges = exports.IdentityToUnicodeMap = exports.ToUnicodeMap = exports.FontFlags = exports.Font = exports.ErrorFont = exports.PRIVATE_USE_OFFSET_END = exports.PRIVATE_USE_OFFSET_START = exports.SEAC_ANALYSIS_ENABLED = undefined;
exports.getFontType = exports.IdentityToUnicodeMap = exports.ToUnicodeMap = exports.FontFlags = exports.Font = exports.ErrorFont = exports.SEAC_ANALYSIS_ENABLED = undefined;
var _util = __w_pdfjs_require__(2);
@ -22307,11 +22307,9 @@ var _stream = __w_pdfjs_require__(14);
var _type1_parser = __w_pdfjs_require__(38);
var PRIVATE_USE_OFFSET_START = 0xE000;
var PRIVATE_USE_OFFSET_END = 0xF8FF;
var SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false;
const PRIVATE_USE_AREAS = [[0xE000, 0xF8FF], [0x100000, 0x10FFFD]];
var PDF_GLYPH_SPACE_UNITS = 1000;
var SEAC_ANALYSIS_ENABLED = false;
var SEAC_ANALYSIS_ENABLED = true;
var FontFlags = {
FixedPitch: 1,
Serif: 2,
@ -22590,7 +22588,6 @@ var OpenTypeFileBuilder = function OpenTypeFileBuilderClosure() {
};
return OpenTypeFileBuilder;
}();
var ProblematicCharRanges = new Int32Array([0x0000, 0x0020, 0x007F, 0x00A1, 0x00AD, 0x00AE, 0x0600, 0x0780, 0x08A0, 0x10A0, 0x1780, 0x1800, 0x1C00, 0x1C50, 0x2000, 0x2010, 0x2011, 0x2012, 0x2028, 0x2030, 0x205F, 0x2070, 0x25CC, 0x25CD, 0x3000, 0x3001, 0x3164, 0x3165, 0xAA60, 0xAA80, 0xD800, 0xE000, 0xFFF0, 0x10000]);
var Font = function FontClosure() {
function Font(name, file, properties) {
var charCode;
@ -22794,58 +22791,33 @@ var Font = function FontClosure() {
}
return toFontChar;
}
function isProblematicUnicodeLocation(code) {
var i = 0,
j = ProblematicCharRanges.length - 1;
while (i < j) {
var c = i + j + 1 >> 1;
if (code < ProblematicCharRanges[c]) {
j = c - 1;
} else {
i = c;
}
}
return !(i & 1);
}
function adjustMapping(charCodeToGlyphId, properties, missingGlyphs) {
var toUnicode = properties.toUnicode;
var isSymbolic = !!(properties.flags & FontFlags.Symbolic);
var isIdentityUnicode = properties.toUnicode instanceof IdentityToUnicodeMap;
function adjustMapping(charCodeToGlyphId, hasGlyph, newGlyphZeroId) {
var newMap = Object.create(null);
var toFontChar = [];
var usedFontCharCodes = [];
var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START;
var privateUseAreaIndex = 0;
var nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0];
var privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1];
for (var originalCharCode in charCodeToGlyphId) {
originalCharCode |= 0;
var glyphId = charCodeToGlyphId[originalCharCode];
if (missingGlyphs[glyphId]) {
if (!hasGlyph(glyphId)) {
continue;
}
var fontCharCode = originalCharCode;
var hasUnicodeValue = false;
if (!isIdentityUnicode && toUnicode.has(originalCharCode)) {
hasUnicodeValue = true;
var unicode = toUnicode.get(fontCharCode);
if (unicode.length === 1) {
fontCharCode = unicode.charCodeAt(0);
if (nextAvailableFontCharCode > privateUseOffetEnd) {
privateUseAreaIndex++;
if (privateUseAreaIndex >= PRIVATE_USE_AREAS.length) {
(0, _util.warn)('Ran out of space in font private use area.');
break;
}
nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0];
privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1];
}
if (usedFontCharCodes[fontCharCode] !== undefined || isProblematicUnicodeLocation(fontCharCode) || isSymbolic && !hasUnicodeValue) {
do {
if (nextAvailableFontCharCode > PRIVATE_USE_OFFSET_END) {
(0, _util.warn)('Ran out of space in font private use area.');
break;
}
fontCharCode = nextAvailableFontCharCode++;
if (SKIP_PRIVATE_USE_RANGE_F000_TO_F01F && fontCharCode === 0xF000) {
fontCharCode = 0xF020;
nextAvailableFontCharCode = fontCharCode + 1;
}
} while (usedFontCharCodes[fontCharCode] !== undefined);
var fontCharCode = nextAvailableFontCharCode++;
if (glyphId === 0) {
glyphId = newGlyphZeroId;
}
newMap[fontCharCode] = glyphId;
toFontChar[originalCharCode] = fontCharCode;
usedFontCharCodes[fontCharCode] = true;
}
return {
toFontChar,
@ -23032,6 +23004,9 @@ var Font = function FontClosure() {
throw new _util.FormatError('Unicode ranges Bits > 123 are reserved for internal usage');
}
}
if (lastCharIndex > 0xFFFF) {
lastCharIndex = 0xFFFF;
}
} else {
firstCharIndex = 0;
lastCharIndex = 255;
@ -23585,13 +23560,12 @@ var Font = function FontClosure() {
data[offset + 1] = value >> 1 & 0xFF;
};
}
var numGlyphsOut = dupFirstEntry ? numGlyphs + 1 : numGlyphs;
var locaData = loca.data;
var locaDataSize = itemSize * (1 + numGlyphs);
if (locaData.length !== locaDataSize) {
locaData = new Uint8Array(locaDataSize);
locaData.set(loca.data.subarray(0, locaDataSize));
loca.data = locaData;
}
var locaDataSize = itemSize * (1 + numGlyphsOut);
locaData = new Uint8Array(locaDataSize);
locaData.set(loca.data.subarray(0, locaDataSize));
loca.data = locaData;
var oldGlyfData = glyf.data;
var oldGlyfDataLength = oldGlyfData.length;
var newGlyfData = new Uint8Array(oldGlyfDataLength);
@ -23600,8 +23574,7 @@ var Font = function FontClosure() {
var missingGlyphs = Object.create(null);
itemEncode(locaData, 0, writeOffset);
var i, j;
var locaCount = dupFirstEntry ? numGlyphs - 1 : numGlyphs;
for (i = 0, j = itemSize; i < locaCount; i++, j += itemSize) {
for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
var endOffset = itemDecode(locaData, j);
if (endOffset === 0) {
endOffset = startOffset;
@ -23626,7 +23599,7 @@ var Font = function FontClosure() {
}
if (writeOffset === 0) {
var simpleGlyph = new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);
for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
for (i = 0, j = itemSize; i < numGlyphsOut; i++, j += itemSize) {
itemEncode(locaData, j, simpleGlyph.length);
}
glyf.data = simpleGlyph;
@ -24045,7 +24018,14 @@ var Font = function FontClosure() {
}
font.pos = (font.start || 0) + tables['maxp'].offset;
var version = font.getInt32();
var numGlyphs = font.getUint16();
const numGlyphs = font.getUint16();
let numGlyphsOut = numGlyphs + 1;
let dupFirstEntry = true;
if (numGlyphsOut > 0xFFFF) {
dupFirstEntry = false;
numGlyphsOut = numGlyphs;
(0, _util.warn)('Not enough space in glyfs to duplicate first glyph.');
}
var maxFunctionDefs = 0;
var maxSizeOfInstructions = 0;
if (version >= 0x00010000 && tables['maxp'].length >= 22) {
@ -24060,20 +24040,15 @@ var Font = function FontClosure() {
font.pos += 4;
maxSizeOfInstructions = font.getUint16();
}
var dupFirstEntry = false;
if (properties.type === 'CIDFontType2' && properties.toUnicode && properties.toUnicode.get(0) > '\u0000') {
dupFirstEntry = true;
numGlyphs++;
tables['maxp'].data[4] = numGlyphs >> 8;
tables['maxp'].data[5] = numGlyphs & 255;
}
tables['maxp'].data[4] = numGlyphsOut >> 8;
tables['maxp'].data[5] = numGlyphsOut & 255;
var hintsValid = sanitizeTTPrograms(tables['fpgm'], tables['prep'], tables['cvt '], maxFunctionDefs);
if (!hintsValid) {
delete tables['fpgm'];
delete tables['prep'];
delete tables['cvt '];
}
sanitizeMetrics(font, tables['hhea'], tables['hmtx'], numGlyphs);
sanitizeMetrics(font, tables['hhea'], tables['hmtx'], numGlyphsOut);
if (!tables['head']) {
throw new _util.FormatError('Required "head" table is not found');
}
@ -24105,11 +24080,12 @@ var Font = function FontClosure() {
this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm;
this.descent = metricsOverride.descent / metricsOverride.unitsPerEm;
if (tables['post']) {
var valid = readPostScriptTable(tables['post'], properties, numGlyphs);
if (!valid) {
tables['post'] = null;
}
readPostScriptTable(tables['post'], properties, numGlyphs);
}
tables['post'] = {
tag: 'post',
data: createPostTable(properties)
};
var charCodeToGlyphId = [],
charCode;
function hasGlyph(glyphId) {
@ -24132,9 +24108,6 @@ var Font = function FontClosure() {
charCodeToGlyphId[charCode] = glyphId;
}
});
if (dupFirstEntry && (isCidToGidMapEmpty || !charCodeToGlyphId[0])) {
charCodeToGlyphId[0] = numGlyphs - 1;
}
} else {
var cmapTable = readCmapTable(tables['cmap'], font, this.isSymbolicFont, properties.hasEncoding);
var cmapPlatformId = cmapTable.platformId;
@ -24202,11 +24175,15 @@ var Font = function FontClosure() {
if (charCodeToGlyphId.length === 0) {
charCodeToGlyphId[0] = 0;
}
var newMapping = adjustMapping(charCodeToGlyphId, properties, missingGlyphs);
let glyphZeroId = numGlyphsOut - 1;
if (!dupFirstEntry) {
glyphZeroId = 0;
}
var newMapping = adjustMapping(charCodeToGlyphId, hasGlyph, glyphZeroId);
this.toFontChar = newMapping.toFontChar;
tables['cmap'] = {
tag: 'cmap',
data: createCmapTable(newMapping.charCodeToGlyphId, numGlyphs)
data: createCmapTable(newMapping.charCodeToGlyphId, numGlyphsOut)
};
if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) {
tables['OS/2'] = {
@ -24214,17 +24191,12 @@ var Font = function FontClosure() {
data: createOS2Table(properties, newMapping.charCodeToGlyphId, metricsOverride)
};
}
if (!tables['post']) {
tables['post'] = {
tag: 'post',
data: createPostTable(properties)
};
}
if (!isTrueType) {
try {
cffFile = new _stream.Stream(tables['CFF '].data);
var parser = new _cff_parser.CFFParser(cffFile, properties, SEAC_ANALYSIS_ENABLED);
cff = parser.parse();
cff.duplicateFirstGlyph();
var compiler = new _cff_parser.CFFCompiler(cff);
tables['CFF '].data = compiler.compile();
} catch (e) {
@ -24251,8 +24223,12 @@ var Font = function FontClosure() {
if (properties.builtInEncoding) {
adjustToUnicode(properties, properties.builtInEncoding);
}
let glyphZeroId = 1;
if (font instanceof CFFFont) {
glyphZeroId = font.numGlyphs - 1;
}
var mapping = font.getGlyphMapping(properties);
var newMapping = adjustMapping(mapping, properties, Object.create(null));
var newMapping = adjustMapping(mapping, font.hasGlyphId.bind(font), glyphZeroId);
this.toFontChar = newMapping.toFontChar;
var numGlyphs = font.numGlyphs;
function getCharCodes(charCodeToGlyphId, glyphId) {
@ -24403,11 +24379,11 @@ var Font = function FontClosure() {
var seac = this.seacMap[charcode];
fontCharCode = seac.baseFontCharCode;
accent = {
fontChar: String.fromCharCode(seac.accentFontCharCode),
fontChar: String.fromCodePoint(seac.accentFontCharCode),
offset: seac.accentOffset
};
}
var fontChar = String.fromCharCode(fontCharCode);
var fontChar = typeof fontCharCode === 'number' ? String.fromCodePoint(fontCharCode) : '';
var glyph = this.glyphCache[charcode];
if (!glyph || !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont)) {
glyph = new Glyph(fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont);
@ -24669,6 +24645,16 @@ var Type1Font = function Type1FontClosure() {
}
return type1FontGlyphMapping(properties, builtInEncoding, glyphNames);
},
hasGlyphId: function Type1Font_hasGlyphID(id) {
if (id < 0 || id >= this.numGlyphs) {
return false;
}
if (id === 0) {
return true;
}
var glyph = this.charstrings[id - 1];
return glyph.charstring.length > 0;
},
getSeacs: function Type1Font_getSeacs(charstrings) {
var i, ii;
var seacMap = [];
@ -24746,12 +24732,7 @@ var Type1Font = function Type1FontClosure() {
var charStringsIndex = new _cff_parser.CFFIndex();
charStringsIndex.add([0x8B, 0x0E]);
for (i = 0; i < count; i++) {
var glyph = glyphs[i];
if (glyph.length === 0) {
charStringsIndex.add([0x8B, 0x0E]);
continue;
}
charStringsIndex.add(glyph);
charStringsIndex.add(glyphs[i]);
}
cff.charStrings = charStringsIndex;
var privateDict = new _cff_parser.CFFPrivateDict();
@ -24787,6 +24768,7 @@ var CFFFont = function CFFFontClosure() {
this.properties = properties;
var parser = new _cff_parser.CFFParser(file, properties, SEAC_ANALYSIS_ENABLED);
this.cff = parser.parse();
this.cff.duplicateFirstGlyph();
var compiler = new _cff_parser.CFFCompiler(this.cff);
this.seacs = this.cff.seacs;
try {
@ -24827,29 +24809,19 @@ var CFFFont = function CFFFontClosure() {
var encoding = cff.encoding ? cff.encoding.encoding : null;
charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
return charCodeToGlyphId;
},
hasGlyphId: function CFFFont_hasGlyphID(id) {
return this.cff.hasGlyphId(id);
}
};
return CFFFont;
}();
(function checkSeacSupport() {
if (typeof navigator !== 'undefined' && /Windows/.test(navigator.userAgent)) {
exports.SEAC_ANALYSIS_ENABLED = SEAC_ANALYSIS_ENABLED = true;
}
})();
(function checkChromeWindows() {
if (typeof navigator !== 'undefined' && /Windows.*Chrome/.test(navigator.userAgent)) {
SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = true;
}
})();
exports.SEAC_ANALYSIS_ENABLED = SEAC_ANALYSIS_ENABLED;
exports.PRIVATE_USE_OFFSET_START = PRIVATE_USE_OFFSET_START;
exports.PRIVATE_USE_OFFSET_END = PRIVATE_USE_OFFSET_END;
exports.ErrorFont = ErrorFont;
exports.Font = Font;
exports.FontFlags = FontFlags;
exports.ToUnicodeMap = ToUnicodeMap;
exports.IdentityToUnicodeMap = IdentityToUnicodeMap;
exports.ProblematicCharRanges = ProblematicCharRanges;
exports.getFontType = getFontType;
/***/ }),
@ -24862,7 +24834,7 @@ exports.getFontType = getFontType;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.CFFCompiler = exports.CFFPrivateDict = exports.CFFTopDict = exports.CFFCharset = exports.CFFIndex = exports.CFFStrings = exports.CFFHeader = exports.CFF = exports.CFFParser = exports.CFFStandardStrings = undefined;
exports.CFFFDSelect = exports.CFFCompiler = exports.CFFPrivateDict = exports.CFFTopDict = exports.CFFCharset = exports.CFFIndex = exports.CFFStrings = exports.CFFHeader = exports.CFF = exports.CFFParser = exports.CFFStandardStrings = undefined;
var _util = __w_pdfjs_require__(2);
@ -25626,20 +25598,16 @@ var CFFParser = function CFFParserClosure() {
return new CFFEncoding(predefined, format, encoding, raw);
},
parseFDSelect: function CFFParser_parseFDSelect(pos, length) {
var start = pos;
var bytes = this.bytes;
var format = bytes[pos++];
var fdSelect = [],
rawBytes;
var i,
invalidFirstGID = false;
var fdSelect = [];
var i;
switch (format) {
case 0:
for (i = 0; i < length; ++i) {
var id = bytes[pos++];
fdSelect.push(id);
}
rawBytes = bytes.subarray(start, pos);
break;
case 3:
var rangesCount = bytes[pos++] << 8 | bytes[pos++];
@ -25647,7 +25615,6 @@ var CFFParser = function CFFParserClosure() {
var first = bytes[pos++] << 8 | bytes[pos++];
if (i === 0 && first !== 0) {
(0, _util.warn)('parseFDSelect: The first range must have a first GID of 0' + ' -- trying to recover.');
invalidFirstGID = true;
first = 0;
}
var fdIndex = bytes[pos++];
@ -25657,10 +25624,6 @@ var CFFParser = function CFFParserClosure() {
}
}
pos += 2;
rawBytes = bytes.subarray(start, pos);
if (invalidFirstGID) {
rawBytes[3] = rawBytes[4] = 0;
}
break;
default:
throw new _util.FormatError(`parseFDSelect: Unknown format "${format}".`);
@ -25668,7 +25631,7 @@ var CFFParser = function CFFParserClosure() {
if (fdSelect.length !== length) {
throw new _util.FormatError('parseFDSelect: Invalid font data.');
}
return new CFFFDSelect(fdSelect, rawBytes);
return new CFFFDSelect(format, fdSelect);
}
};
return CFFParser;
@ -25687,6 +25650,26 @@ var CFF = function CFFClosure() {
this.fdSelect = null;
this.isCIDFont = false;
}
CFF.prototype = {
duplicateFirstGlyph: function CFF_duplicateFirstGlyph() {
if (this.charStrings.count >= 65535) {
(0, _util.warn)('Not enough space in charstrings to duplicate first glyph.');
return;
}
var glyphZero = this.charStrings.get(0);
this.charStrings.add(glyphZero);
if (this.isCIDFont) {
this.fdSelect.fdSelect.push(this.fdSelect.fdSelect[0]);
}
},
hasGlyphId: function CFF_hasGlyphID(id) {
if (id < 0 || id >= this.charStrings.count) {
return false;
}
var glyph = this.charStrings.get(id);
return glyph.length > 0;
}
};
return CFF;
}();
var CFFHeader = function CFFHeaderClosure() {
@ -25873,9 +25856,9 @@ var CFFEncoding = function CFFEncodingClosure() {
return CFFEncoding;
}();
var CFFFDSelect = function CFFFDSelectClosure() {
function CFFFDSelect(fdSelect, raw) {
function CFFFDSelect(format, fdSelect) {
this.format = format;
this.fdSelect = fdSelect;
this.raw = raw;
}
CFFFDSelect.prototype = {
getFDIndex: function CFFFDSelect_get(glyphIndex) {
@ -25966,6 +25949,7 @@ var CFFCompiler = function CFFCompilerClosure() {
}
}
}
cff.topDict.setByName('charset', 0);
var compiled = this.compileTopDicts([cff.topDict], output.length, cff.isCIDFont);
output.add(compiled.output);
var topDictTracker = compiled.trackers[0];
@ -25982,21 +25966,15 @@ var CFFCompiler = function CFFCompilerClosure() {
output.add(encoding);
}
}
if (cff.charset && cff.topDict.hasName('charset')) {
if (cff.charset.predefined) {
topDictTracker.setEntryLocation('charset', [cff.charset.format], output);
} else {
var charset = this.compileCharset(cff.charset);
topDictTracker.setEntryLocation('charset', [output.length], output);
output.add(charset);
}
}
var charset = this.compileCharset(cff.charset);
topDictTracker.setEntryLocation('charset', [output.length], output);
output.add(charset);
var charStrings = this.compileCharStrings(cff.charStrings);
topDictTracker.setEntryLocation('CharStrings', [output.length], output);
output.add(charStrings);
if (cff.isCIDFont) {
topDictTracker.setEntryLocation('FDSelect', [output.length], output);
var fdSelect = this.compileFDSelect(cff.fdSelect.raw);
var fdSelect = this.compileFDSelect(cff.fdSelect);
output.add(fdSelect);
compiled = this.compileTopDicts(cff.fdArray, output.length, true);
topDictTracker.setEntryLocation('FDArray', [output.length], output);
@ -26191,16 +26169,55 @@ var CFFCompiler = function CFFCompilerClosure() {
this.out.writeByteArray(this.compileIndex(globalSubrIndex));
},
compileCharStrings: function CFFCompiler_compileCharStrings(charStrings) {
return this.compileIndex(charStrings);
var charStringsIndex = new CFFIndex();
for (var i = 0; i < charStrings.count; i++) {
var glyph = charStrings.get(i);
if (glyph.length === 0) {
charStringsIndex.add(new Uint8Array([0x8B, 0x0E]));
continue;
}
charStringsIndex.add(glyph);
}
return this.compileIndex(charStringsIndex);
},
compileCharset: function CFFCompiler_compileCharset(charset) {
return this.compileTypedArray(charset.raw);
let length = 1 + (this.cff.charStrings.count - 1) * 2;
let out = new Uint8Array(length);
return this.compileTypedArray(out);
},
compileEncoding: function CFFCompiler_compileEncoding(encoding) {
return this.compileTypedArray(encoding.raw);
},
compileFDSelect: function CFFCompiler_compileFDSelect(fdSelect) {
return this.compileTypedArray(fdSelect);
let format = fdSelect.format;
let out, i;
switch (format) {
case 0:
out = new Uint8Array(1 + fdSelect.fdSelect.length);
out[0] = format;
for (i = 0; i < fdSelect.fdSelect.length; i++) {
out[i + 1] = fdSelect.fdSelect[i];
}
break;
case 3:
let start = 0;
let lastFD = fdSelect.fdSelect[0];
let ranges = [format, 0, 0, start >> 8 & 0xFF, start & 0xFF, lastFD];
for (i = 1; i < fdSelect.fdSelect.length; i++) {
let currentFD = fdSelect.fdSelect[i];
if (currentFD !== lastFD) {
ranges.push(i >> 8 & 0xFF, i & 0xFF, currentFD);
lastFD = currentFD;
}
}
let numRanges = (ranges.length - 3) / 3;
ranges[1] = numRanges >> 8 & 0xFF;
ranges[2] = numRanges & 0xFF;
ranges.push(i >> 8 & 0xFF, i & 0xFF);
out = new Uint8Array(ranges);
break;
}
return this.compileTypedArray(out);
},
compileTypedArray: function CFFCompiler_compileTypedArray(data) {
var out = [];
@ -26271,6 +26288,7 @@ exports.CFFCharset = CFFCharset;
exports.CFFTopDict = CFFTopDict;
exports.CFFPrivateDict = CFFPrivateDict;
exports.CFFCompiler = CFFCompiler;
exports.CFFFDSelect = CFFFDSelect;
/***/ }),
/* 32 */
@ -33703,7 +33721,7 @@ var FontRendererFactory = function FontRendererFactoryClosure() {
return glyphs;
}
function lookupCmap(ranges, unicode) {
var code = unicode.charCodeAt(0),
var code = unicode.codePointAt(0),
gid = 0;
var l = 0,
r = ranges.length - 1;

View File

@ -82,11 +82,15 @@ See https://github.com/adobe-type-tools/cmap-resources
</div>
</div>
<div id="findbarOptionsContainer">
<div id="findbarOptionsOneContainer">
<input type="checkbox" id="findHighlightAll" class="toolbarField" tabindex="94">
<label for="findHighlightAll" class="toolbarLabel" data-l10n-id="find_highlight">Highlight all</label>
<input type="checkbox" id="findMatchCase" class="toolbarField" tabindex="95">
<label for="findMatchCase" class="toolbarLabel" data-l10n-id="find_match_case_label">Match case</label>
</div>
<div id="findbarOptionsTwoContainer">
<input type="checkbox" id="findEntireWord" class="toolbarField" tabindex="96">
<label for="findEntireWord" class="toolbarLabel" data-l10n-id="find_entire_word_label">Whole words</label>
<span id="findResultsCount" class="toolbarLabel hidden"></span>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: version 2.0.815
release: version 2.0.843
# The package's license, where possible using the mnemonic from
# https://spdx.org/licenses/

View File

@ -165,8 +165,16 @@ find_next.title=Find the next occurrence of the phrase
find_next_label=Next
find_highlight=Highlight all
find_match_case_label=Match case
find_entire_word_label=Whole words
find_reached_top=Reached top of document, continued from bottom
find_reached_bottom=Reached end of document, continued from top
# LOCALIZATION NOTE (find_matches_count): "{{current}}" and "{{total}}" will be
# replaced by a number representing the index of the currently active find result,
# respectively a number representing the total number of matches in the document.
find_matches_count={{current}} of {{total}} matches
# LOCALIZATION NOTE (find_matches_count_limit): "{{limit}}" will be replaced by
# a numerical value.
find_matches_count_limit=More than {{limit}} matches
find_not_found=Phrase not found
# Error panel labels

View File

@ -13,13 +13,10 @@ var EXPORTED_SYMBOLS = [
];
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyGlobalGetters(this, ["URLSearchParams"]);
// The upper bound for the count of the visited unique domain names.
const MAX_UNIQUE_VISITED_DOMAINS = 100;
@ -202,29 +199,7 @@ let URICountListener = {
return;
}
let parseURLResult = Services.search.parseSubmissionURL(uriSpec);
if (parseURLResult.engine) {
this._recordSearchTelemetry(uriSpec, parseURLResult);
} else if (this._urlsQueuedForParsing) {
if (Services.search.isInitialized) {
this._urlsQueuedForParsing = null;
} else {
this._urlsQueuedForParsing.push(uriSpec);
if (this._urlsQueuedForParsing.length == 1) {
Services.search.init(rv => {
if (Components.isSuccessCode(rv)) {
for (let url of this._urlsQueuedForParsing) {
let innerParseURLResult = Services.search.parseSubmissionURL(url);
if (innerParseURLResult.engine) {
this._recordSearchTelemetry(url, innerParseURLResult);
}
}
}
this._urlsQueuedForParsing = null;
});
}
}
}
Services.search.recordSearchURLTelemetry(uriSpec);
if (!shouldCountURI) {
return;
@ -262,31 +237,6 @@ let URICountListener = {
this._domainSet.clear();
},
_urlsQueuedForParsing: [],
_recordSearchTelemetry(url, parseURLResult) {
switch (parseURLResult.engine.identifier) {
case "google":
case "google-2018":
let type;
let queries = new URLSearchParams(url.split("#")[0].split("?")[1]);
let code = queries.get("client");
if (code) {
// Detecting follow-on searches for sap is a little tricky.
// There are a few parameters that only show up
// with follow-ons, so we look for those. (oq/ved/ei)
type = queries.has("oq") || queries.has("ved") || queries.has("ei") ? "sap-follow-on" : "sap";
} else {
type = "organic";
}
let payload = `google.in-content:${type}:${code || "none"}`;
let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
histogram.add(payload);
break;
}
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference]),
};

View File

@ -14,7 +14,6 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
// Lazy getters
XPCOMUtils.defineLazyModuleGetters(this, {
AppConstants: "resource://gre/modules/AppConstants.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
});
@ -145,44 +144,6 @@ var WindowHelper = {
_trackedWindows.push(window);
}
},
getTopWindow(options) {
let checkPrivacy = typeof options == "object" &&
"private" in options;
let allowPopups = typeof options == "object" && !!options.allowPopups;
function isSuitableBrowserWindow(win) {
return (!win.closed &&
(allowPopups || win.toolbar.visible) &&
(!checkPrivacy ||
PrivateBrowsingUtils.permanentPrivateBrowsing ||
PrivateBrowsingUtils.isWindowPrivate(win) == options.private));
}
let broken_wm_z_order =
AppConstants.platform != "macosx" && AppConstants.platform != "win";
if (broken_wm_z_order) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
// if we're lucky, this isn't a popup, and we can just return this
if (win && !isSuitableBrowserWindow(win)) {
win = null;
// this is oldest to newest, so this gets a bit ugly
for (let nextWin of Services.wm.getEnumerator("navigator:browser")) {
if (isSuitableBrowserWindow(nextWin))
win = nextWin;
}
}
return win;
}
for (let win of Services.wm.getZOrderDOMWindowEnumerator("navigator:browser", true)) {
if (isSuitableBrowserWindow(win))
return win;
}
return null;
},
};
this.BrowserWindowTracker = {
@ -195,23 +156,34 @@ this.BrowserWindowTracker = {
* Omit the property to search in both groups.
* * allowPopups: true if popup windows are permissable.
*/
getTopWindow(options) {
return WindowHelper.getTopWindow(options);
getTopWindow(options = {}) {
for (let win of _trackedWindows) {
if (!win.closed &&
(options.allowPopups || win.toolbar.visible) &&
(!("private" in options) ||
PrivateBrowsingUtils.permanentPrivateBrowsing ||
PrivateBrowsingUtils.isWindowPrivate(win) == options.private)) {
return win;
}
}
return null;
},
/**
* Iterator property that yields window objects by z-index, in reverse order.
* This means that the lastly focused window will the first item that is yielded.
* Note: we only know the order of windows we're actively tracking, which
* basically means _only_ browser windows.
* Number of currently open browser windows.
*/
orderedWindows: {
* [Symbol.iterator]() {
// Clone the windows array immediately as it may change during iteration,
// we'd rather have an outdated order than skip/revisit windows.
for (let window of [..._trackedWindows])
yield window;
},
get windowCount() {
return _trackedWindows.length;
},
/**
* Array of browser windows ordered by z-index, in reverse order.
* This means that the top-most browser window will be the first item.
*/
get orderedWindows() {
// Clone the windows array immediately as it may change during iteration,
// we'd rather have an outdated order than skip/revisit windows.
return [..._trackedWindows];
},
track(window) {

View File

@ -79,7 +79,9 @@ add_task(async function test_getTopWindow() {
add_task(async function test_orderedWindows() {
await withOpenWindows(10, async function(windows) {
let ordered = [...BrowserWindowTracker.orderedWindows].filter(w => w != TEST_WINDOW);
Assert.equal(BrowserWindowTracker.windowCount, 11,
"Number of tracked windows, including the test window");
let ordered = BrowserWindowTracker.orderedWindows.filter(w => w != TEST_WINDOW);
Assert.deepEqual([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], ordered.map(w => windows.indexOf(w)),
"Order of opened windows should be as opened.");
@ -90,7 +92,7 @@ add_task(async function test_orderedWindows() {
await promise;
}
let ordered2 = [...BrowserWindowTracker.orderedWindows].filter(w => w != TEST_WINDOW);
let ordered2 = BrowserWindowTracker.orderedWindows.filter(w => w != TEST_WINDOW);
// After the shuffle, we expect window '1' to be the top-most window, because
// it was the last one we called focus on. Then '6', the window we focused
// before-last, followed by '4'. The order of the other windows remains
@ -104,7 +106,7 @@ add_task(async function test_orderedWindows() {
windows[9].minimize();
await promise;
let ordered3 = [...BrowserWindowTracker.orderedWindows].filter(w => w != TEST_WINDOW);
let ordered3 = BrowserWindowTracker.orderedWindows.filter(w => w != TEST_WINDOW);
// Test the end of the array of window indices, because Windows Debug builds
// mysteriously swap the order of the first two windows.
Assert.deepEqual([8, 7, 5, 3, 2, 0, 9], ordered3.map(w => windows.indexOf(w)).slice(3),

View File

@ -483,3 +483,7 @@ def alter_path(sdk_bin_path):
set_config('PATH', alter_path)
check_prog('MAKECAB', ('makecab.exe',))
# Make sure that the build system can handle non-ASCII characters in
# environment variables to prevent silent breakage on non-English systems.
set_config('NONASCII', b'\241\241')

View File

@ -5,7 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsIPaymentActionRequest.idl',
'nsIPaymentActionResponse.idl',
'nsIPaymentAddress.idl',
'nsIPaymentRequest.idl',

View File

@ -1,161 +0,0 @@
/* -*- 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 "nsISupports.idl"
#include "nsIVariant.idl"
#include "nsIPaymentRequest.idl"
#include "nsIPaymentActionResponse.idl"
#include "nsIPaymentAddress.idl"
interface nsIArray;
[builtinclass, uuid(3fef5459-b0ea-469b-be9f-b99e8ca75d3d)]
interface nsIPaymentActionCallback : nsISupports
{
void respondPayment(in nsIPaymentActionResponse aResponse);
void changeShippingAddress(in AString aRequestId, in nsIPaymentAddress aAddress);
void changeShippingOption(in AString aRequestId, in AString aOption);
};
[builtinclass, uuid(7ddbe8be-beac-4952-96f6-619981dff7a6)]
interface nsIPaymentActionRequest : nsISupports
{
const uint32_t UNKNOWN_ACTION = 0;
const uint32_t CREATE_ACTION = 1;
const uint32_t CANMAKE_ACTION = 2;
const uint32_t SHOW_ACTION = 3;
const uint32_t ABORT_ACTION = 4;
const uint32_t COMPLETE_ACTION = 5;
const uint32_t UPDATE_ACTION = 6;
const uint32_t CLOSE_ACTION = 7;
/*
* The payment request identifier.
*/
readonly attribute AString requestId;
/*
* The type of the requested task.
*/
readonly attribute uint32_t type;
/*
* The callback for the response from UI module
*/
readonly attribute nsIPaymentActionCallback callback;
/*
* Initialize function for this request.
*/
void init(in AString aRequestId,
in uint32_t aType,
in nsIPaymentActionCallback aCallback);
};
[builtinclass, uuid(1d38dce6-8bcd-441b-aa94-68e300b6e175)]
interface nsIPaymentCreateActionRequest : nsIPaymentActionRequest
{
/*
* The tab identifier
*/
readonly attribute uint64_t tabId;
/*
* The top level document's principal
*/
readonly attribute nsIPrincipal topLevelPrincipal;
/*
* The methodData information of the payment request.
*/
readonly attribute nsIArray methodData;
/*
* The Details information of the payment request.
*/
readonly attribute nsIPaymentDetails details;
/*
* The Options information of the payment request.
*/
readonly attribute nsIPaymentOptions options;
/*
* The selected shipping option of the payment request;
*/
readonly attribute AString shippingOption;
/*
* Initialize function the this request.
*/
void initRequest(in AString aRequestId,
in nsIPaymentActionCallback aCallback,
in uint64_t aTabId,
in nsIPrincipal aPrincipal,
in nsIArray aMethodData,
in nsIPaymentDetails aDetails,
in nsIPaymentOptions aOptions,
in AString aShippingOption);
};
[builtinclass, uuid(4429697d-1135-47de-a46e-5196d399ec55)]
interface nsIPaymentCompleteActionRequest : nsIPaymentActionRequest
{
/*
* The complete status from merchant side.
*/
readonly attribute AString completeStatus;
/*
* Initialize function for this request.
*/
void initRequest(in AString aRequestId,
in nsIPaymentActionCallback aCallback,
in AString aCompleteStatus);
};
[builtinclass, uuid(21f631e8-c047-4fd8-b3c6-68e26c62639a)]
interface nsIPaymentUpdateActionRequest : nsIPaymentActionRequest
{
/*
* The details information for updating the specified payment request.
*/
readonly attribute nsIPaymentDetails details;
/*
* The selected shipping option information
*/
readonly attribute AString shippingOption;
/*
* Initialize function for this request.
*/
void initRequest(in AString aRequestId,
in nsIPaymentActionCallback aCallback,
in nsIPaymentDetails aDetails,
in AString aShippingOption);
};
%{C++
#define NS_PAYMENT_ACTION_REQUEST_CID \
{ 0x7ddbe8be, 0xbeac, 0x4952, { 0x96, 0xf6, 0x61, 0x99, 0x81, 0xdf, 0xf7, 0xa6 } }
#define NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID \
"@mozilla.org/dom/payments/payment-action-request;1"
#define NS_PAYMENT_CREATE_ACTION_REQUEST_CID \
{ 0x1d38dce6, 0x8bcd, 0x441b, { 0xaa, 0x94, 0x68, 0xe3, 0x00, 0xb6, 0xe1, 0x75 } }
#define NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID \
"@mozilla.org/dom/payments/payment-create-action-request;1"
#define NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID \
{ 0x4429697d, 0x1135, 0x47de, { 0xa4, 0x6e, 0x51, 0x96, 0xd3, 0x99, 0xec, 0x55 } }
#define NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID \
"@mozilla.org/dom/payments/payment-complete-action-request;1"
#define NS_PAYMENT_UPDATE_ACTION_REQUEST_CID \
{ 0x21f631e8, 0xc047, 0x4fd8, { 0xb3, 0xc6, 0x68, 0xe2, 0x6c, 0x62, 0x63, 0x9a } }
#define NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID \
"@mozilla.org/dom/payments/payment-update-action-request;1"
%}

View File

@ -63,9 +63,10 @@ interface nsIPaymentDetails : nsISupports
readonly attribute AString error;
[implicit_jscontext]
readonly attribute jsval shippingAddressErrors;
void update(in nsIPaymentDetails aDetails, in boolean aRequestShipping);
AString shippingAddressErrorsJSON();
[implicit_jscontext]
readonly attribute jsval payer;
[implicit_jscontext]
readonly attribute jsval paymentMethod;
};
[scriptable, builtinclass, uuid(d53f9f20-138e-47cc-9fd5-db16a3f6d301)]
@ -89,8 +90,4 @@ interface nsIPaymentRequest : nsISupports
readonly attribute nsIPaymentDetails paymentDetails;
readonly attribute nsIPaymentOptions paymentOptions;
readonly attribute AString shippingOption;
[noscript] void setCompleteStatus(in AString aCompleteStatus);
void updatePaymentDetails(in nsIPaymentDetails aDetails,
in AString aShippingOption);
};

View File

@ -6,7 +6,6 @@
#include "nsISupports.idl"
#include "nsIVariant.idl"
#include "nsIPaymentRequest.idl"
#include "nsIPaymentActionRequest.idl"
#include "nsIPaymentActionResponse.idl"
#include "nsIPaymentAddress.idl"
#include "nsISimpleEnumerator.idl"
@ -70,22 +69,6 @@ interface nsIPaymentRequestService : nsISupports
* This API is for testing only.
*/
void setTestingUIService(in nsIPaymentUIService aUIService);
/**
* Request a specified action on the specified PaymentRequest.
* @param aRequest - the requested action.
*/
void requestPayment(in nsIPaymentActionRequest aRequest);
/**
* This is a cleanup function to break the association between
* nsIPaymentRequestService and nsIPaymentActionCallback.
* nsIPaymentActionCallback is an interface that registered to
* nsIPaymentRequestService when the merchant asks to perform actions, and it
* will be called when user's response send back to nsIPaymentRequestService.
* @param aCallback - the specified nsIPaymentActionCallback.
*/
void removeActionCallback(in nsIPaymentActionCallback aCallback);
};
%{C++

View File

@ -753,7 +753,7 @@ SpeechRecognition::Start(const Optional<NonNull<DOMMediaStream>>& aStream,
if (aStream.WasPassed()) {
StartRecording(&aStream.Value());
} else {
AutoNoJSAPI();
AutoNoJSAPI nojsapi;
MediaManager* manager = MediaManager::Get();
MediaManager::GetUserMediaSuccessCallback onsuccess(
new GetUserMediaSuccessCallback(this));

View File

@ -1,230 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "PaymentActionRequest.h"
#include "PaymentRequestData.h"
using namespace mozilla::dom::payments;
namespace mozilla {
namespace dom {
/* PaymentActionRequest */
NS_IMPL_ISUPPORTS(PaymentActionRequest,
nsIPaymentActionRequest)
PaymentActionRequest::PaymentActionRequest()
: mRequestId(EmptyString())
, mType(nsIPaymentActionRequest::UNKNOWN_ACTION)
, mCallback(nullptr)
{
}
NS_IMETHODIMP
PaymentActionRequest::Init(const nsAString& aRequestId,
const uint32_t aType,
nsIPaymentActionCallback* aCallback)
{
mRequestId = aRequestId;
mType = aType;
mCallback = aCallback;
return NS_OK;
}
NS_IMETHODIMP
PaymentActionRequest::GetRequestId(nsAString& aRequestId)
{
aRequestId = mRequestId;
return NS_OK;
}
NS_IMETHODIMP
PaymentActionRequest::GetType(uint32_t* aType)
{
*aType = mType;
return NS_OK;
}
NS_IMETHODIMP
PaymentActionRequest::GetCallback(nsIPaymentActionCallback** aCallback)
{
NS_ENSURE_ARG_POINTER(aCallback);
nsCOMPtr<nsIPaymentActionCallback> callback = mCallback;
callback.forget(aCallback);
return NS_OK;
}
/* PaymentCreateActionRequest */
NS_IMPL_ISUPPORTS_INHERITED(PaymentCreateActionRequest,
PaymentActionRequest,
nsIPaymentCreateActionRequest)
PaymentCreateActionRequest::PaymentCreateActionRequest()
: mTabId(0)
{
}
NS_IMETHODIMP
PaymentCreateActionRequest::InitRequest(const nsAString& aRequestId,
nsIPaymentActionCallback* aCallback,
const uint64_t aTabId,
nsIPrincipal* aTopLevelPrincipal,
nsIArray* aMethodData,
nsIPaymentDetails* aDetails,
nsIPaymentOptions* aOptions,
const nsAString& aShippingOption)
{
NS_ENSURE_ARG_POINTER(aCallback);
NS_ENSURE_ARG_POINTER(aTopLevelPrincipal);
NS_ENSURE_ARG_POINTER(aMethodData);
NS_ENSURE_ARG_POINTER(aDetails);
NS_ENSURE_ARG_POINTER(aOptions);
nsresult rv = Init(aRequestId, nsIPaymentActionRequest::CREATE_ACTION, aCallback);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mTabId = aTabId;
mTopLevelPrincipal = aTopLevelPrincipal;
mMethodData = aMethodData;
mDetails = aDetails;
mOptions = aOptions;
mShippingOption = aShippingOption;
return NS_OK;
}
NS_IMETHODIMP
PaymentCreateActionRequest::GetTabId(uint64_t* aTabId)
{
NS_ENSURE_ARG_POINTER(aTabId);
*aTabId = mTabId;
return NS_OK;
}
NS_IMETHODIMP
PaymentCreateActionRequest::GetTopLevelPrincipal(nsIPrincipal** aTopLevelPrincipal)
{
NS_ENSURE_ARG_POINTER(aTopLevelPrincipal);
MOZ_ASSERT(mTopLevelPrincipal);
nsCOMPtr<nsIPrincipal> principal = mTopLevelPrincipal;
principal.forget(aTopLevelPrincipal);
return NS_OK;
}
NS_IMETHODIMP
PaymentCreateActionRequest::GetMethodData(nsIArray** aMethodData)
{
NS_ENSURE_ARG_POINTER(aMethodData);
MOZ_ASSERT(mMethodData);
nsCOMPtr<nsIArray> methodData = mMethodData;
methodData.forget(aMethodData);
return NS_OK;
}
NS_IMETHODIMP
PaymentCreateActionRequest::GetDetails(nsIPaymentDetails** aDetails)
{
NS_ENSURE_ARG_POINTER(aDetails);
MOZ_ASSERT(mDetails);
nsCOMPtr<nsIPaymentDetails> details = mDetails;
details.forget(aDetails);
return NS_OK;
}
NS_IMETHODIMP
PaymentCreateActionRequest::GetOptions(nsIPaymentOptions** aOptions)
{
NS_ENSURE_ARG_POINTER(aOptions);
MOZ_ASSERT(mOptions);
nsCOMPtr<nsIPaymentOptions> options = mOptions;
options.forget(aOptions);
return NS_OK;
}
NS_IMETHODIMP
PaymentCreateActionRequest::GetShippingOption(nsAString& aShippingOption)
{
aShippingOption = mShippingOption;
return NS_OK;
}
/* PaymentCompleteActionRequest */
NS_IMPL_ISUPPORTS_INHERITED(PaymentCompleteActionRequest,
PaymentActionRequest,
nsIPaymentCompleteActionRequest)
PaymentCompleteActionRequest::PaymentCompleteActionRequest()
: mCompleteStatus(EmptyString())
{
}
NS_IMETHODIMP
PaymentCompleteActionRequest::GetCompleteStatus(nsAString& aCompleteStatus)
{
aCompleteStatus = mCompleteStatus;
return NS_OK;
}
NS_IMETHODIMP
PaymentCompleteActionRequest::InitRequest(const nsAString& aRequestId,
nsIPaymentActionCallback* aCallback,
const nsAString& aCompleteStatus)
{
NS_ENSURE_ARG_POINTER(aCallback);
nsresult rv = Init(aRequestId, nsIPaymentActionRequest::COMPLETE_ACTION, aCallback);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mCompleteStatus = aCompleteStatus;
return NS_OK;
}
/* PaymentUpdateActionRequest */
NS_IMPL_ISUPPORTS_INHERITED(PaymentUpdateActionRequest,
PaymentActionRequest,
nsIPaymentUpdateActionRequest)
NS_IMETHODIMP
PaymentUpdateActionRequest::GetDetails(nsIPaymentDetails** aDetails)
{
NS_ENSURE_ARG_POINTER(aDetails);
MOZ_ASSERT(mDetails);
nsCOMPtr<nsIPaymentDetails> details = mDetails;
details.forget(aDetails);
return NS_OK;
}
NS_IMETHODIMP
PaymentUpdateActionRequest::GetShippingOption(nsAString& aShippingOption)
{
aShippingOption = mShippingOption;
return NS_OK;
}
NS_IMETHODIMP
PaymentUpdateActionRequest::InitRequest(const nsAString& aRequestId,
nsIPaymentActionCallback* aCallback,
nsIPaymentDetails* aDetails,
const nsAString& aShippingOption)
{
NS_ENSURE_ARG_POINTER(aCallback);
NS_ENSURE_ARG_POINTER(aDetails);
nsresult rv = Init(aRequestId, nsIPaymentActionRequest::UPDATE_ACTION, aCallback);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mDetails = aDetails;
mShippingOption = aShippingOption;
return NS_OK;
}
} // end of namespace dom
} // end of namespace mozilla

View File

@ -1,90 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_PaymentActionRequest_h
#define mozilla_dom_PaymentActionRequest_h
#include "nsIPaymentActionRequest.h"
#include "nsCOMPtr.h"
#include "nsIArray.h"
#include "nsString.h"
namespace mozilla {
namespace dom {
class PaymentActionRequest : public nsIPaymentActionRequest
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPAYMENTACTIONREQUEST
PaymentActionRequest();
protected:
virtual ~PaymentActionRequest() = default;
nsString mRequestId;
uint32_t mType;
nsCOMPtr<nsIPaymentActionCallback> mCallback;
};
class PaymentCreateActionRequest final : public nsIPaymentCreateActionRequest
, public PaymentActionRequest
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
NS_DECL_NSIPAYMENTCREATEACTIONREQUEST
PaymentCreateActionRequest();
private:
~PaymentCreateActionRequest() = default;
uint64_t mTabId;
nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
nsCOMPtr<nsIArray> mMethodData;
nsCOMPtr<nsIPaymentDetails> mDetails;
nsCOMPtr<nsIPaymentOptions> mOptions;
nsString mShippingOption;
};
class PaymentCompleteActionRequest final : public nsIPaymentCompleteActionRequest
, public PaymentActionRequest
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
NS_DECL_NSIPAYMENTCOMPLETEACTIONREQUEST
PaymentCompleteActionRequest();
private:
~PaymentCompleteActionRequest() = default;
nsString mCompleteStatus;
};
class PaymentUpdateActionRequest final : public nsIPaymentUpdateActionRequest
, public PaymentActionRequest
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
NS_DECL_NSIPAYMENTUPDATEACTIONREQUEST
PaymentUpdateActionRequest() = default;
private:
~PaymentUpdateActionRequest() = default;
nsCOMPtr<nsIPaymentDetails> mDetails;
nsString mShippingOption;
};
} // end of namespace dom
} // end of namespace mozilla
#endif

View File

@ -745,10 +745,14 @@ PaymentRequest::Show(const Optional<OwningNonNull<Promise>>& aDetailsPromise,
void
PaymentRequest::RejectShowPayment(nsresult aRejectReason)
{
MOZ_ASSERT(mAcceptPromise);
MOZ_ASSERT(mAcceptPromise || mResponse);
MOZ_ASSERT(mState == eInteractive);
mAcceptPromise->MaybeReject(aRejectReason);
if (mResponse) {
mResponse->RejectRetry(aRejectReason);
} else {
mAcceptPromise->MaybeReject(aRejectReason);
}
mState = eClosed;
mAcceptPromise = nullptr;
}
@ -761,7 +765,7 @@ PaymentRequest::RespondShowPayment(const nsAString& aMethodName,
const nsAString& aPayerPhone,
nsresult aRv)
{
MOZ_ASSERT(mAcceptPromise);
MOZ_ASSERT(mAcceptPromise || mResponse);
MOZ_ASSERT(mState == eInteractive);
if (NS_FAILED(aRv)) {
@ -773,12 +777,17 @@ PaymentRequest::RespondShowPayment(const nsAString& aMethodName,
mShippingAddress.swap(mFullShippingAddress);
mFullShippingAddress = nullptr;
RefPtr<PaymentResponse> paymentResponse =
new PaymentResponse(GetOwner(), this, mId, aMethodName,
mShippingOption, mShippingAddress, aDetails,
aPayerName, aPayerEmail, aPayerPhone);
mResponse = paymentResponse;
mAcceptPromise->MaybeResolve(paymentResponse);
if (mResponse) {
mResponse->RespondRetry(aMethodName, mShippingOption, mShippingAddress,
aDetails, aPayerName, aPayerEmail, aPayerPhone);
} else {
RefPtr<PaymentResponse> paymentResponse =
new PaymentResponse(GetOwner(), this, mId, aMethodName,
mShippingOption, mShippingAddress, aDetails,
aPayerName, aPayerEmail, aPayerPhone);
mResponse = paymentResponse;
mAcceptPromise->MaybeResolve(paymentResponse);
}
mState = eClosed;
mAcceptPromise = nullptr;
@ -903,6 +912,22 @@ PaymentRequest::AbortUpdate(nsresult aRv, bool aDeferredShow)
mUpdateError = aRv;
}
nsresult
PaymentRequest::RetryPayment(JSContext* aCx, const PaymentValidationErrors& aErrors)
{
if (mState == eInteractive) {
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
MOZ_ASSERT(manager);
nsresult rv = manager->RetryPayment(aCx, this, aErrors);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mState = eInteractive;
return NS_OK;
}
void
PaymentRequest::GetId(nsAString& aRetVal) const
{

View File

@ -109,6 +109,8 @@ public:
already_AddRefed<Promise> Abort(ErrorResult& aRv);
void RespondAbortPayment(bool aResult);
nsresult RetryPayment(JSContext* aCx, const PaymentValidationErrors& aErrors);
void GetId(nsAString& aRetVal) const;
void GetInternalId(nsAString& aRetVal);
void SetId(const nsAString& aId);

View File

@ -341,7 +341,9 @@ PaymentDetails::PaymentDetails(const nsAString& aId,
nsIArray* aShippingOptions,
nsIArray* aModifiers,
const nsAString& aError,
const nsAString& aShippingAddressErrors)
const nsAString& aShippingAddressErrors,
const nsAString& aPayerErrors,
const nsAString& aPaymentMethodErrors)
: mId(aId)
, mTotalItem(aTotalItem)
, mDisplayItems(aDisplayItems)
@ -349,6 +351,8 @@ PaymentDetails::PaymentDetails(const nsAString& aId,
, mModifiers(aModifiers)
, mError(aError)
, mShippingAddressErrors(aShippingAddressErrors)
, mPayerErrors(aPayerErrors)
, mPaymentMethodErrors(aPaymentMethodErrors)
{
}
@ -415,7 +419,9 @@ PaymentDetails::Create(const IPCPaymentDetails& aIPCDetails,
nsCOMPtr<nsIPaymentDetails> details =
new PaymentDetails(aIPCDetails.id(), total, displayItems, shippingOptions,
modifiers, aIPCDetails.error(),
aIPCDetails.shippingAddressErrors());
aIPCDetails.shippingAddressErrors(),
aIPCDetails.payerErrors(),
aIPCDetails.paymentMethodErrors());
details.forget(aDetails);
return NS_OK;
@ -484,6 +490,31 @@ PaymentDetails::GetShippingAddressErrors(JSContext* aCx, JS::MutableHandleValue
}
NS_IMETHODIMP
PaymentDetails::GetPayer(JSContext* aCx, JS::MutableHandleValue aErrors)
{
PayerErrorFields errors;
errors.Init(mPayerErrors);
if (!ToJSValue(aCx, errors, aErrors)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
PaymentDetails::GetPaymentMethod(JSContext* aCx, JS::MutableHandleValue aErrors)
{
if (mPaymentMethodErrors.IsEmpty()) {
aErrors.set(JS::NullValue());
return NS_OK;
}
nsresult rv = DeserializeToJSValue(mPaymentMethodErrors, aCx ,aErrors);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
PaymentDetails::Update(nsIPaymentDetails* aDetails, const bool aRequestShipping)
{
MOZ_ASSERT(aDetails);
@ -533,14 +564,44 @@ PaymentDetails::Update(nsIPaymentDetails* aDetails, const bool aRequestShipping)
return rv;
}
aDetails->ShippingAddressErrorsJSON(mShippingAddressErrors);
PaymentDetails* rowDetails = static_cast<PaymentDetails*>(aDetails);
MOZ_ASSERT(rowDetails);
mShippingAddressErrors = rowDetails->GetShippingAddressErrors();
mPayerErrors = rowDetails->GetPayer();
mPaymentMethodErrors = rowDetails->GetPaymentMethod();
return NS_OK;
}
NS_IMETHODIMP
PaymentDetails::ShippingAddressErrorsJSON(nsAString& aErrors)
const nsString&
PaymentDetails::GetShippingAddressErrors() const
{
aErrors = mShippingAddressErrors;
return mShippingAddressErrors;
}
const nsString&
PaymentDetails::GetPayer() const
{
return mPayerErrors;
}
const nsString&
PaymentDetails::GetPaymentMethod() const
{
return mPaymentMethodErrors;
}
nsresult
PaymentDetails::UpdateErrors(const nsAString& aError,
const nsAString& aPayerErrors,
const nsAString& aPaymentMethodErrors,
const nsAString& aShippingAddressErrors)
{
mError = aError;
mPayerErrors = aPayerErrors;
mPaymentMethodErrors = aPaymentMethodErrors;
mShippingAddressErrors = aShippingAddressErrors;
return NS_OK;
}
@ -701,7 +762,7 @@ PaymentRequest::GetShippingOption(nsAString& aShippingOption)
return NS_OK;
}
NS_IMETHODIMP
nsresult
PaymentRequest::UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails,
const nsAString& aShippingOption)
{
@ -712,14 +773,30 @@ PaymentRequest::UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails,
return rv;
}
mShippingOption = aShippingOption;
return mPaymentDetails->Update(aPaymentDetails, requestShipping);
PaymentDetails* rowDetails = static_cast<PaymentDetails*>(mPaymentDetails.get());
MOZ_ASSERT(rowDetails);
return rowDetails->Update(aPaymentDetails, requestShipping);
}
NS_IMETHODIMP
void
PaymentRequest::SetCompleteStatus(const nsAString& aCompleteStatus)
{
mCompleteStatus = aCompleteStatus;
return NS_OK;
}
nsresult
PaymentRequest::UpdateErrors(const nsAString& aError,
const nsAString& aPayerErrors,
const nsAString& aPaymentMethodErrors,
const nsAString& aShippingAddressErrors)
{
PaymentDetails* rowDetails = static_cast<PaymentDetails*>(mPaymentDetails.get());
MOZ_ASSERT(rowDetails);
return rowDetails->UpdateErrors(aError,
aPayerErrors,
aPaymentMethodErrors,
aShippingAddressErrors);
}
NS_IMETHODIMP

View File

@ -10,7 +10,7 @@
#include "nsIPaymentAddress.h"
#include "nsIPaymentRequest.h"
#include "nsCOMPtr.h"
#include "mozilla/dom/PPaymentRequest.h"
#include "mozilla/dom/PaymentRequestParent.h"
namespace mozilla {
namespace dom {
@ -131,6 +131,15 @@ public:
static nsresult Create(const IPCPaymentDetails& aIPCDetails,
nsIPaymentDetails** aDetails);
nsresult Update(nsIPaymentDetails* aDetails, const bool aRequestShipping);
const nsString& GetShippingAddressErrors() const;
const nsString& GetPayer() const;
const nsString& GetPaymentMethod() const;
nsresult UpdateErrors(const nsAString& aError,
const nsAString& aPayerErrors,
const nsAString& aPaymentMethodErrors,
const nsAString& aShippingAddressErrors);
private:
PaymentDetails(const nsAString& aId,
nsIPaymentItem* aTotalItem,
@ -138,7 +147,9 @@ private:
nsIArray* aShippingOptions,
nsIArray* aModifiers,
const nsAString& aError,
const nsAString& aShippingAddressError);
const nsAString& aShippingAddressError,
const nsAString& aPayerError,
const nsAString& aPaymentMethodError);
~PaymentDetails() = default;
@ -149,6 +160,8 @@ private:
nsCOMPtr<nsIArray> mModifiers;
nsString mError;
nsString mShippingAddressErrors;
nsString mPayerErrors;
nsString mPaymentMethodErrors;
};
class PaymentOptions final : public nsIPaymentOptions
@ -189,6 +202,29 @@ public:
nsIPaymentOptions* aPaymentOptions,
const nsAString& aShippingOption);
void SetIPC(PaymentRequestParent* aIPC)
{
mIPC = aIPC;
}
PaymentRequestParent* GetIPC() const
{
return mIPC;
}
nsresult
UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails,
const nsAString& aShippingOption);
void
SetCompleteStatus(const nsAString& aCompleteStatus);
nsresult
UpdateErrors(const nsAString& aError,
const nsAString& aPayerErrors,
const nsAString& aPaymentMethodErrors,
const nsAString& aShippingAddressErrors);
private:
~PaymentRequest() = default;
@ -200,6 +236,10 @@ private:
nsCOMPtr<nsIPaymentDetails> mPaymentDetails;
nsCOMPtr<nsIPaymentOptions> mPaymentOptions;
nsString mShippingOption;
// IPC's life cycle should be controlled by IPC mechanism.
// PaymentRequest should not own the reference of it.
PaymentRequestParent* mIPC;
};
class PaymentAddress final : public nsIPaymentAddress

View File

@ -163,7 +163,7 @@ ConvertDetailsInit(JSContext* aCx,
}
// Convert |id|
nsString id(EmptyString());
nsAutoString id;
if (aDetails.mId.WasPassed()) {
id = aDetails.mId.Value();
}
@ -178,7 +178,9 @@ ConvertDetailsInit(JSContext* aCx,
shippingOptions,
modifiers,
EmptyString(), // error message
EmptyString()); // shippingAddressErrors
EmptyString(), // shippingAddressErrors
EmptyString(), // payerErrors
EmptyString()); // paymentMethodErrors
return NS_OK;
}
@ -204,23 +206,39 @@ ConvertDetailsUpdate(JSContext* aCx,
ConvertItem(aDetails.mTotal, total);
// Convert |error|
nsString error(EmptyString());
nsAutoString error;
if (aDetails.mError.WasPassed()) {
error = aDetails.mError.Value();
}
nsString shippingAddressErrors(EmptyString());
nsAutoString shippingAddressErrors;
if (!aDetails.mShippingAddressErrors.ToJSON(shippingAddressErrors)) {
return NS_ERROR_FAILURE;
}
nsAutoString payerErrors;
if (!aDetails.mPayerErrors.ToJSON(payerErrors)) {
return NS_ERROR_FAILURE;
}
nsAutoString paymentMethodErrors;
if (aDetails.mPaymentMethodErrors.WasPassed()) {
JS::RootedObject object(aCx, aDetails.mPaymentMethodErrors.Value());
nsresult rv = SerializeFromJSObject(aCx, object, paymentMethodErrors);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
aIPCDetails = IPCPaymentDetails(EmptyString(), // id
total,
displayItems,
shippingOptions,
modifiers,
error,
shippingAddressErrors);
shippingAddressErrors,
payerErrors,
paymentMethodErrors);
return NS_OK;
}
@ -539,6 +557,44 @@ PaymentRequestManager::ClosePayment(PaymentRequest* aRequest)
return SendRequestPayment(aRequest, action, false);
}
nsresult
PaymentRequestManager::RetryPayment(JSContext* aCx,
PaymentRequest* aRequest,
const PaymentValidationErrors& aErrors)
{
NS_ENSURE_ARG_POINTER(aCx);
NS_ENSURE_ARG_POINTER(aRequest);
nsAutoString requestId;
aRequest->GetInternalId(requestId);
nsAutoString error;
if (aErrors.mError.WasPassed()) {
error = aErrors.mError.Value();
}
nsAutoString shippingAddressErrors;
aErrors.mShippingAddress.ToJSON(shippingAddressErrors);
nsAutoString payerErrors;
aErrors.mPayer.ToJSON(payerErrors);
nsAutoString paymentMethodErrors;
if (aErrors.mPaymentMethod.WasPassed()) {
JS::RootedObject object(aCx, aErrors.mPaymentMethod.Value());
nsresult rv = SerializeFromJSObject(aCx, object, paymentMethodErrors);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
IPCPaymentRetryActionRequest action(requestId,
error,
payerErrors,
paymentMethodErrors,
shippingAddressErrors);
return SendRequestPayment(aRequest, action);
}
nsresult
PaymentRequestManager::RespondPayment(PaymentRequest* aRequest,
const IPCPaymentActionResponse& aResponse)

View File

@ -58,6 +58,9 @@ public:
bool aRequestShipping,
bool aDeferredShow);
nsresult ClosePayment(PaymentRequest* aRequest);
nsresult RetryPayment(JSContext* aCx,
PaymentRequest* aRequest,
const PaymentValidationErrors& aErrors);
nsresult RespondPayment(PaymentRequest* aRequest,
const IPCPaymentActionResponse& aResponse);

View File

@ -5,17 +5,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ModuleUtils.h"
#include "PaymentActionRequest.h"
#include "PaymentActionResponse.h"
#include "PaymentRequestData.h"
#include "PaymentRequestService.h"
using mozilla::dom::GeneralResponseData;
using mozilla::dom::BasicCardResponseData;
using mozilla::dom::PaymentActionRequest;
using mozilla::dom::PaymentCreateActionRequest;
using mozilla::dom::PaymentCompleteActionRequest;
using mozilla::dom::PaymentUpdateActionRequest;
using mozilla::dom::PaymentCanMakeActionResponse;
using mozilla::dom::PaymentAbortActionResponse;
using mozilla::dom::PaymentShowActionResponse;
@ -25,10 +20,6 @@ using mozilla::dom::PaymentRequestService;
NS_GENERIC_FACTORY_CONSTRUCTOR(GeneralResponseData)
NS_GENERIC_FACTORY_CONSTRUCTOR(BasicCardResponseData)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentActionRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCreateActionRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentUpdateActionRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCanMakeActionResponse)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAbortActionResponse)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentShowActionResponse)
@ -39,10 +30,6 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService,
NS_DEFINE_NAMED_CID(NS_GENERAL_RESPONSE_DATA_CID);
NS_DEFINE_NAMED_CID(NS_BASICCARD_RESPONSE_DATA_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_ACTION_REQUEST_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_CREATE_ACTION_REQUEST_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_UPDATE_ACTION_REQUEST_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_ABORT_ACTION_RESPONSE_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_SHOW_ACTION_RESPONSE_CID);
@ -53,10 +40,6 @@ NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID);
static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
{ &kNS_GENERAL_RESPONSE_DATA_CID, false, nullptr, GeneralResponseDataConstructor},
{ &kNS_BASICCARD_RESPONSE_DATA_CID, false, nullptr, BasicCardResponseDataConstructor},
{ &kNS_PAYMENT_ACTION_REQUEST_CID, false, nullptr, PaymentActionRequestConstructor},
{ &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID, false, nullptr, PaymentCreateActionRequestConstructor},
{ &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID, false, nullptr, PaymentCompleteActionRequestConstructor},
{ &kNS_PAYMENT_UPDATE_ACTION_REQUEST_CID, false, nullptr, PaymentUpdateActionRequestConstructor},
{ &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID, false, nullptr, PaymentCanMakeActionResponseConstructor},
{ &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID, false, nullptr, PaymentAbortActionResponseConstructor},
{ &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID, false, nullptr, PaymentShowActionResponseConstructor},
@ -69,10 +52,6 @@ static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
{ NS_GENERAL_RESPONSE_DATA_CONTRACT_ID, &kNS_GENERAL_RESPONSE_DATA_CID },
{ NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID, &kNS_BASICCARD_RESPONSE_DATA_CID },
{ NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_ACTION_REQUEST_CID },
{ NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID },
{ NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID },
{ NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_UPDATE_ACTION_REQUEST_CID },
{ NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID },
{ NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID },
{ NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID },
@ -85,10 +64,6 @@ static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = {
{ "payment-request", "GeneralResponseData", NS_GENERAL_RESPONSE_DATA_CONTRACT_ID },
{ "payment-request", "BasicCardResponseData", NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID },
{ "payment-request", "PaymentActionRequest", NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID },
{ "payment-request", "PaymentCreateActionRequest", NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID },
{ "payment-request", "PaymentCompleteActionRequest", NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID },
{ "payment-request", "PaymentUpdateActionRequest", NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID },
{ "payment-request", "PaymentCanMakeActionResponse", NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID },
{ "payment-request", "PaymentAbortActionResponse", NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID },
{ "payment-request", "PaymentShowActionResponse", NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID },

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/PaymentRequestParent.h"
#include "PaymentRequestData.h"
#include "PaymentRequestService.h"
#include "BasicCardPayment.h"
@ -161,23 +162,23 @@ PaymentRequestService::LaunchUIAction(const nsAString& aRequestId, uint32_t aAct
}
}
switch (aActionType) {
case nsIPaymentActionRequest::SHOW_ACTION: {
case IPCPaymentActionRequest::TIPCPaymentShowActionRequest:{
rv = uiService->ShowPayment(aRequestId);
break;
}
case nsIPaymentActionRequest::ABORT_ACTION: {
case IPCPaymentActionRequest::TIPCPaymentAbortActionRequest: {
rv = uiService->AbortPayment(aRequestId);
break;
}
case nsIPaymentActionRequest::COMPLETE_ACTION: {
case IPCPaymentActionRequest::TIPCPaymentCompleteActionRequest: {
rv = uiService->CompletePayment(aRequestId);
break;
}
case nsIPaymentActionRequest::UPDATE_ACTION: {
case IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest: {
rv = uiService->UpdatePayment(aRequestId);
break;
}
case nsIPaymentActionRequest::CLOSE_ACTION: {
case IPCPaymentActionRequest::TIPCPaymentCloseActionRequest: {
rv = uiService->ClosePayment(aRequestId);
break;
}
@ -191,103 +192,85 @@ PaymentRequestService::LaunchUIAction(const nsAString& aRequestId, uint32_t aAct
return NS_OK;
}
NS_IMETHODIMP
PaymentRequestService::RemoveActionCallback(nsIPaymentActionCallback* aCallback)
nsresult
PaymentRequestService::RequestPayment(const nsAString& aRequestId,
const IPCPaymentActionRequest& aAction,
PaymentRequestParent* aIPC)
{
NS_ENSURE_ARG_POINTER(aCallback);
for (auto iter = mCallbackHashtable.Iter(); !iter.Done(); iter.Next()) {
nsCOMPtr<nsIPaymentActionCallback> callback = iter.Data();
MOZ_ASSERT(callback);
if (callback == aCallback) {
iter.Remove();
return NS_OK;
NS_ENSURE_ARG_POINTER(aIPC);
nsresult rv = NS_OK;
uint32_t type = aAction.type();
if (type != IPCPaymentActionRequest::TIPCPaymentCreateActionRequest) {
nsCOMPtr<nsIPaymentRequest> request;
rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!request && type != IPCPaymentActionRequest::TIPCPaymentCloseActionRequest) {
return NS_ERROR_FAILURE;
}
if (request) {
payments::PaymentRequest* rowRequest =
static_cast<payments::PaymentRequest*>(request.get());
if (!rowRequest) {
return NS_ERROR_FAILURE;
}
rowRequest->SetIPC(aIPC);
}
}
return NS_OK;
}
NS_IMETHODIMP
PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
{
NS_ENSURE_ARG_POINTER(aRequest);
nsAutoString requestId;
nsresult rv = aRequest->GetRequestId(requestId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIPaymentActionCallback> callback;
rv = aRequest->GetCallback(getter_AddRefs(callback));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = SetActionCallback(requestId, callback);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
uint32_t type;
rv = aRequest->GetType(&type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
switch (type) {
case nsIPaymentActionRequest::CREATE_ACTION: {
nsCOMPtr<nsIPaymentCreateActionRequest> request =
do_QueryInterface(aRequest);
MOZ_ASSERT(request);
uint64_t tabId;
rv = request->GetTabId(&tabId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> topLevelPrincipal;
rv = request->GetTopLevelPrincipal(getter_AddRefs(topLevelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIArray> methodData;
rv = request->GetMethodData(getter_AddRefs(methodData));
NS_ENSURE_SUCCESS(rv, rv);
case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: {
const IPCPaymentCreateActionRequest& action = aAction;
uint64_t tabId = aIPC->GetTabId();
nsCOMPtr<nsIMutableArray> methodData = do_CreateInstance(NS_ARRAY_CONTRACTID);
MOZ_ASSERT(methodData);
for (IPCPaymentMethodData data : action.methodData()) {
nsCOMPtr<nsIPaymentMethodData> method;
rv = payments::PaymentMethodData::Create(data, getter_AddRefs(method));
NS_ENSURE_SUCCESS(rv, rv);
rv = methodData->AppendElement(method);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIPaymentDetails> details;
rv = request->GetDetails(getter_AddRefs(details));
rv = payments::PaymentDetails::Create(action.details(), getter_AddRefs(details));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPaymentOptions> options;
rv = request->GetOptions(getter_AddRefs(options));
rv = payments::PaymentOptions::Create(action.options(), getter_AddRefs(options));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString shippingOption;
rv = request->GetShippingOption(shippingOption);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPaymentRequest> payment =
new payments::PaymentRequest(tabId, requestId, topLevelPrincipal,
methodData, details, options, shippingOption);
new payments::PaymentRequest(tabId,
aRequestId,
action.topLevelPrincipal(),
methodData,
details,
options,
action.shippingOption());
if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
break;
}
case nsIPaymentActionRequest::CANMAKE_ACTION: {
case IPCPaymentActionRequest::TIPCPaymentCanMakeActionRequest: {
nsCOMPtr<nsIPaymentCanMakeActionResponse> canMakeResponse =
do_CreateInstance(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID);
MOZ_ASSERT(canMakeResponse);
rv = canMakeResponse->Init(requestId, CanMakePayment(requestId));
rv = canMakeResponse->Init(aRequestId,
CanMakePayment(aRequestId));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = RespondPayment(canMakeResponse.get());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
break;
}
case nsIPaymentActionRequest::SHOW_ACTION: {
if (mShowingRequest || !CanMakePayment(requestId)) {
case IPCPaymentActionRequest::TIPCPaymentShowActionRequest: {
if (mShowingRequest || !CanMakePayment(aRequestId)) {
uint32_t responseStatus;
if (mShowingRequest) {
responseStatus = nsIPaymentActionResponse::PAYMENT_REJECTED;
@ -297,7 +280,7 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
nsCOMPtr<nsIPaymentShowActionResponse> showResponse =
do_CreateInstance(NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID);
MOZ_ASSERT(showResponse);
rv = showResponse->Init(requestId,
rv = showResponse->Init(aRequestId,
responseStatus,
EmptyString(),
nullptr,
@ -309,90 +292,83 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
return rv;
}
} else {
rv = GetPaymentRequestById(requestId, getter_AddRefs(mShowingRequest));
rv = GetPaymentRequestById(aRequestId,
getter_AddRefs(mShowingRequest));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
return rv;
}
rv = LaunchUIAction(requestId, type);
rv = LaunchUIAction(aRequestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
return rv;
}
}
break;
}
case nsIPaymentActionRequest::ABORT_ACTION: {
rv = LaunchUIAction(requestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
break;
}
case nsIPaymentActionRequest::COMPLETE_ACTION: {
nsCOMPtr<nsIPaymentCompleteActionRequest> request =
do_QueryInterface(aRequest);
MOZ_ASSERT(request);
nsAutoString completeStatus;
rv = request->GetCompleteStatus(completeStatus);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPaymentRequest> payment;
rv = GetPaymentRequestById(requestId, getter_AddRefs(payment));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
rv = payment->SetCompleteStatus(completeStatus);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
rv = LaunchUIAction(requestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
break;
}
case nsIPaymentActionRequest::UPDATE_ACTION: {
nsCOMPtr<nsIPaymentUpdateActionRequest> request = do_QueryInterface(aRequest);
MOZ_ASSERT(request);
nsCOMPtr<nsIPaymentDetails> details;
rv = request->GetDetails(getter_AddRefs(details));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString shippingOption;
rv = request->GetShippingOption(shippingOption);
NS_ENSURE_SUCCESS(rv, rv);
rv = request->GetRequestId(requestId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPaymentRequest> payment;
rv = GetPaymentRequestById(requestId, getter_AddRefs(payment));
case IPCPaymentActionRequest::TIPCPaymentAbortActionRequest: {
rv = LaunchUIAction(aRequestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = payment->UpdatePaymentDetails(details, shippingOption);
break;
}
case IPCPaymentActionRequest::TIPCPaymentCompleteActionRequest: {
const IPCPaymentCompleteActionRequest& action = aAction;
nsCOMPtr<nsIPaymentRequest> payment;
rv = GetPaymentRequestById(aRequestId, getter_AddRefs(payment));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(payment);
payments::PaymentRequest* rowPayment =
static_cast<payments::PaymentRequest*>(payment.get());
MOZ_ASSERT(rowPayment);
rowPayment->SetCompleteStatus(action.completeStatus());
rv = LaunchUIAction(aRequestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
break;
}
case IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest: {
const IPCPaymentUpdateActionRequest& action = aAction;
nsCOMPtr<nsIPaymentDetails> details;
rv = payments::PaymentDetails::Create(action.details(), getter_AddRefs(details));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIPaymentRequest> payment;
rv = GetPaymentRequestById(aRequestId, getter_AddRefs(payment));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(payment);
payments::PaymentRequest* rowPayment =
static_cast<payments::PaymentRequest*>(payment.get());
MOZ_ASSERT(rowPayment);
rv = rowPayment->UpdatePaymentDetails(details, action.shippingOption());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (mShowingRequest) {
MOZ_ASSERT(mShowingRequest == payment);
rv = LaunchUIAction(requestId, type);
rv = LaunchUIAction(aRequestId, type);
} else {
mShowingRequest = payment;
rv = LaunchUIAction(requestId, nsIPaymentActionRequest::SHOW_ACTION);
rv = LaunchUIAction(aRequestId,
IPCPaymentActionRequest::TIPCPaymentShowActionRequest);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
break;
}
case nsIPaymentActionRequest::CLOSE_ACTION: {
nsCOMPtr<nsIPaymentRequest> payment;
rv = GetPaymentRequestById(requestId, getter_AddRefs(payment));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = LaunchUIAction(requestId, type);
break;
}
case IPCPaymentActionRequest::TIPCPaymentCloseActionRequest: {
nsCOMPtr<nsIPaymentRequest> payment;
rv = GetPaymentRequestById(aRequestId, getter_AddRefs(payment));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = LaunchUIAction(aRequestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -402,6 +378,26 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
mRequestQueue.RemoveElement(payment);
break;
}
case IPCPaymentActionRequest::TIPCPaymentRetryActionRequest: {
const IPCPaymentRetryActionRequest& action = aAction;
nsCOMPtr<nsIPaymentRequest> payment;
rv = GetPaymentRequestById(aRequestId, getter_AddRefs(payment));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(payment);
payments::PaymentRequest* rowPayment =
static_cast<payments::PaymentRequest*>(payment.get());
MOZ_ASSERT(rowPayment);
rowPayment->UpdateErrors(action.error(),
action.payerErrors(),
action.paymentMethodErrors(),
action.shippingAddressErrors());
MOZ_ASSERT(mShowingRequest == payment);
rv = LaunchUIAction(aRequestId,
IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest);
break;
}
default: {
return NS_ERROR_FAILURE;
}
@ -422,19 +418,18 @@ PaymentRequestService::RespondPayment(nsIPaymentActionResponse* aResponse)
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!request) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPaymentActionCallback> callback;
if (!mCallbackHashtable.Get(requestId, getter_AddRefs(callback))) {
payments::PaymentRequest* rowRequest =
static_cast<payments::PaymentRequest*>(request.get());
if (!rowRequest) {
return NS_ERROR_FAILURE;
}
if (NS_WARN_IF(!callback)) {
if (!rowRequest->GetIPC()) {
return NS_ERROR_FAILURE;
}
rv = callback->RespondPayment(aResponse);
rv = rowRequest->GetIPC()->RespondPayment(aResponse);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -487,15 +482,23 @@ NS_IMETHODIMP
PaymentRequestService::ChangeShippingAddress(const nsAString& aRequestId,
nsIPaymentAddress* aAddress)
{
nsCOMPtr<nsIPaymentActionCallback> callback;
if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
nsCOMPtr<nsIPaymentRequest> request;
nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!request) {
return NS_ERROR_FAILURE;
}
if (NS_WARN_IF(!callback)) {
payments::PaymentRequest* rowRequest =
static_cast<payments::PaymentRequest*>(request.get());
if (!rowRequest) {
return NS_ERROR_FAILURE;
}
nsresult rv = callback->ChangeShippingAddress(aRequestId, aAddress);
if (!rowRequest->GetIPC()) {
return NS_ERROR_FAILURE;
}
rv = rowRequest->GetIPC()->ChangeShippingAddress(aRequestId, aAddress);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -506,15 +509,23 @@ NS_IMETHODIMP
PaymentRequestService::ChangeShippingOption(const nsAString& aRequestId,
const nsAString& aOption)
{
nsCOMPtr<nsIPaymentActionCallback> callback;
if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
nsCOMPtr<nsIPaymentRequest> request;
nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!request) {
return NS_ERROR_FAILURE;
}
if (NS_WARN_IF(!callback)) {
payments::PaymentRequest* rowRequest =
static_cast<payments::PaymentRequest*>(request.get());
if (!rowRequest) {
return NS_ERROR_FAILURE;
}
nsresult rv = callback->ChangeShippingOption(aRequestId, aOption);
if (!rowRequest->GetIPC()) {
return NS_ERROR_FAILURE;
}
rv = rowRequest->GetIPC()->ChangeShippingOption(aRequestId, aOption);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -522,30 +533,6 @@ PaymentRequestService::ChangeShippingOption(const nsAString& aRequestId,
return NS_OK;
}
nsresult
PaymentRequestService::SetActionCallback(const nsAString& aRequestId,
nsIPaymentActionCallback* aCallback)
{
NS_ENSURE_ARG_POINTER(aCallback);
nsCOMPtr<nsIPaymentActionCallback> callback;
if (mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
mCallbackHashtable.Remove(aRequestId);
}
mCallbackHashtable.Put(aRequestId, aCallback);
return NS_OK;
}
nsresult
PaymentRequestService::RemoveActionCallback(const nsAString& aRequestId)
{
nsCOMPtr<nsIPaymentActionCallback> callback;
if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
return NS_ERROR_FAILURE;
}
mCallbackHashtable.Remove(aRequestId);
return NS_OK;
}
bool
PaymentRequestService::CanMakePayment(const nsAString& aRequestId)
{

View File

@ -34,16 +34,12 @@ public:
uint32_t NumPayments() const;
nsresult RequestPayment(const nsAString& aRequestId,
const IPCPaymentActionRequest& aAction,
PaymentRequestParent* aCallback);
private:
~PaymentRequestService() = default;
nsresult
SetActionCallback(const nsAString& aRequestId,
nsIPaymentActionCallback* aCallback);
nsresult
RemoveActionCallback(const nsAString& aRequestId);
// this method is only used for testing
nsresult
LaunchUIAction(const nsAString& aRequestId, uint32_t aActionType);
@ -55,8 +51,6 @@ private:
FallibleTArray<nsCOMPtr<nsIPaymentRequest>> mRequestQueue;
nsInterfaceHashtable<nsStringHashKey, nsIPaymentActionCallback> mCallbackHashtable;
nsCOMPtr<nsIPaymentUIService> mTestingUIService;
nsCOMPtr<nsIPaymentRequest> mShowingRequest;

View File

@ -31,7 +31,7 @@ PaymentResponse::PaymentResponse(nsPIDOMWindowInner* aWindow,
const nsAString& aRequestId,
const nsAString& aMethodName,
const nsAString& aShippingOption,
RefPtr<PaymentAddress> aShippingAddress,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
@ -183,6 +183,156 @@ PaymentResponse::RespondComplete()
}
}
already_AddRefed<Promise>
PaymentResponse::Retry(JSContext* aCx,
const PaymentValidationErrors& aErrors,
ErrorResult& aRv)
{
nsIGlobalObject* global = mOwner->AsGlobal();
ErrorResult errResult;
RefPtr<Promise> promise = Promise::Create(global, errResult);
if (errResult.Failed()) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
nsIDocument* doc = mOwner->GetExtantDoc();
if (!doc || !doc->IsCurrentActiveDocument()) {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
return promise.forget();
}
if (mCompleteCalled || mRetryPromise) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
return promise.forget();
}
nsresult rv = ValidatePaymentValidationErrors(aErrors);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(rv);
return promise.forget();
}
MOZ_ASSERT(mRequest);
rv = mRequest->RetryPayment(aCx, aErrors);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(rv);
return promise.forget();
}
mRetryPromise = promise;
return promise.forget();
}
void
PaymentResponse::RespondRetry(const nsAString& aMethodName,
const nsAString& aShippingOption,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone)
{
mMethodName = aMethodName;
mShippingOption = aShippingOption;
mShippingAddress = aShippingAddress;
mDetails = aDetails;
mPayerName = aPayerName;
mPayerEmail = aPayerEmail;
mPayerPhone = aPayerPhone;
NS_NewTimerWithCallback(getter_AddRefs(mTimer),
this,
StaticPrefs::dom_payments_response_timeout(),
nsITimer::TYPE_ONE_SHOT,
mOwner->EventTargetFor(TaskCategory::Other));
MOZ_ASSERT(mRetryPromise);
mRetryPromise->MaybeResolve(JS::UndefinedHandleValue);
mRetryPromise = nullptr;
}
void
PaymentResponse::RejectRetry(nsresult aRejectReason)
{
MOZ_ASSERT(mRetryPromise);
mRetryPromise->MaybeReject(aRejectReason);
mRetryPromise = nullptr;
}
nsresult
PaymentResponse::ValidatePaymentValidationErrors(const PaymentValidationErrors& aErrors)
{
// Should not be empty errors
// check PaymentValidationErrors.error
if (aErrors.mError.WasPassed() && !aErrors.mError.Value().IsEmpty()) {
return NS_OK;
}
// check PaymentValidationErrors.payer
PayerErrorFields payerErrors(aErrors.mPayer);
if (payerErrors.mName.WasPassed() && !payerErrors.mName.Value().IsEmpty()) {
return NS_OK;
}
if (payerErrors.mEmail.WasPassed() && !payerErrors.mEmail.Value().IsEmpty()) {
return NS_OK;
}
if (payerErrors.mPhone.WasPassed() && !payerErrors.mPhone.Value().IsEmpty()) {
return NS_OK;
}
// check PaymentValidationErrors.paymentMethod
if (aErrors.mPaymentMethod.WasPassed()) {
return NS_OK;
}
// check PaymentValidationErrors.shippingAddress
AddressErrors addErrors(aErrors.mShippingAddress);
if (addErrors.mAddressLine.WasPassed() &&
!addErrors.mAddressLine.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mCity.WasPassed() && !addErrors.mCity.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mCountry.WasPassed() && !addErrors.mCountry.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mDependentLocality.WasPassed() &&
!addErrors.mDependentLocality.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mOrganization.WasPassed() &&
!addErrors.mOrganization.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mPhone.WasPassed() && !addErrors.mPhone.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mPostalCode.WasPassed() &&
!addErrors.mPostalCode.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mRecipient.WasPassed() &&
!addErrors.mRecipient.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mRegion.WasPassed() &&
!addErrors.mRegion.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mRegionCode.WasPassed() &&
!addErrors.mRegionCode.Value().IsEmpty()) {
return NS_OK;
}
if (addErrors.mSortingCode.WasPassed() &&
!addErrors.mSortingCode.Value().IsEmpty()) {
return NS_OK;
}
return NS_ERROR_DOM_ABORT_ERR;
}
NS_IMETHODIMP
PaymentResponse::Notify(nsITimer *timer)
{

View File

@ -33,7 +33,7 @@ public:
const nsAString& aRequestId,
const nsAString& aMethodName,
const nsAString& aShippingOption,
RefPtr<PaymentAddress> aShippingAddress,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
@ -69,9 +69,24 @@ public:
void RespondComplete();
already_AddRefed<Promise> Retry(JSContext* aCx,
const PaymentValidationErrors& errorField,
ErrorResult& aRv);
void RespondRetry(const nsAString& aMethodName,
const nsAString& aShippingOption,
PaymentAddress* aShippingAddress,
const nsAString& aDetails,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone);
void RejectRetry(nsresult aRejectReason);
protected:
~PaymentResponse();
nsresult ValidatePaymentValidationErrors(const PaymentValidationErrors& aErrors);
private:
nsCOMPtr<nsPIDOMWindowInner> mOwner;
bool mCompleteCalled;
@ -89,6 +104,8 @@ private:
// Timer for timing out if the page doesn't call
// complete()
nsCOMPtr<nsITimer> mTimer;
// Promise for "PaymentResponse::Retry"
RefPtr<Promise> mRetryPromise;
};
} // namespace dom

View File

@ -56,6 +56,8 @@ struct IPCPaymentDetails
IPCPaymentDetailsModifier[] modifiers;
nsString error;
nsString shippingAddressErrors;
nsString payerErrors;
nsString paymentMethodErrors;
};
struct IPCPaymentOptions
@ -110,6 +112,15 @@ struct IPCPaymentCloseActionRequest
nsString requestId;
};
struct IPCPaymentRetryActionRequest
{
nsString requestId;
nsString error;
nsString payerErrors;
nsString paymentMethodErrors;
nsString shippingAddressErrors;
};
union IPCPaymentActionRequest
{
IPCPaymentCreateActionRequest;
@ -119,6 +130,7 @@ union IPCPaymentActionRequest
IPCPaymentCompleteActionRequest;
IPCPaymentUpdateActionRequest;
IPCPaymentCloseActionRequest;
IPCPaymentRetryActionRequest;
};
struct IPCPaymentCanMakeActionResponse

View File

@ -7,21 +7,20 @@
#include "mozilla/ipc/InputStreamUtils.h"
#include "nsArrayUtils.h"
#include "nsCOMPtr.h"
#include "nsIMutableArray.h"
#include "nsIPaymentRequestService.h"
#include "nsISupportsPrimitives.h"
#include "nsServiceManagerUtils.h"
#include "PaymentRequestData.h"
#include "PaymentRequestParent.h"
#include "PaymentRequestService.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS(PaymentRequestParent, nsIPaymentActionCallback)
PaymentRequestParent::PaymentRequestParent(uint64_t aTabId)
: mActorAlive(true)
, mTabId(aTabId)
, mRequestId(EmptyString())
{
}
@ -31,151 +30,75 @@ PaymentRequestParent::RecvRequestPayment(const IPCPaymentActionRequest& aRequest
if (!mActorAlive) {
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIPaymentActionRequest> action;
nsresult rv;
switch (aRequest.type()) {
case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: {
case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest:{
const IPCPaymentCreateActionRequest& request = aRequest;
nsCOMPtr<nsIMutableArray> methodData = do_CreateInstance(NS_ARRAY_CONTRACTID);
MOZ_ASSERT(methodData);
for (IPCPaymentMethodData data : request.methodData()) {
nsCOMPtr<nsIPaymentMethodData> method;
rv = payments::PaymentMethodData::Create(data, getter_AddRefs(method));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
rv = methodData->AppendElement(method);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
}
nsCOMPtr<nsIPaymentDetails> details;
rv = payments::PaymentDetails::Create(request.details(), getter_AddRefs(details));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIPaymentOptions> options;
rv = payments::PaymentOptions::Create(request.options(), getter_AddRefs(options));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIPaymentCreateActionRequest> createAction =
do_CreateInstance(NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID);
if (NS_WARN_IF(!createAction)) {
return IPC_FAIL_NO_REASON(this);
}
rv = createAction->InitRequest(request.requestId(),
this,
mTabId,
request.topLevelPrincipal(),
methodData,
details,
options,
request.shippingOption());
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
action = do_QueryInterface(createAction);
MOZ_ASSERT(action);
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentCanMakeActionRequest: {
case IPCPaymentActionRequest::TIPCPaymentCanMakeActionRequest:{
const IPCPaymentCanMakeActionRequest& request = aRequest;
rv = CreateActionRequest(request.requestId(),
nsIPaymentActionRequest::CANMAKE_ACTION,
getter_AddRefs(action));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentShowActionRequest: {
case IPCPaymentActionRequest::TIPCPaymentShowActionRequest:{
const IPCPaymentShowActionRequest& request = aRequest;
rv = CreateActionRequest(request.requestId(),
nsIPaymentActionRequest::SHOW_ACTION,
getter_AddRefs(action));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentAbortActionRequest: {
const IPCPaymentAbortActionRequest& request = aRequest;
rv = CreateActionRequest(request.requestId(),
nsIPaymentActionRequest::ABORT_ACTION,
getter_AddRefs(action));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentCompleteActionRequest: {
const IPCPaymentCompleteActionRequest& request = aRequest;
nsCOMPtr<nsIPaymentCompleteActionRequest> completeAction =
do_CreateInstance(NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID);
rv = completeAction->InitRequest(request.requestId(),
this,
request.completeStatus());
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
action = do_QueryInterface(completeAction);
MOZ_ASSERT(action);
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest: {
const IPCPaymentUpdateActionRequest& request = aRequest;
nsCOMPtr<nsIPaymentDetails> details;
rv = payments::PaymentDetails::Create(request.details(), getter_AddRefs(details));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIPaymentUpdateActionRequest> updateAction =
do_CreateInstance(NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID);
rv = updateAction->InitRequest(request.requestId(),
this,
details,
request.shippingOption());
action = do_QueryInterface(updateAction);
MOZ_ASSERT(action);
mRequestId = request.requestId();
break;
}
case IPCPaymentActionRequest::TIPCPaymentCloseActionRequest: {
const IPCPaymentCloseActionRequest& request = aRequest;
rv = CreateActionRequest(request.requestId(),
nsIPaymentActionRequest::CLOSE_ACTION,
getter_AddRefs(action));
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
mRequestId = request.requestId();
break;
}
default: {
return IPC_FAIL(this, "Unexpected request type");
case IPCPaymentActionRequest::TIPCPaymentRetryActionRequest: {
const IPCPaymentRetryActionRequest& request = aRequest;
mRequestId = request.requestId();
break;
}
default : {
return IPC_FAIL(this, "Unknown PaymentRequest action type");
}
}
nsCOMPtr<nsIPaymentRequestService> service =
do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
MOZ_ASSERT(service);
rv = service->RequestPayment(action);
PaymentRequestService* rowService =
static_cast<PaymentRequestService*>(service.get());
MOZ_ASSERT(rowService);
nsresult rv = rowService->RequestPayment(mRequestId, aRequest, this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL(this, "nsIPaymentRequestService::RequestPayment failed");
}
return IPC_OK();
}
NS_IMETHODIMP
uint64_t
PaymentRequestParent::GetTabId()
{
return mTabId;
}
nsresult
PaymentRequestParent::RespondPayment(nsIPaymentActionResponse* aResponse)
{
if (!NS_IsMainThread()) {
nsCOMPtr<nsIPaymentActionCallback> self = this;
RefPtr<PaymentRequestParent> self = this;
nsCOMPtr<nsIPaymentActionResponse> response = aResponse;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("PaymentRequestParent::RespondPayment",
[self, response] ()
@ -268,12 +191,12 @@ PaymentRequestParent::RespondPayment(nsIPaymentActionResponse* aResponse)
return NS_OK;
}
NS_IMETHODIMP
nsresult
PaymentRequestParent::ChangeShippingAddress(const nsAString& aRequestId,
nsIPaymentAddress* aAddress)
{
if (!NS_IsMainThread()) {
nsCOMPtr<nsIPaymentActionCallback> self = this;
RefPtr<PaymentRequestParent> self = this;
nsCOMPtr<nsIPaymentAddress> address = aAddress;
nsAutoString requestId(aRequestId);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("dom::PaymentRequestParent::ChangeShippingAddress",
@ -350,12 +273,12 @@ PaymentRequestParent::ChangeShippingAddress(const nsAString& aRequestId,
return NS_OK;
}
NS_IMETHODIMP
nsresult
PaymentRequestParent::ChangeShippingOption(const nsAString& aRequestId,
const nsAString& aOption)
{
if (!NS_IsMainThread()) {
nsCOMPtr<nsIPaymentActionCallback> self = this;
RefPtr<PaymentRequestParent> self = this;
nsAutoString requestId(aRequestId);
nsAutoString option(aOption);
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("dom::PaymentRequestParent::ChangeShippingOption",
@ -390,28 +313,20 @@ PaymentRequestParent::ActorDestroy(ActorDestroyReason aWhy)
nsCOMPtr<nsIPaymentRequestService> service =
do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
MOZ_ASSERT(service);
nsresult rv = service->RemoveActionCallback(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_ASSERT(false);
if (!mRequestId.Equals(EmptyString())) {
nsCOMPtr<nsIPaymentRequest> request;
nsresult rv = service->GetPaymentRequestById(mRequestId, getter_AddRefs(request));
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
if (!request) {
return;
}
payments::PaymentRequest* rowRequest =
static_cast<payments::PaymentRequest*>(request.get());
MOZ_ASSERT(rowRequest);
rowRequest->SetIPC(nullptr);
}
}
nsresult
PaymentRequestParent::CreateActionRequest(const nsAString& aRequestId,
uint32_t aActionType,
nsIPaymentActionRequest** aAction)
{
NS_ENSURE_ARG_POINTER(aAction);
nsCOMPtr<nsIPaymentActionRequest> action =
do_CreateInstance(NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID);
MOZ_ASSERT(action);
nsresult rv = action->Init(aRequestId, aActionType, this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
action.forget(aAction);
return NS_OK;
}
} // end of namespace dom
} // end of namespace mozilla

View File

@ -8,19 +8,25 @@
#define mozilla_dom_PaymentRequestParent_h
#include "mozilla/dom/PPaymentRequestParent.h"
#include "nsIPaymentActionRequest.h"
#include "nsIPaymentAddress.h"
#include "nsIPaymentActionResponse.h"
namespace mozilla {
namespace dom {
class PaymentRequestParent final : public nsIPaymentActionCallback
, public PPaymentRequestParent
class PaymentRequestParent final : public PPaymentRequestParent
{
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIPAYMENTACTIONCALLBACK
NS_INLINE_DECL_REFCOUNTING(PaymentRequestParent)
public:
explicit PaymentRequestParent(uint64_t aTabId);
uint64_t GetTabId();
nsresult RespondPayment(nsIPaymentActionResponse* aResponse);
nsresult ChangeShippingAddress(const nsAString& aRequestId,
nsIPaymentAddress* aAddress);
nsresult ChangeShippingOption(const nsAString& aRequestId,
const nsAString& aOption);
protected:
mozilla::ipc::IPCResult
RecvRequestPayment(const IPCPaymentActionRequest& aRequest) override;
@ -31,12 +37,9 @@ protected:
private:
~PaymentRequestParent() = default;
nsresult CreateActionRequest(const nsAString& aRequestId,
uint32_t aActionType,
nsIPaymentActionRequest** aAction);
bool mActorAlive;
uint64_t mTabId;
nsString mRequestId;
};
} // end of namespace dom

View File

@ -24,7 +24,6 @@ EXPORTS.mozilla.dom += [
UNIFIED_SOURCES += [
'BasicCardPayment.cpp',
'PaymentActionRequest.cpp',
'PaymentActionResponse.cpp',
'PaymentAddress.cpp',
'PaymentMethodChangeEvent.cpp',

View File

@ -0,0 +1,182 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
function emitTestFail(message) {
sendAsyncMessage("test-fail", message);
}
function emitTestPass(message) {
sendAsyncMessage("test-pass", message);
}
const billingAddress = Cc["@mozilla.org/dom/payments/payment-address;1"].
createInstance(Ci.nsIPaymentAddress);
const addressLine = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
const address = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
address.data = "Easton Ave";
addressLine.appendElement(address);
billingAddress.init("USA", // country
addressLine, // address line
"CA", // region
"San Bruno", // city
"", // dependent locality
"94066", // postal code
"123456", // sorting code
"", // organization
"Bill A. Pacheco", // recipient
"+14344413879"); // phone
function acceptPayment(requestId, mode) {
const basiccardResponseData = Cc["@mozilla.org/dom/payments/basiccard-response-data;1"].
createInstance(Ci.nsIBasicCardResponseData);
const showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
createInstance(Ci.nsIPaymentShowActionResponse);
basiccardResponseData.initData("Bill A. Pacheco", // cardholderName
"4916855166538720", // cardNumber
"01", // expiryMonth
"2024", // expiryYear
"180", // cardSecurityCode
billingAddress); // billingAddress
if (mode === "show") {
showResponse.init(requestId,
Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
"basic-card", // payment method
basiccardResponseData,// payment method data
"Bill A. Pacheco", // payer name
"", // payer email
""); // payer phone
}
if (mode == "retry") {
showResponse.init(requestId,
Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
"basic-card", // payment method
basiccardResponseData,// payment method data
"Bill A. Pacheco", // payer name
"bpacheco@test.org", // payer email
"+123456789"); // payer phone
}
paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
}
function rejectPayment(requestId) {
const responseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
createInstance(Ci.nsIGeneralResponseData);
responseData.initData({});
const showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
createInstance(Ci.nsIPaymentShowActionResponse);
showResponse.init(requestId,
Ci.nsIPaymentActionResponse.PAYMENT_REJECTED,
"", // payment method
responseData, // payment method data
"", // payer name
"", // payer email
""); // payer phone
paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
}
function checkAddressErrors(testName, errors) {
if (!errors) {
emitTestFail(`${testName}: Expect non-null shippingAddressErrors, but got null.`);
return;
}
for (const [key, msg] of Object.entries(errors)) {
const expected = `${key} error`;
if (msg !== expected) {
emitTestFail(
`${testName}: Expected '${expected}' on shippingAddressErrors.${key}, but got '${msg}'.`
);
return;
}
}
}
function checkPayerErrors(testName, errors) {
if (!errors) {
emitTestFail(`${testName}: Expect non-null payerErrors, but got null.`);
return;
}
for (const [key, msg] of Object.entries(errors)) {
const expected = `${key} error`;
if (msg !== expected) {
emitTestFail(`${testName}: Expected '${expected}' on payerErrors.${key}, but got '${msg}'.`);
return;
}
}
}
function checkPaymentMethodErrors(testName, errors) {
if (!errors) {
emitTestFail(`${testName} :Expect non-null payerMethodErrors, but got null.`);
return;
}
for (const [key, msg] of Object.entries(errors)) {
const expected = `method ${key} error`;
if (msg !== expected) {
emitTestFail(
`${testName}: Expected '${expected}' on paymentMethodErrors.${key}, but got '${msg}'.`
);
return;
}
}
}
const DummyUIService = {
testName: "",
rejectRetry: false,
showPayment(requestId) {
acceptPayment(requestId, "show");
},
abortPaymen(requestId) {
respondRequestId = requestId
},
completePayment(requestId) {
let completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"].
createInstance(Ci.nsIPaymentCompleteActionResponse);
completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLETE_SUCCEEDED);
paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
},
updatePayment(requestId) {
const payment = paymentSrv.getPaymentRequestById(requestId);
if (payment.paymentDetails.error !== "error") {
emitTestFail("Expect 'error' on details.error, but got '" +
payment.paymentDetails.error + "'");
}
checkAddressErrors(this.testName, payment.paymentDetails.shippingAddressErrors)
checkPayerErrors(this.testName, payment.paymentDetails.payer);
checkPaymentMethodErrors(this.testName, payment.paymentDetails.paymentMethod);
if (this.rejectRetry) {
rejectPayment(requestId);
} else {
acceptPayment(requestId, "retry");
}
},
closePayment: (requestId) => {respondRequestId = requestId},
QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
};
paymentSrv.setTestingUIService(DummyUIService.QueryInterface(Ci.nsIPaymentUIService));
addMessageListener("start-test", function(testName) {
DummyUIService.testName = testName;
sendAsyncMessage("start-test-complete");
});
addMessageListener("finish-test", function() {
DummyUIService.testName = "";
sendAsyncMessage("finish-test-complete");
});
addMessageListener("reject-retry", function() {
DummyUIService.rejectRetry = true;
sendAsyncMessage("reject-retry-complete");
});
addMessageListener("teardown", function() {
paymentSrv.setTestingUIService(null);
sendAsyncMessage('teardown-complete');
});

View File

@ -14,6 +14,7 @@ support-files =
GeneralChromeScript.js
PMIValidationChromeScript.js
RequestShippingChromeScript.js
RetryPaymentChromeScript.js
ShippingOptionsChromeScript.js
ShowPaymentChromeScript.js
UpdateErrorsChromeScript.js
@ -33,6 +34,7 @@ skip-if = (verify && debug)
[test_pmi_validation.html]
skip-if = (verify && debug)
[test_requestShipping.html]
[test_retryPayment.html]
[test_shippingOptions.html]
[test_showPayment.html]
[test_update_errors.html]

View File

@ -0,0 +1,354 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1435161
-->
<head>
<meta charset="utf-8">
<title>Test for retry PaymentRequest</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="DefaultData.js"></script>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
const gUrl = SimpleTest.getTestFileURL('RetryPaymentChromeScript.js');
const gScript = SpecialPowers.loadChromeScript(gUrl);
function testFailHandler(message) {
ok(false, message);
}
function testPassHandler(message) {
ok(true, message);
}
gScript.addMessageListener("test-fail", testFailHandler);
gScript.addMessageListener("test-pass", testPassHandler);
async function requestChromeAction(action, params) {
gScript.sendAsyncMessage(action, params);
await new Promise(resolve => {
gScript.addMessageListener(`${action}-complete`, function completeListener() {
gScript.removeMessageListener(`${action}-complete`, completeListener);
resolve();
});
});
}
const validationErrors = {
error: "error",
shippingAddress: {
addressLine: "addressLine error",
city: "city error",
country: "country error",
dependentLocality: "dependentLocality error",
organization: "organization error",
phone: "phone error",
postalCode: "postalCode error",
recipient: "recipient error",
region: "region error",
regionCode: "regionCode error",
sortingCode: "sortingCode error",
},
payer: {
name: "name error",
email: "email error",
phone: "phone error",
},
paymentMethod: {
account: "method account error",
password: "method password error",
},
};
const options = {
requestPayerName: true,
requestPayerEmail: true,
reqeustPayerPhone: true,
requestShipping: true,
shippingType: "shipping"
};
function checkShowResponse(testName, payResponse) {
const { payerName, payerEmail, payerPhone } = payResponse.toJSON();
is(
payerName,
"Bill A. Pacheco",
`${testName}: Expected 'Bill A. Pacheco' on payerName, but got '${payerName}' after show PaymentRequest`
);
is(
payerEmail,
"",
`${testName}: Expected '' on payerEmail, but got '${payerEmail}' after show PaymentRequest`
);
is(
payerPhone,
"",
`${testName}: Expected '' on payerPhone, but got '${payerPhone}' after show PaymentRequest`
);
}
function checkRetryResponse(testName, payResponse) {
const { payerName, payerEmail, payerPhone } = payResponse.toJSON();
is(
payerName,
"Bill A. Pacheco",
`${testName}: Expected 'Bill A. Pacheco' on payerName, but got '${payerName}' after retry PaymentRequest`
);
is(
payerEmail,
"bpacheco@test.org",
`${testName} : Expected 'bpacheco@test.org' on payerEmail, but got '${payerEmail}' after retry PaymentRequest`
);
is(
payerPhone,
"+123456789",
`${testName} : Expected '+123456789' on payerPhone, but got '${payerPhone}' after retry PaymentRequest`
);
}
function unexpectedErrMsg(testName, errName, timing) {
return `${testName}: Unexpected error(${errName}) when ${timing} the PaymentRequest.`;
}
function expectedErrMsg(testName, expectedErr, errName, timing) {
return `${testName}: Expected '${expectedErr}' when ${timing} PaymentResponse, but got '${errName}'.`;
}
async function testRetryAfterComplete() {
const testName = "testRetryAfterComplete";
await requestChromeAction("start-test", testName);
const payRequest = new PaymentRequest(defaultMethods, defaultDetails, options);
ok(payRequest, testName + ": failed to create PaymentRequest.");
if (!payRequest) {
await requestChromeAction("finish-test");
return;
}
const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
let payResponse;
try {
payResponse = await payRequest.show();
await checkShowResponse(testName, payResponse);
handler.destruct();
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.Name, "showing"));
await requestChromeAction("finish-test");
handler.destruct();
return;
}
try {
await payResponse.complete("success");
} catch(err) {
let errName = err.Name;
ok(false, unexpectedErrMsg(testName, err.Name, "completing"));
await requestChromeAction("finish-test");
return;
}
try {
await payResponse.retry(validationErrors);
ok(false, `${testName}: Unexpected success when retry the PaymentResponse.`);
return;
} catch(err) {
is(err.name,
"InvalidStateError",
expectedErrMsg(testName, "InvalidStateError", err.name, "retrying"));
await requestChromeAction("finish-test");
return;
}
await requestChromeAction("finish-test");
}
async function testRetryAfterRetry() {
const testName = "testRetryAfterRetry";
await requestChromeAction("start-test", testName);
const payRequest = new PaymentRequest(defaultMethods, defaultDetails, options);
ok(payRequest, testName + ": failed to create PaymentRequest.");
if (!payRequest) {
await requestChromeAction("finish-test");
return;
}
const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
let payResponse;
try {
payResponse = await payRequest.show();
await checkShowResponse(testName, payResponse);
handler.destruct();
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.name, "showing"));
await requestChromeAction("finish-test");
handler.destruct();
return;
}
let retryPromise;
try {
retryPromise = payResponse.retry(validationErrors);
await payResponse.retry(validationErrors);
ok(false, `${testName}: Unexpected success when retry the PaymentResponse.`);
await requestChromeAction("finish-test");
return;
} catch(err) {
is(err.name,
"InvalidStateError",
expectedErrMsg(testName, "InvalidStateError", err.name, "retrying"));
}
try {
await retryPromise;
await payResponse.complete("success");
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.name, "completing"));
await requestChromeAction("finish-test");
return;
}
await requestChromeAction("finish-test");
}
async function testRetryWithEmptyErrors() {
const testName = "testRetryWithEmptyErrors";
await requestChromeAction("start-test", testName);
const payRequest = new PaymentRequest(defaultMethods, defaultDetails, options);
ok(payRequest, testName + ": failed to create PaymentRequest.");
if (!payRequest) {
requestChromeAction("finish-test");
return;
}
const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
let payResponse;
try {
payResponse = await payRequest.show();
await checkShowResponse(testName, payResponse);
handler.destruct();
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.name, "showing"));
await requestChromeAction("finish-test");
handler.destruct();
return;
}
try {
await payResponse.retry();
ok(false, `${testName}: Unexpected success when retry the PaymentResponse.`);
await requestChromeAction("finish-test");
return;
} catch(err) {
is(err.name,
"AbortError",
expectedErrMsg(testName, "AbortError", err.name, "retrying"));
}
try {
await payResponse.complete("success");
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.name, "completing"));
await requestChromeAction("finish-test");
return;
}
await requestChromeAction("finish-test");
}
async function testRetry() {
const testName = "testRetry";
await requestChromeAction("start-test", testName);
const payRequest = new PaymentRequest(defaultMethods, defaultDetails, options);
ok(payRequest, testName + ": failed to create PaymentRequest.");
if (!payRequest) {
await requestChromeAction("finish-test");
return;
}
const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
let payResponse;
try {
payResponse = await payRequest.show();
await checkShowResponse(testName, payResponse);
handler.destruct();
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.name, "showing"));
await requestChromeAction("finish-test");
handler.destruct();
return;
}
try {
await payResponse.retry(validationErrors);
await checkRetryResponse(testName, payResponse);
await payResponse.complete("success");
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.name, "retrying"));
await requestChromeAction("finish-test");
return;
}
await requestChromeAction("finish-test");
}
async function testRetryAbortByUser() {
const testName = "testRetryAbortByUser";
await requestChromeAction("reject-retry");
const payRequest = new PaymentRequest(defaultMethods, defaultDetails, options);
ok(payRequest, testName + ": failed to create PaymentRequest.");
if (!payRequest) {
await requestChromeAction("finish-test");
return;
}
const handler = SpecialPowers.getDOMWindowUtils(window).setHandlingUserInput(true);
let payResponse;
try {
payResponse = await payRequest.show();
await checkShowResponse(testName, payResponse);
handler.destruct();
} catch(err) {
ok(false, unexpectedErrMsg(testName, err.name, "showing"));
handler.destruct();
await requestChromeAction("finish-test");
return;
}
try {
await payResponse.retry(validationErrors);
ok(false, `${testName}: Unexpected success when retry the PaymentResponse.`);
await requestChromeAction("finish-test");
return;
} catch(err) {
is(err.name,
"AbortError",
expectedErrMsg(testName, "AbortError", err.name, "retrying"));
}
await requestChromeAction("finish-test");
}
function teardown() {
return new Promise((resolve, reject) => {
gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
gScript.removeMessageListener("test-fail", testFailHandler);
gScript.removeMessageListener("test-pass", testPassHandler);
gScript.destroy();
SimpleTest.finish();
resolve();
});
gScript.sendAsyncMessage("teardown");
});
}
async function runTests() {
try {
await testRetryAfterComplete()
await testRetryAfterRetry()
await testRetryWithEmptyErrors()
await testRetry()
await testRetryAbortByUser()
await teardown()
} catch(e) {
ok(false, "Unexpected error: " + e.name);
SimpleTest.finish();
}
}
window.addEventListener('load', function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.payments.request.enabled', true],
]
}, runTests);
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1435161">Mozilla Bug 1435161</a>
</body>
</html>

View File

@ -68,9 +68,24 @@ dictionary AddressErrors {
DOMString sortingCode;
};
dictionary PaymentValidationErrors {
PayerErrorFields payer;
AddressErrors shippingAddress;
DOMString error;
object paymentMethod;
};
dictionary PayerErrorFields {
DOMString email;
DOMString name;
DOMString phone;
};
dictionary PaymentDetailsUpdate : PaymentDetailsBase {
DOMString error;
AddressErrors shippingAddressErrors;
PayerErrorFields payerErrors;
object paymentMethodErrors;
PaymentItem total;
};

View File

@ -29,4 +29,8 @@ interface PaymentResponse {
[NewObject]
Promise<void> complete(optional PaymentComplete result = "unknown");
// If the dictionary argument has no required members, it must be optional.
[NewObject]
Promise<void> retry(optional PaymentValidationErrors errorFields);
};

View File

@ -7,8 +7,7 @@ function load()
let textarea = document.getElementById("editor");
textarea.focus();
SpecialPowers.Cu.import(
"chrome://reftest/content/AsyncSpellCheckTestHelper.jsm")
SpecialPowers.Cu.import("resource://reftest/AsyncSpellCheckTestHelper.jsm")
.onSpellCheck(textarea, () => {
let isc = SpecialPowers.wrap(textarea).editor.getInlineSpellChecker(false);
let sc = isc.spellChecker;

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://reftest/content/input.css" type="text/css"?>
<?xml-stylesheet href="resource://reftest/input.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

View File

@ -130,15 +130,15 @@ impl GlyphCache {
where
for<'r> F: Fn(&'r &FontInstance) -> bool,
{
let caches_to_destroy = self.glyph_key_caches
.keys()
.filter(&key_fun)
.cloned()
.collect::<Vec<_>>();
for key in caches_to_destroy {
let mut cache = self.glyph_key_caches.remove(&key).unwrap();
self.glyph_key_caches.retain(|k, cache| {
let should_clear = key_fun(&k);
if !should_clear {
return true;
}
cache.clear();
}
false
})
}
// Clear out evicted entries from glyph key caches and, if possible,

View File

@ -97,12 +97,6 @@ struct Document {
// A set of pipelines that the caller has requested be
// made available as output textures.
output_pipelines: FastHashSet<PipelineId>,
// A helper switch to prevent any frames rendering triggered by scrolling
// messages between `SetDisplayList` and `GenerateFrame`.
// If we allow them, then a reftest that scrolls a few layers before generating
// the first frame would produce inconsistent rendering results, because
// scroll events are not necessarily received in deterministic order.
render_on_scroll: Option<bool>,
/// A data structure to allow hit testing against rendered frames. This is updated
/// every time we produce a fully rendered frame.
@ -117,14 +111,8 @@ impl Document {
pub fn new(
window_size: DeviceUintSize,
layer: DocumentLayer,
enable_render_on_scroll: bool,
default_device_pixel_ratio: f32,
) -> Self {
let render_on_scroll = if enable_render_on_scroll {
Some(false)
} else {
None
};
Document {
scene: Scene::new(),
removed_pipelines: Vec::new(),
@ -141,7 +129,6 @@ impl Document {
frame_id: FrameId(0),
frame_builder: None,
output_pipelines: FastHashSet::default(),
render_on_scroll,
hit_tester: None,
dynamic_properties: SceneProperties::new(),
}
@ -173,7 +160,6 @@ impl Document {
FrameMsg::Scroll(delta, cursor) => {
profile_scope!("Scroll");
let mut should_render = true;
let node_index = match self.hit_tester {
Some(ref hit_tester) => {
// Ideally we would call self.scroll_nearest_scrolling_ancestor here, but
@ -182,20 +168,18 @@ impl Document {
hit_tester.find_node_under_point(test)
}
None => {
should_render = false;
None
}
};
let should_render =
should_render &&
self.scroll_nearest_scrolling_ancestor(delta, node_index) &&
self.render_on_scroll == Some(true);
if self.hit_tester.is_some() {
let _scrolled = self.scroll_nearest_scrolling_ancestor(delta, node_index);
}
return DocumentOps {
// TODO: Does it make sense to track this as a scrolling even if we
// ended up not scrolling anything?
scroll: true,
build_frame: should_render,
render_frame: should_render,
..DocumentOps::nop()
};
}
@ -216,13 +200,10 @@ impl Document {
FrameMsg::ScrollNodeWithId(origin, id, clamp) => {
profile_scope!("ScrollNodeWithScrollId");
let should_render = self.scroll_node(origin, id, clamp)
&& self.render_on_scroll == Some(true);
let _scrolled = self.scroll_node(origin, id, clamp);
return DocumentOps {
scroll: true,
build_frame: should_render,
render_frame: should_render,
..DocumentOps::nop()
};
}
@ -350,7 +331,6 @@ static NEXT_NAMESPACE_ID: AtomicUsize = ATOMIC_USIZE_INIT;
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct PlainRenderBackend {
default_device_pixel_ratio: f32,
enable_render_on_scroll: bool,
frame_config: FrameBuilderConfig,
documents: FastHashMap<DocumentId, DocumentView>,
resources: PlainResources,
@ -384,7 +364,6 @@ pub struct RenderBackend {
sampler: Option<Box<AsyncPropertySampler + Send>>,
last_scene_id: u64,
enable_render_on_scroll: bool,
}
impl RenderBackend {
@ -401,7 +380,6 @@ impl RenderBackend {
frame_config: FrameBuilderConfig,
recorder: Option<Box<ApiRecordingReceiver>>,
sampler: Option<Box<AsyncPropertySampler + Send>>,
enable_render_on_scroll: bool,
) -> RenderBackend {
// The namespace_id should start from 1.
NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed);
@ -423,7 +401,6 @@ impl RenderBackend {
recorder,
sampler,
last_scene_id: 0,
enable_render_on_scroll,
}
}
@ -507,10 +484,6 @@ impl RenderBackend {
content_size,
});
if let Some(ref mut ros) = doc.render_on_scroll {
*ros = false; //wait for `GenerateFrame`
}
// Note: this isn't quite right as auxiliary values will be
// pulled out somewhere in the prim_store, but aux values are
// really simple and cheap to access, so it's not a big deal.
@ -597,18 +570,16 @@ impl RenderBackend {
self.resource_cache.set_blob_rasterizer(rasterizer);
}
if txn.build_frame || !txn.resource_updates.is_empty() || !txn.frame_ops.is_empty() {
self.update_document(
self.update_document(
txn.document_id,
replace(&mut txn.resource_updates, Vec::new()),
replace(&mut txn.frame_ops, Vec::new()),
txn.build_frame,
txn.render_frame,
&mut frame_counter,
&mut profile_counters,
has_built_scene,
);
}
replace(&mut txn.resource_updates, Vec::new()),
replace(&mut txn.frame_ops, Vec::new()),
txn.build_frame,
txn.render_frame,
&mut frame_counter,
&mut profile_counters,
has_built_scene,
);
},
SceneBuilderResult::FlushComplete(tx) => {
tx.send(()).ok();
@ -704,7 +675,6 @@ impl RenderBackend {
let document = Document::new(
initial_size,
layer,
self.enable_render_on_scroll,
self.default_device_pixel_ratio,
);
self.documents.insert(document_id, document);
@ -720,14 +690,7 @@ impl RenderBackend {
}
ApiMsg::ClearNamespace(namespace_id) => {
self.resource_cache.clear_namespace(namespace_id);
let document_ids = self.documents
.keys()
.filter(|did| did.0 == namespace_id)
.cloned()
.collect::<Vec<_>>();
for document in document_ids {
self.documents.remove(&document);
}
self.documents.retain(|did, _doc| did.0 != namespace_id);
}
ApiMsg::MemoryPressure => {
// This is drastic. It will basically flush everything out of the cache,
@ -956,12 +919,6 @@ impl RenderBackend {
build_frame = true;
}
if render_frame {
if let Some(ref mut ros) = doc.render_on_scroll {
*ros = true;
}
}
if !doc.can_render() {
// TODO: this happens if we are building the first scene asynchronously and
// scroll at the same time. we should keep track of the fact that we skipped
@ -1225,7 +1182,6 @@ impl RenderBackend {
info!("\tbackend");
let backend = PlainRenderBackend {
default_device_pixel_ratio: self.default_device_pixel_ratio,
enable_render_on_scroll: self.enable_render_on_scroll,
frame_config: self.frame_config.clone(),
documents: self.documents
.iter()
@ -1290,7 +1246,6 @@ impl RenderBackend {
self.documents.clear();
self.default_device_pixel_ratio = backend.default_device_pixel_ratio;
self.frame_config = backend.frame_config;
self.enable_render_on_scroll = backend.enable_render_on_scroll;
let mut scenes_to_build = Vec::new();
@ -1309,7 +1264,6 @@ impl RenderBackend {
frame_id: FrameId(0),
frame_builder: Some(FrameBuilder::empty()),
output_pipelines: FastHashSet::default(),
render_on_scroll: None,
dynamic_properties: SceneProperties::new(),
hit_tester: None,
};

View File

@ -458,48 +458,6 @@ pub(crate) mod desc {
],
};
pub const BORDER_CORNER_DASH_AND_DOT: VertexDescriptor = VertexDescriptor {
vertex_attributes: &[
VertexAttribute {
name: "aPosition",
count: 2,
kind: VertexAttributeKind::F32,
},
],
instance_attributes: &[
VertexAttribute {
name: "aClipRenderTaskAddress",
count: 1,
kind: VertexAttributeKind::I32,
},
VertexAttribute {
name: "aScrollNodeId",
count: 1,
kind: VertexAttributeKind::I32,
},
VertexAttribute {
name: "aClipSegment",
count: 1,
kind: VertexAttributeKind::I32,
},
VertexAttribute {
name: "aClipDataResourceAddress",
count: 4,
kind: VertexAttributeKind::U16,
},
VertexAttribute {
name: "aDashOrDot0",
count: 4,
kind: VertexAttributeKind::F32,
},
VertexAttribute {
name: "aDashOrDot1",
count: 4,
kind: VertexAttributeKind::F32,
},
],
};
pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor {
vertex_attributes: &[
VertexAttribute {
@ -1349,7 +1307,6 @@ pub struct RendererVAOs {
prim_vao: VAO,
blur_vao: VAO,
clip_vao: VAO,
dash_and_dot_vao: VAO,
border_vao: VAO,
}
@ -1646,8 +1603,6 @@ impl Renderer {
let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao);
let border_vao =
device.create_vao_with_new_instances(&desc::BORDER, &prim_vao);
let dash_and_dot_vao =
device.create_vao_with_new_instances(&desc::BORDER_CORNER_DASH_AND_DOT, &prim_vao);
let texture_cache_upload_pbo = device.create_pbo();
let texture_resolver = SourceTextureResolver::new(&mut device);
@ -1710,7 +1665,6 @@ impl Renderer {
Arc::new(worker.unwrap())
});
let sampler = options.sampler;
let enable_render_on_scroll = options.enable_render_on_scroll;
let blob_image_handler = options.blob_image_handler.take();
let thread_listener_for_render_backend = thread_listener.clone();
@ -1792,7 +1746,6 @@ impl Renderer {
config,
recorder,
sampler,
enable_render_on_scroll,
);
backend.run(backend_profile_counters);
if let Some(ref thread_listener) = *thread_listener_for_render_backend {
@ -1836,7 +1789,6 @@ impl Renderer {
prim_vao,
blur_vao,
clip_vao,
dash_and_dot_vao,
border_vao,
},
transforms_texture,
@ -4060,7 +4012,6 @@ impl Renderer {
self.device.delete_vao(self.vaos.prim_vao);
self.device.delete_vao(self.vaos.clip_vao);
self.device.delete_vao(self.vaos.blur_vao);
self.device.delete_vao(self.vaos.dash_and_dot_vao);
self.device.delete_vao(self.vaos.border_vao);
#[cfg(feature = "debug_renderer")]
@ -4240,7 +4191,6 @@ pub struct RendererOptions {
pub blob_image_handler: Option<Box<BlobImageHandler>>,
pub recorder: Option<Box<ApiRecordingReceiver>>,
pub thread_listener: Option<Box<ThreadListener + Send + Sync>>,
pub enable_render_on_scroll: bool,
pub cached_programs: Option<Rc<ProgramCache>>,
pub debug_flags: DebugFlags,
pub renderer_id: Option<u64>,
@ -4276,7 +4226,6 @@ impl Default for RendererOptions {
blob_image_handler: None,
recorder: None,
thread_listener: None,
enable_render_on_scroll: true,
renderer_id: None,
cached_programs: None,
disable_dual_source_blending: false,

View File

@ -395,12 +395,11 @@ impl SegmentBuilder {
None => return,
};
let mut items = self.items;
// First, filter out any items that don't intersect
// with the visible bounding rect.
let mut items: Vec<Item> = self.items
.into_iter()
.filter(|item| item.rect.intersects(&bounding_rect))
.collect();
items.retain(|item| item.rect.intersects(&bounding_rect));
// Create events for each item
let mut x_events = Vec::new();

View File

@ -400,6 +400,14 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
return IntRectAbsolute(x1, y1, x2, y2);
}
layers::BlobFont ReadBlobFont() {
MOZ_RELEASE_ASSERT(pos + sizeof(layers::BlobFont) <= len);
layers::BlobFont ret;
memcpy(&ret, buf + pos, sizeof(ret));
pos += sizeof(ret);
return ret;
}
};
MOZ_RELEASE_ASSERT(aBlob.length() > sizeof(size_t));
@ -421,10 +429,12 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
layers::WebRenderTranslator translator(dt);
size_t count = *(size_t*)(aBlob.begin().get() + end);
MOZ_RELEASE_ASSERT(extra_end >= end);
MOZ_RELEASE_ASSERT(extra_end < aBlob.length());
Reader fontReader(aBlob.begin().get() + end, extra_end - end);
size_t count = fontReader.ReadSize();
for (size_t i = 0; i < count; i++) {
layers::BlobFont blobFont =
*(layers::BlobFont*)(aBlob.begin() + end + sizeof(count) + sizeof(layers::BlobFont)*i).get();
layers::BlobFont blobFont = fontReader.ReadBlobFont();
RefPtr<ScaledFont> scaledFont = GetScaledFont(&translator, blobFont.mFontInstanceKey);
translator.AddScaledFont(blobFont.mScaledFontPtr, scaledFont);
}

View File

@ -1 +1 @@
ced27184ede63268f78ab56453e7ee39007826d7
27e3bc4293d4a5057346739bfe8b7a163cf068f3

View File

@ -938,7 +938,6 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
blob_image_handler: Some(Box::new(Moz2dBlobImageHandler::new(workers.clone()))),
workers: Some(workers.clone()),
thread_listener: Some(Box::new(GeckoProfilerThreadListener::new())),
enable_render_on_scroll: false,
resource_override_path: unsafe {
let override_charptr = gfx_wr_resource_path_override();
if override_charptr.is_null() {

View File

@ -40,6 +40,7 @@ from __future__ import with_statement
import re
import sys
import os
import mozpack.path as mozpath
import subprocess
import shlex
import which
@ -86,8 +87,11 @@ namespace %(namespace)s {
def embed(cxx, preprocessorOption, cppflags, msgs, sources, c_out, js_out, namespace, env):
objdir = os.getcwd()
# Use relative pathnames to avoid path translation issues in WSL.
combinedSources = '\n'.join([msgs] + ['#include "%(s)s"' %
{'s': source} for source in sources])
{'s': mozpath.relpath(source, objdir)}
for source in sources])
args = cppflags + ['-D%(k)s=%(v)s' % {'k': k, 'v': env[k]} for k in env]
preprocessed = preprocess(cxx, preprocessorOption, combinedSources, args)
processed = '\n'.join([line for line in preprocessed.splitlines() if

View File

@ -0,0 +1,5 @@
// |jit-test| allow-overrecursed
function f() {
f.apply(null, new Array(20000));
}
f()

View File

@ -2572,7 +2572,7 @@ class Simulator : public DecoderVisitor {
// Stack
byte* stack_;
static const int stack_protection_size_ = 128 * KBytes;
static const int stack_protection_size_ = 512 * KBytes;
static const int stack_size_ = (2 * MBytes) + (2 * stack_protection_size_);
byte* stack_limit_;

View File

@ -188,6 +188,7 @@ EXPORTS.js += [
]
UNIFIED_SOURCES += [
'builtin/Array.cpp',
'builtin/AtomicsObject.cpp',
'builtin/Boolean.cpp',
'builtin/DataViewObject.cpp',
@ -382,6 +383,7 @@ UNIFIED_SOURCES += [
'vm/Id.cpp',
'vm/Initialization.cpp',
'vm/Iteration.cpp',
'vm/JSAtom.cpp',
'vm/JSContext.cpp',
'vm/JSFunction.cpp',
'vm/JSObject.cpp',
@ -443,8 +445,6 @@ UNIFIED_SOURCES += [
'wasm/WasmValidate.cpp'
]
# builtin/Array.cpp and vm/JSAtom.cpp cannot be built in unified mode because
# xpcshell is broken during packaging when compiled with gcc-4.8.2
# builtin/RegExp.cpp cannot be built in unified mode because it causes huge
# win32 test slowdowns
# frontend/Parser.cpp cannot be built in unified mode because of explicit
@ -464,7 +464,6 @@ UNIFIED_SOURCES += [
# vm/Interpreter.cpp is gigantic and destroys incremental build times for any
# files unlucky enough to be unified with it.
SOURCES += [
'builtin/Array.cpp',
'builtin/RegExp.cpp',
'frontend/Parser.cpp',
'gc/StoreBuffer.cpp',
@ -472,7 +471,6 @@ SOURCES += [
'jsutil.cpp',
'util/DoubleToString.cpp',
'vm/Interpreter.cpp',
'vm/JSAtom.cpp',
'vm/ProfilingStack.cpp',
]

View File

@ -1662,12 +1662,6 @@ else
fi
AC_SUBST(CL_INCLUDES_PREFIX)
rm -f dummy-hello.c
dnl Make sure that the build system can handle non-ASCII characters
dnl in environment variables to prevent it from breaking silently on
dnl non-English systems.
NONASCII=$'\241\241'
AC_SUBST(NONASCII)
fi
fi

View File

@ -428,12 +428,14 @@ ParseTask::ParseTask(ParseTaskKind kind, JSContext* cx,
JS::OffThreadCompileCallback callback, void* callbackData)
: kind(kind),
options(cx),
alloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
parseGlobal(nullptr),
callback(callback), callbackData(callbackData),
scripts(cx), sourceObjects(cx),
overRecursed(false), outOfMemory(false)
{
// Note that |cx| is the main thread context here but the parse task will
// run with a different, helper thread, context.
MOZ_ASSERT(!cx->helperThread());
MOZ_ALWAYS_TRUE(scripts.reserve(scripts.capacity()));
MOZ_ALWAYS_TRUE(sourceObjects.reserve(sourceObjects.capacity()));
}
@ -441,6 +443,8 @@ ParseTask::ParseTask(ParseTaskKind kind, JSContext* cx,
bool
ParseTask::init(JSContext* cx, const ReadOnlyCompileOptions& options, JSObject* global)
{
MOZ_ASSERT(!cx->helperThread());
if (!this->options.copy(cx, options))
return false;
@ -454,20 +458,6 @@ ParseTask::activate(JSRuntime* rt)
rt->setUsedByHelperThread(parseGlobal->zone());
}
bool
ParseTask::finish(JSContext* cx)
{
for (auto& sourceObject : sourceObjects) {
RootedScriptSourceObject sso(cx, sourceObject);
if (!ScriptSourceObject::initFromOptions(cx, sso, options))
return false;
if (!sso->source()->tryCompressOffThread(cx))
return false;
}
return true;
}
ParseTask::~ParseTask() = default;
void
@ -491,7 +481,6 @@ size_t
ParseTask::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return options.sizeOfExcludingThis(mallocSizeOf) +
alloc.sizeOfExcludingThis(mallocSizeOf) +
errors.sizeOfExcludingThis(mallocSizeOf);
}
@ -504,11 +493,13 @@ ScriptParseTask::ScriptParseTask(JSContext* cx, JS::SourceBufferHolder& srcBuf,
void
ScriptParseTask::parse(JSContext* cx)
{
MOZ_ASSERT(cx->helperThread());
Rooted<ScriptSourceObject*> sourceObject(cx);
ScopeKind scopeKind = options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
JSScript* script = frontend::CompileGlobalScript(cx, alloc, scopeKind,
JSScript* script = frontend::CompileGlobalScript(cx, cx->tempLifoAlloc(), scopeKind,
options, data,
/* sourceObjectOut = */ &sourceObject.get());
if (script)
@ -526,9 +517,11 @@ ModuleParseTask::ModuleParseTask(JSContext* cx, JS::SourceBufferHolder& srcBuf,
void
ModuleParseTask::parse(JSContext* cx)
{
MOZ_ASSERT(cx->helperThread());
Rooted<ScriptSourceObject*> sourceObject(cx);
JSScript* script = frontend::CompileModule(cx, options, data, alloc, &sourceObject.get());
JSScript* script = frontend::CompileModule(cx, options, data, cx->tempLifoAlloc(), &sourceObject.get());
if (script) {
scripts.infallibleAppend(script);
if (sourceObject)
@ -545,11 +538,13 @@ ScriptDecodeTask::ScriptDecodeTask(JSContext* cx, const JS::TranscodeRange& rang
void
ScriptDecodeTask::parse(JSContext* cx)
{
MOZ_ASSERT(cx->helperThread());
RootedScript resultScript(cx);
Rooted<ScriptSourceObject*> sourceObject(cx);
XDROffThreadDecoder decoder(cx, alloc, &options, /* sourceObjectOut = */ &sourceObject.get(),
range);
XDROffThreadDecoder decoder(cx, cx->tempLifoAlloc(), &options,
/* sourceObjectOut = */ &sourceObject.get(), range);
XDRResult res = decoder.codeScript(&resultScript);
MOZ_ASSERT(bool(resultScript) == res.isOk());
if (res.isOk()) {
@ -570,9 +565,11 @@ BinASTDecodeTask::BinASTDecodeTask(JSContext* cx, const uint8_t* buf, size_t len
void
BinASTDecodeTask::parse(JSContext* cx)
{
MOZ_ASSERT(cx->helperThread());
RootedScriptSourceObject sourceObject(cx);
JSScript* script = frontend::CompileGlobalBinASTScript(cx, alloc, options,
JSScript* script = frontend::CompileGlobalBinASTScript(cx, cx->tempLifoAlloc(), options,
data.begin().get(), data.length(),
&sourceObject.get());
if (script) {
@ -594,9 +591,12 @@ MultiScriptsDecodeTask::MultiScriptsDecodeTask(JSContext* cx, JS::TranscodeSourc
void
MultiScriptsDecodeTask::parse(JSContext* cx)
{
MOZ_ASSERT(cx->helperThread());
if (!scripts.reserve(sources->length()) ||
!sourceObjects.reserve(sources->length()))
{
ReportOutOfMemory(cx); // This sets |outOfMemory|.
return;
}
@ -607,7 +607,8 @@ MultiScriptsDecodeTask::parse(JSContext* cx)
RootedScript resultScript(cx);
Rooted<ScriptSourceObject*> sourceObject(cx);
XDROffThreadDecoder decoder(cx, alloc, &opts, &sourceObject.get(), source.range);
XDROffThreadDecoder decoder(cx, cx->tempLifoAlloc(), &opts, &sourceObject.get(),
source.range);
XDRResult res = decoder.codeScript(&resultScript);
MOZ_ASSERT(bool(resultScript) == res.isOk());
@ -1647,11 +1648,11 @@ GlobalHelperThreadState::removeFinishedParseTask(ParseTaskKind kind, JS::OffThre
return task;
}
template <typename F, typename>
bool
GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
JS::OffThreadToken* token, F&& finishCallback)
UniquePtr<ParseTask>
GlobalHelperThreadState::finishParseTaskCommon(JSContext* cx, ParseTaskKind kind,
JS::OffThreadToken* token)
{
MOZ_ASSERT(!cx->helperThread());
MOZ_ASSERT(cx->realm());
Rooted<UniquePtr<ParseTask>> parseTask(cx, removeFinishedParseTask(kind, token));
@ -1660,23 +1661,26 @@ GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
// remapping below, since we can't GC while that's happening.
if (!EnsureParserCreatedClasses(cx, kind)) {
LeaveParseTaskZone(cx->runtime(), parseTask.get().get());
return false;
return nullptr;
}
mergeParseTaskRealm(cx, parseTask.get().get(), cx->realm());
bool ok = finishCallback(parseTask.get().get());
for (auto& script : parseTask->scripts)
cx->releaseCheck(script);
if (!parseTask->finish(cx) || !ok)
return false;
for (auto& sourceObject : parseTask->sourceObjects) {
RootedScriptSourceObject sso(cx, sourceObject);
if (!ScriptSourceObject::initFromOptions(cx, sso, parseTask->options))
return nullptr;
if (!sso->source()->tryCompressOffThread(cx))
return nullptr;
}
// Report out of memory errors eagerly, or errors could be malformed.
if (parseTask->outOfMemory) {
ReportOutOfMemory(cx);
return false;
return nullptr;
}
// Report any error or warnings generated during the parse.
@ -1685,28 +1689,27 @@ GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
if (parseTask->overRecursed)
ReportOverRecursed(cx);
if (cx->isExceptionPending())
return false;
return nullptr;
return true;
return std::move(parseTask.get());
}
JSScript*
GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
JS::OffThreadToken* token)
GlobalHelperThreadState::finishSingleParseTask(JSContext* cx, ParseTaskKind kind,
JS::OffThreadToken* token)
{
JS::RootedScript script(cx);
bool ok = finishParseTask(cx, kind, token, [&script] (ParseTask* parseTask) {
MOZ_RELEASE_ASSERT(parseTask->scripts.length() <= 1);
if (parseTask->scripts.length() > 0)
script = parseTask->scripts[0];
return true;
});
if (!ok)
Rooted<UniquePtr<ParseTask>> parseTask(cx, finishParseTaskCommon(cx, kind, token));
if (!parseTask) {
return nullptr;
}
MOZ_RELEASE_ASSERT(parseTask->scripts.length() <= 1);
if (parseTask->scripts.length() > 0) {
script = parseTask->scripts[0];
}
if (!script) {
// No error was reported, but no script produced. Assume we hit out of
@ -1723,29 +1726,26 @@ GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
}
bool
GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
JS::OffThreadToken* token,
MutableHandle<ScriptVector> scripts)
GlobalHelperThreadState::finishMultiParseTask(JSContext* cx, ParseTaskKind kind,
JS::OffThreadToken* token,
MutableHandle<ScriptVector> scripts)
{
size_t expectedLength = 0;
bool ok = finishParseTask(cx, kind, token, [&scripts, &expectedLength] (ParseTask* parseTask) {
MOZ_ASSERT(parseTask->kind == ParseTaskKind::MultiScriptsDecode);
auto task = static_cast<MultiScriptsDecodeTask*>(parseTask);
expectedLength = task->sources->length();
if (!scripts.reserve(task->scripts.length()))
return false;
for (auto& script : task->scripts)
scripts.infallibleAppend(script);
return true;
});
if (!ok)
Rooted<UniquePtr<ParseTask>> parseTask(cx, finishParseTaskCommon(cx, kind, token));
if (!parseTask)
return false;
MOZ_ASSERT(parseTask->kind == ParseTaskKind::MultiScriptsDecode);
auto task = static_cast<MultiScriptsDecodeTask*>(parseTask.get().get());
size_t expectedLength = task->sources->length();
if (!scripts.reserve(parseTask->scripts.length())) {
ReportOutOfMemory(cx);
return false;
}
for (auto& script : parseTask->scripts)
scripts.infallibleAppend(script);
if (scripts.length() != expectedLength) {
// No error was reported, but fewer scripts produced than expected.
// Assume we hit out of memory.
@ -1769,7 +1769,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind,
JSScript*
GlobalHelperThreadState::finishScriptParseTask(JSContext* cx, JS::OffThreadToken* token)
{
JSScript* script = finishParseTask(cx, ParseTaskKind::Script, token);
JSScript* script = finishSingleParseTask(cx, ParseTaskKind::Script, token);
MOZ_ASSERT_IF(script, script->isGlobalCode());
return script;
}
@ -1777,7 +1777,7 @@ GlobalHelperThreadState::finishScriptParseTask(JSContext* cx, JS::OffThreadToken
JSScript*
GlobalHelperThreadState::finishScriptDecodeTask(JSContext* cx, JS::OffThreadToken* token)
{
JSScript* script = finishParseTask(cx, ParseTaskKind::ScriptDecode, token);
JSScript* script = finishSingleParseTask(cx, ParseTaskKind::ScriptDecode, token);
MOZ_ASSERT_IF(script, script->isGlobalCode());
return script;
}
@ -1787,7 +1787,7 @@ GlobalHelperThreadState::finishScriptDecodeTask(JSContext* cx, JS::OffThreadToke
JSScript*
GlobalHelperThreadState::finishBinASTDecodeTask(JSContext* cx, JS::OffThreadToken* token)
{
JSScript* script = finishParseTask(cx, ParseTaskKind::BinAST, token);
JSScript* script = finishSingleParseTask(cx, ParseTaskKind::BinAST, token);
MOZ_ASSERT_IF(script, script->isGlobalCode());
return script;
}
@ -1798,13 +1798,13 @@ bool
GlobalHelperThreadState::finishMultiScriptsDecodeTask(JSContext* cx, JS::OffThreadToken* token,
MutableHandle<ScriptVector> scripts)
{
return finishParseTask(cx, ParseTaskKind::MultiScriptsDecode, token, scripts);
return finishMultiParseTask(cx, ParseTaskKind::MultiScriptsDecode, token, scripts);
}
JSScript*
GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token)
{
RootedScript script(cx, finishParseTask(cx, ParseTaskKind::Module, token));
RootedScript script(cx, finishSingleParseTask(cx, ParseTaskKind::Module, token));
if (!script)
return nullptr;

View File

@ -279,30 +279,23 @@ class GlobalHelperThreadState
// Used by a major GC to signal processing enqueued compression tasks.
void startHandlingCompressionTasks(const AutoLockHelperThreadState&);
jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock);
private:
void scheduleCompressionTasks(const AutoLockHelperThreadState&);
public:
jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock);
UniquePtr<ParseTask> finishParseTaskCommon(JSContext* cx, ParseTaskKind kind,
JS::OffThreadToken* token);
template <
typename F,
typename = typename mozilla::EnableIf<
// Matches when the type is a function or lambda with the signature `bool(ParseTask*)`
mozilla::IsSame<bool, decltype((*(F*)nullptr)((ParseTask*)nullptr))>::value
>::Type
>
bool finishParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token, F&& finishCallback);
JSScript* finishParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token);
bool finishParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token, MutableHandle<ScriptVector> scripts);
void cancelParseTask(JSRuntime* rt, ParseTaskKind kind, JS::OffThreadToken* token);
void destroyParseTask(JSRuntime* rt, ParseTask* parseTask);
JSScript* finishSingleParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token);
bool finishMultiParseTask(JSContext* cx, ParseTaskKind kind, JS::OffThreadToken* token,
MutableHandle<ScriptVector> scripts);
void mergeParseTaskRealm(JSContext* cx, ParseTask* parseTask, JS::Realm* dest);
public:
void cancelParseTask(JSRuntime* rt, ParseTaskKind kind, JS::OffThreadToken* token);
void destroyParseTask(JSRuntime* rt, ParseTask* parseTask);
void trace(JSTracer* trc);
JSScript* finishScriptParseTask(JSContext* cx, JS::OffThreadToken* token);
@ -690,8 +683,6 @@ struct ParseTask : public mozilla::LinkedListElement<ParseTask>, public JS::OffT
ParseTaskKind kind;
JS::OwningCompileOptions options;
LifoAlloc alloc;
// The global object to use while parsing.
JSObject* parseGlobal;
@ -702,10 +693,10 @@ struct ParseTask : public mozilla::LinkedListElement<ParseTask>, public JS::OffT
// Holds the final scripts between the invocation of the callback and the
// point where FinishOffThreadScript is called, which will destroy the
// ParseTask.
GCVector<JSScript*, 1> scripts;
GCVector<JSScript*, 1, SystemAllocPolicy> scripts;
// Holds the ScriptSourceObjects generated for the script compilation.
GCVector<ScriptSourceObject*, 1> sourceObjects;
GCVector<ScriptSourceObject*, 1, SystemAllocPolicy> sourceObjects;
// Any errors or warnings produced during compilation. These are reported
// when finishing the script.
@ -721,7 +712,6 @@ struct ParseTask : public mozilla::LinkedListElement<ParseTask>, public JS::OffT
void activate(JSRuntime* rt);
virtual void parse(JSContext* cx) = 0;
bool finish(JSContext* cx);
bool runtimeMatches(JSRuntime* rt) {
return parseGlobal->runtimeFromAnyThread() == rt;

View File

@ -204,6 +204,7 @@ XPC_MSG_DEF(NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE , "The JAR's signature is wr
XPC_MSG_DEF(NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE , "An entry in the JAR is too large.")
XPC_MSG_DEF(NS_ERROR_SIGNED_JAR_ENTRY_INVALID , "An entry in the JAR is invalid.")
XPC_MSG_DEF(NS_ERROR_SIGNED_JAR_MANIFEST_INVALID , "The JAR's manifest or signature file is invalid.")
XPC_MSG_DEF(NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO , "The PKCS#7 signature is malformed or invalid.")
XPC_MSG_DEF(NS_ERROR_CMS_VERIFY_NOT_SIGNED , "The PKCS#7 information is not signed.")
/* Codes related to signed manifests */
@ -236,4 +237,4 @@ XPC_MSG_DEF(NS_ERROR_PHISHING_URI , "The URI is phishing")
XPC_MSG_DEF(NS_ERROR_TRACKING_URI , "The URI is tracking")
XPC_MSG_DEF(NS_ERROR_UNWANTED_URI , "The URI is unwanted")
XPC_MSG_DEF(NS_ERROR_BLOCKED_URI , "The URI is blocked")
XPC_MSG_DEF(NS_ERROR_HARMFUL_URI , "The URI is harmful")
XPC_MSG_DEF(NS_ERROR_HARMFUL_URI , "The URI is harmful")

View File

@ -370,7 +370,7 @@ TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder,
// has overflow on that side.
}
/* static */ UniquePtr<TextOverflow>
/* static */ Maybe<TextOverflow>
TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder,
nsIFrame* aBlockFrame)
{
@ -378,14 +378,14 @@ TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder,
if (aBuilder->IsForEventDelivery() ||
aBuilder->IsForFrameVisibility() ||
!CanHaveTextOverflow(aBlockFrame)) {
return nullptr;
return Nothing();
}
nsIScrollableFrame* scrollableFrame = nsLayoutUtils::GetScrollableFrameFor(aBlockFrame);
if (scrollableFrame && scrollableFrame->IsTransformingByAPZ()) {
// If the APZ is actively scrolling this, don't bother with markers.
return nullptr;
return Nothing();
}
return MakeUnique<TextOverflow>(aBuilder, aBlockFrame);
return Some(TextOverflow(aBuilder, aBlockFrame));
}
void

View File

@ -27,13 +27,13 @@ namespace css {
* 1. allocate an object using WillProcessLines
* 2. then call ProcessLine for each line you are building display lists for
*/
class MOZ_HEAP_CLASS TextOverflow final {
class TextOverflow final {
public:
/**
* Allocate an object for text-overflow processing.
* @return nullptr if no processing is necessary. The caller owns the object.
*/
static UniquePtr<TextOverflow>
static Maybe<TextOverflow>
WillProcessLines(nsDisplayListBuilder* aBuilder,
nsIFrame* aBlockFrame);
@ -45,6 +45,13 @@ class MOZ_HEAP_CLASS TextOverflow final {
TextOverflow(nsDisplayListBuilder* aBuilder,
nsIFrame* aBlockFrame);
TextOverflow() = default;
~TextOverflow() = default;
TextOverflow(TextOverflow&&) = default;
TextOverflow(const TextOverflow&) = delete;
TextOverflow& operator=(TextOverflow&&) = default;
TextOverflow& operator=(const TextOverflow&) = delete;
/**
* Analyze the display lists for text overflow and what kind of item is at
* the content edges. Add display items for text-overflow markers as needed

View File

@ -6812,8 +6812,7 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aBuilder->MarkFramesForDisplayList(this, mFloats);
// Prepare for text-overflow processing.
UniquePtr<TextOverflow> textOverflow =
TextOverflow::WillProcessLines(aBuilder, this);
Maybe<TextOverflow> textOverflow = TextOverflow::WillProcessLines(aBuilder, this);
// We'll collect our lines' display items here, & then append this to aLists.
nsDisplayListCollection linesDisplayListCollection(aBuilder);
@ -6828,7 +6827,7 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// Also skip the cursor if we're creating text overflow markers,
// since we need to know what line number we're up to in order
// to generate unique display item keys.
nsLineBox* cursor = (aBuilder->ShouldDescendIntoFrame(this, true) || textOverflow) ?
nsLineBox* cursor = (aBuilder->ShouldDescendIntoFrame(this, true) || textOverflow.isSome()) ?
nullptr : GetFirstLineContaining(aBuilder->GetDirtyRect().y);
LineIterator line_end = LinesEnd();
@ -6843,7 +6842,7 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (lineArea.y >= aBuilder->GetDirtyRect().YMost()) {
break;
}
MOZ_ASSERT(!textOverflow);
MOZ_ASSERT(textOverflow.isNothing());
DisplayLine(aBuilder, lineArea, line, depth, drawnLines,
linesDisplayListCollection, this, nullptr, 0);
}
@ -6858,7 +6857,7 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
++line) {
nsRect lineArea = line->GetVisualOverflowArea();
DisplayLine(aBuilder, lineArea, line, depth, drawnLines,
linesDisplayListCollection, this, textOverflow.get(), lineCount);
linesDisplayListCollection, this, textOverflow.ptrOr(nullptr), lineCount);
if (!lineArea.IsEmpty()) {
if (lineArea.y < lastY
|| lineArea.YMost() < lastYMost) {
@ -6879,7 +6878,7 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// PositionedDescendants just before we append the lines' display items,
// so that our text-overflow markers will appear on top of this block's
// normal content but below any of its its' positioned children.
if (textOverflow) {
if (textOverflow.isSome()) {
aLists.PositionedDescendants()->AppendToTop(&textOverflow->GetMarkers());
}
linesDisplayListCollection.MoveTo(aLists);

View File

@ -159,8 +159,7 @@ public:
/**
* Return the containing block for aChild which MUST be an abs.pos. child
* of a grid container. This is just a helper method for
* nsAbsoluteContainingBlock::Reflow - it's not meant to be used elsewhere.
* of a grid container and that container must have been reflowed.
*/
static const nsRect& GridItemCB(nsIFrame* aChild);

View File

@ -3254,6 +3254,40 @@ public:
}
}
nsDisplayList(nsDisplayList&& aOther)
{
mIsOpaque = aOther.mIsOpaque;
mForceTransparentSurface = aOther.mForceTransparentSurface;
if (aOther.mSentinel.mAbove) {
AppendToTop(&aOther);
} else {
mTop = &mSentinel;
mLength = 0;
}
}
nsDisplayList& operator=(nsDisplayList&& aOther)
{
if (this != &aOther) {
if (aOther.mSentinel.mAbove) {
nsDisplayList tmp;
tmp.AppendToTop(&aOther);
aOther.AppendToTop(this);
AppendToTop(&tmp);
} else {
mTop = &mSentinel;
mLength = 0;
}
mIsOpaque = aOther.mIsOpaque;
mForceTransparentSurface = aOther.mForceTransparentSurface;
}
return *this;
}
nsDisplayList(const nsDisplayList&) = delete;
nsDisplayList& operator=(const nsDisplayList& aOther) = delete;
/**
* Append an item to the top of the list. The item must not currently
* be in a list and cannot be null.

View File

@ -867,7 +867,7 @@ fuzzy-if(skiaContent,0-2,0-5) == 402629-3.html 402629-3-ref.html
== 403129-3.html 403129-3-ref.html
== 403129-4.html 403129-4-ref.html
random == 403134-1.html 403134-1-ref.html # bug 405377
fuzzy-if(webrender,130-131,177-177) == 403181-1.xml 403181-1-ref.xml
fuzzy-if(webrender,130-131,177-177) skip-if(winWidget&&!isDebugBuild&&webrender) == 403181-1.xml 403181-1-ref.xml
== 403249-1a.html 403249-1-ref.html
== 403249-1b.html 403249-1-ref.html
== 403249-2a.html 403249-2-ref.html

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
body > div:nth-child(1) > .progress-bar { margin: 10px; padding: 0px; }
body > div:nth-child(2) > .progress-bar { margin: 0px; padding: 10px; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
body > div:nth-child(1) > .progress-bar { margin: 0px 10px 0px 0px; padding: 0px; }
body > div:nth-child(2) > .progress-bar { margin: 0px 0px 0px 10px; padding: 0px; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
.progress-element { margin: 10px; }
body > div:nth-child(1) > .progress-bar { position: relative; top: 4px; left: 4px;

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
.progress-element { margin: 10px; }
body > div:nth-child(1) > .progress-bar { position: relative; top: 4px; left: 4px;

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
progress { display: block; }
</style>

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
progress { width: 10em; height: 1em; }
progress.vertical { -moz-orient: vertical; width: 1em; height: 10em; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
div.progress-element {
height: 12em;

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
div.progress-bar {
width:100%;

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
body > div:nth-child(1) { margin: 10px; padding: 0px; }
body > div:nth-child(2) { margin: 0px; padding: 10px; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
body > div:nth-child(1) { margin: 10px; padding: 0px; }
body > div:nth-child(2) { margin: 0px; padding: 10px; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
body > div:nth-child(1) { margin: 10px; padding: 0px; }
body > div:nth-child(2) { margin: 0px; padding: 10px; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
body > div:nth-child(1) { margin: 10px; padding: 0px; }
body > div:nth-child(2) { margin: 0px; padding: 10px; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
body > div:nth-child(1) { -moz-transform: matrix(1, -0.2, 0, 1, 0, 0); }
body > div:nth-child(2) { -moz-transform: translateX(15em) matrix(1, 0, 0.6, 1, 0, 0); }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
div:nth-child(1) > .progress-bar { width: 100%; }
div:nth-child(2) > .progress-bar { width: 0%; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
div:nth-child(1) > .progress-bar { width: 100%; }
div:nth-child(2) > .progress-bar { width: 0%; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
div:nth-child(1) > .progress-bar { position: relative; top: 0%; height: 100%; }
div:nth-child(2) > .progress-bar { position: relative; top: 100%; height: 0%; }

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<link rel='stylesheet' href='chrome://reftest/content/progress.css'>
<link rel='stylesheet' href='resource://reftest/progress.css'>
<style>
div:nth-child(1) > .progress-bar { position: relative; top: 0%; height: 100%; }
div:nth-child(2) > .progress-bar { position: relative; top: 100%; height: 0%; }

View File

@ -6,7 +6,7 @@
<link rel="author" title="Kyle Zentner" href="mailto:zentner.kyle@gmail.com">
<link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
<link rel="help" href="http://www.w3.org/TR/css-containment-1/#containment-layout">
<link rel="match" href="contain-paint-formatting-context-margin-001-ref.html">
<link rel="match" href="contain-layout-formatting-context-margin-001-ref.html">
<style>
#a {
contain:layout;

View File

@ -4162,6 +4162,10 @@ nsComputedDOMStyle::GetAbsoluteOffset(mozilla::Side aSide)
if (scrollFrame) {
scrollbarSizes = scrollFrame->GetActualScrollbarSizes();
}
} else if (container->IsGridContainerFrame() &&
(mOuterFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) {
containerRect = nsGridContainerFrame::GridItemCB(mOuterFrame);
rect.MoveBy(-containerRect.x, -containerRect.y);
}
nscoord offset = 0;

114
layout/tools/reftest/api.js Normal file
View File

@ -0,0 +1,114 @@
/* 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/. */
const Cm = Components.manager;
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsISubstitutingProtocolHandler");
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
"@mozilla.org/addons/addon-manager-startup;1",
"amIAddonManagerStartup");
function processTerminated() {
return new Promise(resolve => {
Services.obs.addObserver(function observe(subject, topic) {
if (topic == "ipc:content-shutdown") {
Services.obs.removeObserver(observe, topic);
resolve();
}
}, "ipc:content-shutdown");
});
}
function startAndroid(win) {
// Add setTimeout here because windows.innerWidth/Height are not set yet.
win.setTimeout(function() {OnRefTestLoad(win);}, 0);
}
var WindowListener = {
onOpenWindow: function(xulWin) {
Services.wm.removeListener(WindowListener);
let win = xulWin.docShell.domWindow;
win.addEventListener("load", function listener() {
// Load into any existing windows.
for (win of Services.wm.getEnumerator("navigator:browser")) {
break;
}
win.addEventListener("pageshow", function() {
startAndroid(win);
}, {once: true});
}, {once: true});
}
};
this.reftest = class extends ExtensionAPI {
onStartup() {
let uri = Services.io.newURI("chrome/reftest/res/", null, this.extension.rootURI);
resProto.setSubstitutionWithFlags("reftest", uri, resProto.ALLOW_CONTENT_ACCESS);
const manifestURI = Services.io.newURI("manifest.json", null, this.extension.rootURI);
this.chromeHandle = aomStartup.registerChrome(manifestURI, [
["content", "reftest", "chrome/reftest/content/", "contentaccessible=yes"],
]);
// Starting tests is handled quite differently on android and desktop.
// On Android, OnRefTestLoad() takes over the main browser window so
// we just need to call it as soon as the browser window is available.
// On desktop, a separate window (dummy) is created and explicitly given
// focus (see bug 859339 for details), then tests are launched in a new
// top-level window.
let win = Services.wm.getMostRecentWindow("navigator:browser");
if (Services.appinfo.OS == "Android") {
ChromeUtils.import("resource://reftest/reftest.jsm");
if (win) {
startAndroid(win);
} else {
Services.wm.addListener(WindowListener);
}
return;
}
Services.io.manageOfflineStatus = false;
Services.io.offline = false;
let dummy = Services.ww.openWindow(null, "about:blank", "dummy",
"chrome,dialog=no,left=800,height=200,width=200,all",null);
dummy.onload = async function() {
// Close pre-existing window
win.close();
ChromeUtils.import("resource://reftest/PerTestCoverageUtils.jsm");
if (PerTestCoverageUtils.enabled) {
// In PerTestCoverage mode, wait for the process belonging to the window we just closed
// to be terminated, to avoid its shutdown interfering when we reset the counters.
await processTerminated();
}
dummy.focus();
Services.ww.openWindow(null, "chrome://reftest/content/reftest.xul",
"_blank", "chrome,dialog=no,all", {});
};
}
onShutdown() {
resProto.setSubstitution("reftest", null);
this.chromeHandle.destruct();
this.chromeHandle = null;
if (Services.appinfo.OS == "Android") {
Services.wm.removeListener(WindowListener);
OnRefTestUnload();
Cu.unload("resource://reftest/reftest.jsm");
}
}
};

View File

@ -1,86 +0,0 @@
/* 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/. */
const Cm = Components.manager;
ChromeUtils.import("resource://gre/modules/Services.jsm");
function processTerminated() {
return new Promise(resolve => {
Services.obs.addObserver(function observe(subject, topic) {
if (topic == "ipc:content-shutdown") {
Services.obs.removeObserver(observe, topic);
resolve();
}
}, "ipc:content-shutdown");
});
}
var WindowListener = {
onOpenWindow: function(xulWin) {
Services.wm.removeListener(WindowListener);
let win = xulWin.docShell.domWindow;
win.addEventListener("load", function listener() {
// Load into any existing windows.
for (win of Services.wm.getEnumerator("navigator:browser")) {
break;
}
ChromeUtils.import("chrome://reftest/content/reftest.jsm");
win.addEventListener("pageshow", function() {
// Add setTimeout here because windows.innerWidth/Height are not set yet.
win.setTimeout(function() {OnRefTestLoad(win);}, 0);
}, {once: true});
}, {once: true});
}
};
function startup(data, reason) {
if (Services.appinfo.OS == "Android") {
Cm.addBootstrappedManifestLocation(data.installPath);
Services.wm.addListener(WindowListener);
return;
}
let orig = Services.wm.getMostRecentWindow("navigator:browser");
let ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
ios.manageOfflineStatus = false;
ios.offline = false;
let wwatch = Cc["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Ci.nsIWindowWatcher);
let dummy = wwatch.openWindow(null, "about:blank", "dummy",
"chrome,dialog=no,left=800,height=200,width=200,all",null);
dummy.onload = async function() {
// Close pre-existing window
orig.close();
ChromeUtils.import("chrome://reftest/content/PerTestCoverageUtils.jsm");
if (PerTestCoverageUtils.enabled) {
// In PerTestCoverage mode, wait for the process belonging to the window we just closed
// to be terminated, to avoid its shutdown interfering when we reset the counters.
await processTerminated();
}
dummy.focus();
wwatch.openWindow(null, "chrome://reftest/content/reftest.xul", "_blank",
"chrome,dialog=no,all", {});
};
}
function shutdown(data, reason) {
if (Services.appinfo.OS == "Android") {
Services.wm.removeListener(WindowListener);
Cm.removedBootstrappedManifestLocation(data.installPath);
OnRefTestUnload();
Cu.unload("chrome://reftest/content/reftest.jsm");
}
}
function install(data, reason) {}
function uninstall(data, reason) {}

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