mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Merge m-i to m-c, a=merge
This commit is contained in:
commit
0cccf0ed58
@ -1494,34 +1494,34 @@ HyperTextAccessible::CaretLineNumber()
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
LayoutDeviceIntRect
|
||||
HyperTextAccessible::GetCaretRect(nsIWidget** aWidget)
|
||||
{
|
||||
*aWidget = nullptr;
|
||||
|
||||
RefPtr<nsCaret> caret = mDoc->PresShell()->GetCaret();
|
||||
NS_ENSURE_TRUE(caret, nsIntRect());
|
||||
NS_ENSURE_TRUE(caret, LayoutDeviceIntRect());
|
||||
|
||||
bool isVisible = caret->IsVisible();
|
||||
if (!isVisible)
|
||||
return nsIntRect();
|
||||
return LayoutDeviceIntRect();
|
||||
|
||||
nsRect rect;
|
||||
nsIFrame* frame = caret->GetGeometry(&rect);
|
||||
if (!frame || rect.IsEmpty())
|
||||
return nsIntRect();
|
||||
return LayoutDeviceIntRect();
|
||||
|
||||
nsPoint offset;
|
||||
// Offset from widget origin to the frame origin, which includes chrome
|
||||
// on the widget.
|
||||
*aWidget = frame->GetNearestWidget(offset);
|
||||
NS_ENSURE_TRUE(*aWidget, nsIntRect());
|
||||
NS_ENSURE_TRUE(*aWidget, LayoutDeviceIntRect());
|
||||
rect.MoveBy(offset);
|
||||
|
||||
nsIntRect caretRect;
|
||||
caretRect = rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel());
|
||||
LayoutDeviceIntRect caretRect = LayoutDeviceIntRect::FromUnknownRect(
|
||||
rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel()));
|
||||
// ((content screen origin) - (content offset in the widget)) = widget origin on the screen
|
||||
caretRect.MoveBy((*aWidget)->WidgetToScreenOffsetUntyped() - (*aWidget)->GetClientOffset());
|
||||
caretRect.MoveBy((*aWidget)->WidgetToScreenOffset() - (*aWidget)->GetClientOffset());
|
||||
|
||||
// Correct for character size, so that caret always matches the size of
|
||||
// the character. This is important for font size transitions, and is
|
||||
|
@ -335,7 +335,7 @@ public:
|
||||
* @param [out] the widget containing the caret
|
||||
* @return the caret rect
|
||||
*/
|
||||
nsIntRect GetCaretRect(nsIWidget** aWidget);
|
||||
mozilla::LayoutDeviceIntRect GetCaretRect(nsIWidget** aWidget);
|
||||
|
||||
/**
|
||||
* Return selected regions count within the accessible.
|
||||
|
@ -1633,7 +1633,7 @@ AccessibleWrap::UpdateSystemCaretFor(Accessible* aAccessible)
|
||||
return;
|
||||
|
||||
nsIWidget* widget = nullptr;
|
||||
nsIntRect caretRect = text->GetCaretRect(&widget);
|
||||
LayoutDeviceIntRect caretRect = text->GetCaretRect(&widget);
|
||||
HWND caretWnd;
|
||||
if (caretRect.IsEmpty() || !(caretWnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW))) {
|
||||
return;
|
||||
|
84
browser/components/newtab/NewTabPrefsProvider.jsm
Normal file
84
browser/components/newtab/NewTabPrefsProvider.jsm
Normal file
@ -0,0 +1,84 @@
|
||||
/* global Services, Preferences, EventEmitter, XPCOMUtils */
|
||||
/* exported NewTabPrefsProvider */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["NewTabPrefsProvider"];
|
||||
|
||||
const {interfaces: Ci, utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
|
||||
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
|
||||
return EventEmitter;
|
||||
});
|
||||
|
||||
// Supported prefs and data type
|
||||
const gPrefsMap = new Map([
|
||||
["browser.newtabpage.enabled", "bool"],
|
||||
["browser.newtabpage.enhanced", "bool"],
|
||||
["browser.newtabpage.pinned", "str"],
|
||||
["intl.locale.matchOS", "bool"],
|
||||
["general.useragent.locale", "localized"],
|
||||
]);
|
||||
|
||||
let PrefsProvider = function PrefsProvider() {
|
||||
EventEmitter.decorate(this);
|
||||
};
|
||||
|
||||
PrefsProvider.prototype = {
|
||||
|
||||
observe(subject, topic, data) { // jshint ignore:line
|
||||
if (topic === "nsPref:changed") {
|
||||
if (gPrefsMap.has(data)) {
|
||||
switch (gPrefsMap.get(data)) {
|
||||
case "bool":
|
||||
this.emit(data, Preferences.get(data, false));
|
||||
break;
|
||||
case "str":
|
||||
this.emit(data, Preferences.get(data, ""));
|
||||
break;
|
||||
case "localized":
|
||||
try {
|
||||
this.emit(data, Preferences.get(data, "", Ci.nsIPrefLocalizedString));
|
||||
} catch (e) {
|
||||
this.emit(data, Preferences.get(data, ""));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.emit(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Cu.reportError(new Error("NewTabPrefsProvider observing unknown topic"));
|
||||
}
|
||||
},
|
||||
|
||||
get prefsMap() {
|
||||
return gPrefsMap;
|
||||
},
|
||||
|
||||
init() {
|
||||
for (let pref of gPrefsMap.keys()) {
|
||||
Services.prefs.addObserver(pref, this, false);
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
for (let pref of gPrefsMap.keys()) {
|
||||
Services.prefs.removeObserver(pref, this, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton that serves as the default new tab pref provider for the grid.
|
||||
*/
|
||||
const gPrefs = new PrefsProvider();
|
||||
|
||||
let NewTabPrefsProvider = {
|
||||
prefs: gPrefs,
|
||||
};
|
@ -1,9 +1,8 @@
|
||||
/* 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/. */
|
||||
|
||||
/* globals Services, XPCOMUtils, RemotePages, RemoteNewTabLocation, RemoteNewTabUtils, Task */
|
||||
/* globals BackgroundPageThumbs, PageThumbs, DirectoryLinksProvider */
|
||||
/* globals BackgroundPageThumbs, PageThumbs, DirectoryLinksProvider, PlacesProvider, NewTabPrefsProvider */
|
||||
/* exported RemoteAboutNewTab */
|
||||
|
||||
"use strict";
|
||||
@ -31,6 +30,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
|
||||
"resource:///modules/DirectoryLinksProvider.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabLocation",
|
||||
"resource:///modules/RemoteNewTabLocation.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesProvider",
|
||||
"resource:///modules/PlacesProvider.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
|
||||
let RemoteAboutNewTab = {
|
||||
|
||||
@ -43,6 +46,7 @@ let RemoteAboutNewTab = {
|
||||
this.pageListener = new RemotePages("about:remote-newtab");
|
||||
this.pageListener.addMessageListener("NewTab:InitializeGrid", this.initializeGrid.bind(this));
|
||||
this.pageListener.addMessageListener("NewTab:UpdateGrid", this.updateGrid.bind(this));
|
||||
this.pageListener.addMessageListener("NewTab:Customize", this.customize.bind(this));
|
||||
this.pageListener.addMessageListener("NewTab:CaptureBackgroundPageThumbs",
|
||||
this.captureBackgroundPageThumb.bind(this));
|
||||
this.pageListener.addMessageListener("NewTab:PageThumbs", this.createPageThumb.bind(this));
|
||||
@ -51,6 +55,43 @@ let RemoteAboutNewTab = {
|
||||
this._addObservers();
|
||||
},
|
||||
|
||||
customize: function(message) {
|
||||
if (message.data.enabled !== undefined) {
|
||||
Services.prefs.setBoolPref("browser.newtabpage.enabled", message.data.enabled);
|
||||
}
|
||||
if (message.data.enhanced !== undefined) {
|
||||
Services.prefs.setBoolPref("browser.newtabpage.enhanced", message.data.enhanced);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies when history is cleared
|
||||
*/
|
||||
placesClearHistory: function() {
|
||||
this.pageListener.sendAsyncMessage("NewTab:PlacesClearHistory");
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies when a link has changed
|
||||
*/
|
||||
placesLinkChanged: function(name, data) { // jshint ignore:line
|
||||
this.pageListener.sendAsyncMessage("NewTab:PlacesLinkChanged", data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies when many links have changed
|
||||
*/
|
||||
placesManyLinksChanged: function() {
|
||||
this.pageListener.sendAsyncMessage("NewTab:PlacesManyLinksChanged");
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies when one URL has been deleted
|
||||
*/
|
||||
placesDeleteURI: function(name, data) { // jshint ignore:line
|
||||
this.pageListener.sendAsyncMessage("NewTab:PlacesDeleteURI", data.url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the grid for the first time when the page loads.
|
||||
* Fetch all the links and send them down to the child to populate
|
||||
@ -186,7 +227,6 @@ let RemoteAboutNewTab = {
|
||||
*/
|
||||
observe: function(aSubject, aTopic, aData) { // jshint ignore:line
|
||||
let extraData;
|
||||
let refreshPage = false;
|
||||
if (aTopic === "browser:purge-session-history") {
|
||||
RemoteNewTabUtils.links.resetCache();
|
||||
RemoteNewTabUtils.links.populateCache(() => {
|
||||
@ -206,12 +246,31 @@ let RemoteAboutNewTab = {
|
||||
}
|
||||
},
|
||||
|
||||
setEnabled: function(name, data) { // jshint ignore:line
|
||||
this.pageListener.sendAsyncMessage("NewTab:setEnabled", data);
|
||||
},
|
||||
|
||||
setEnhanced: function(name, data) { // jshint ignore:line
|
||||
this.pageListener.sendAsyncMessage("NewTab:setEnhanced", data);
|
||||
},
|
||||
|
||||
setPinned: function(name, data) { // jshint ignore:line
|
||||
this.pageListener.sendAsyncMessage("NewTab:setPinnedLinks", data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add all observers that about:newtab page must listen for.
|
||||
*/
|
||||
_addObservers: function() {
|
||||
Services.obs.addObserver(this, "page-thumbnail:create", true);
|
||||
Services.obs.addObserver(this, "browser:purge-session-history", true);
|
||||
PlacesProvider.links.on("deleteURI", this.placesDeleteURI.bind(this));
|
||||
PlacesProvider.links.on("clearHistory", this.placesClearHistory.bind(this));
|
||||
PlacesProvider.links.on("linkChanged", this.placesLinkChanged.bind(this));
|
||||
PlacesProvider.links.on("manyLinksChanged", this.placesManyLinksChanged.bind(this));
|
||||
NewTabPrefsProvider.prefs.on("browser.newtabpage.enabled", this.setEnabled.bind(this));
|
||||
NewTabPrefsProvider.prefs.on("browser.newtabpage.enhanced", this.setEnhanced.bind(this));
|
||||
NewTabPrefsProvider.prefs.on("browser.newtabpage.pinned", this.setPinned.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -220,6 +279,13 @@ let RemoteAboutNewTab = {
|
||||
_removeObservers: function() {
|
||||
Services.obs.removeObserver(this, "page-thumbnail:create");
|
||||
Services.obs.removeObserver(this, "browser:purge-session-history");
|
||||
PlacesProvider.links.off("deleteURI", this.placesDeleteURI);
|
||||
PlacesProvider.links.off("clearHistory", this.placesClearHistory);
|
||||
PlacesProvider.links.off("linkChanged", this.placesLinkChanged);
|
||||
PlacesProvider.links.off("manyLinksChanged", this.placesManyLinksChanged);
|
||||
NewTabPrefsProvider.prefs.off("browser.newtabpage.enabled", this.setEnabled.bind(this));
|
||||
NewTabPrefsProvider.prefs.off("browser.newtabpage.enhanced", this.setEnhanced.bind(this));
|
||||
NewTabPrefsProvider.prefs.off("browser.newtabpage.pinned", this.setPinned.bind(this));
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
|
@ -11,6 +11,7 @@ XPCSHELL_TESTS_MANIFESTS += [
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'NewTabPrefsProvider.jsm',
|
||||
'NewTabURL.jsm',
|
||||
'PlacesProvider.jsm',
|
||||
'RemoteAboutNewTab.jsm',
|
||||
|
@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
/* global XPCOMUtils, equal, Preferences, NewTabPrefsProvider, run_next_test */
|
||||
/* exported run_test */
|
||||
/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_observe() {
|
||||
let prefsMap = NewTabPrefsProvider.prefs.prefsMap;
|
||||
for (let prefName of prefsMap.keys()) {
|
||||
let prefValueType = prefsMap.get(prefName);
|
||||
|
||||
let beforeVal;
|
||||
let afterVal;
|
||||
|
||||
switch (prefValueType) {
|
||||
case "bool":
|
||||
beforeVal = false;
|
||||
afterVal = true;
|
||||
Preferences.set(prefName, beforeVal);
|
||||
break;
|
||||
case "localized":
|
||||
case "str":
|
||||
beforeVal = "";
|
||||
afterVal = "someStr";
|
||||
Preferences.set(prefName, beforeVal);
|
||||
break;
|
||||
}
|
||||
NewTabPrefsProvider.prefs.init();
|
||||
let promise = new Promise(resolve => {
|
||||
NewTabPrefsProvider.prefs.once(prefName, (name, data) => { // jshint ignore:line
|
||||
resolve([name, data]);
|
||||
});
|
||||
});
|
||||
Preferences.set(prefName, afterVal);
|
||||
let [actualName, actualData] = yield promise;
|
||||
equal(prefName, actualName, `emitter sent the correct pref: ${prefName}`);
|
||||
equal(afterVal, actualData, `emitter collected correct pref data for ${prefName}`);
|
||||
NewTabPrefsProvider.prefs.uninit();
|
||||
}
|
||||
});
|
@ -5,6 +5,7 @@ firefox-appdir = browser
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||
|
||||
[test_AboutNewTabService.js]
|
||||
[test_NewTabPrefsProvider.js]
|
||||
[test_NewTabURL.js]
|
||||
[test_PlacesProvider.js]
|
||||
[test_RemoteNewTabLocation.js]
|
||||
|
@ -32,6 +32,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "RemoteAboutNewTab",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabUtils",
|
||||
"resource:///modules/RemoteNewTabUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||
"resource:///modules/UITour.jsm");
|
||||
|
||||
@ -849,6 +852,7 @@ BrowserGlue.prototype = {
|
||||
RemoteNewTabUtils.init();
|
||||
RemoteNewTabUtils.links.addProvider(DirectoryLinksProvider);
|
||||
RemoteAboutNewTab.init();
|
||||
NewTabPrefsProvider.prefs.init();
|
||||
|
||||
SessionStore.init();
|
||||
BrowserUITelemetry.init();
|
||||
@ -1170,6 +1174,7 @@ BrowserGlue.prototype = {
|
||||
WebappManager.uninit();
|
||||
|
||||
RemoteAboutNewTab.uninit();
|
||||
NewTabPrefsProvider.prefs.uninit();
|
||||
AboutNewTab.uninit();
|
||||
#ifdef NIGHTLY_BUILD
|
||||
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
|
||||
|
@ -1,12 +1,10 @@
|
||||
[DEFAULT]
|
||||
support-files = file_pdfjs_test.pdf
|
||||
support-files =
|
||||
file_pdfjs_test.pdf
|
||||
head.js
|
||||
|
||||
[browser_pdfjs_main.js]
|
||||
skip-if = e10s # Bug 1159385
|
||||
[browser_pdfjs_navigation.js]
|
||||
skip-if = e10s # Bug 1159385
|
||||
[browser_pdfjs_savedialog.js]
|
||||
[browser_pdfjs_views.js]
|
||||
skip-if = e10s # Bug 1159385
|
||||
[browser_pdfjs_zoom.js]
|
||||
skip-if = e10s # Bug 1159385
|
||||
|
@ -4,9 +4,7 @@
|
||||
const RELATIVE_DIR = "browser/extensions/pdfjs/test/";
|
||||
const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
|
||||
|
||||
function test() {
|
||||
var tab;
|
||||
|
||||
add_task(function* test() {
|
||||
let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
|
||||
let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
|
||||
let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf');
|
||||
@ -17,82 +15,53 @@ function test() {
|
||||
|
||||
info('Pref action: ' + handlerInfo.preferredAction);
|
||||
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser: gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" },
|
||||
function* (newTabBrowser) {
|
||||
ok(gBrowser.isFindBarInitialized(), "Browser FindBar initialized!");
|
||||
|
||||
tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf");
|
||||
var newTabBrowser = gBrowser.getBrowserForTab(tab);
|
||||
newTabBrowser.addEventListener("load", function eventHandler() {
|
||||
newTabBrowser.removeEventListener("load", eventHandler, true);
|
||||
yield waitForPdfJS(newTabBrowser);
|
||||
|
||||
var document = newTabBrowser.contentDocument,
|
||||
window = newTabBrowser.contentWindow;
|
||||
yield ContentTask.spawn(newTabBrowser, null, function* () {
|
||||
//
|
||||
// Overall sanity tests
|
||||
//
|
||||
ok(content.document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in content.wrappedJSObject, "window content has PDFJS object");
|
||||
|
||||
// Runs tests after all 'load' event handlers have fired off
|
||||
window.addEventListener("documentload", function() {
|
||||
runTests(document, window, tab, function () {
|
||||
closePDFViewer(window, finish);
|
||||
//
|
||||
// Sidebar: open
|
||||
//
|
||||
var sidebar = content.document.querySelector('button#sidebarToggle'),
|
||||
outerContainer = content.document.querySelector('div#outerContainer');
|
||||
|
||||
sidebar.click();
|
||||
ok(outerContainer.classList.contains('sidebarOpen'), "sidebar opens on click");
|
||||
|
||||
//
|
||||
// Sidebar: close
|
||||
//
|
||||
sidebar.click();
|
||||
ok(!outerContainer.classList.contains('sidebarOpen'), "sidebar closes on click");
|
||||
|
||||
//
|
||||
// Page change from prev/next buttons
|
||||
//
|
||||
var prevPage = content.document.querySelector('button#previous'),
|
||||
nextPage = content.document.querySelector('button#next');
|
||||
|
||||
var pgNumber = content.document.querySelector('input#pageNumber').value;
|
||||
is(parseInt(pgNumber, 10), 1, 'initial page is 1');
|
||||
|
||||
//
|
||||
// Bookmark button
|
||||
//
|
||||
var viewBookmark = content.document.querySelector('a#viewBookmark');
|
||||
viewBookmark.click();
|
||||
|
||||
ok(viewBookmark.href.length > 0, "viewBookmark button has href");
|
||||
|
||||
var viewer = content.wrappedJSObject.PDFViewerApplication;
|
||||
yield viewer.close();
|
||||
});
|
||||
}, false, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
||||
function runTests(document, window, tab, callback) {
|
||||
|
||||
//
|
||||
// Overall sanity tests
|
||||
//
|
||||
ok(document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object");
|
||||
ok('PDFViewerApplication' in window.wrappedJSObject,
|
||||
"window content has viewer object");
|
||||
|
||||
//
|
||||
// Browser Find
|
||||
//
|
||||
ok(gBrowser.isFindBarInitialized(tab), "Browser FindBar initialized!");
|
||||
|
||||
//
|
||||
// Sidebar: open
|
||||
//
|
||||
var sidebar = document.querySelector('button#sidebarToggle'),
|
||||
outerContainer = document.querySelector('div#outerContainer');
|
||||
|
||||
sidebar.click();
|
||||
ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click');
|
||||
|
||||
//
|
||||
// Sidebar: close
|
||||
//
|
||||
sidebar.click();
|
||||
ok(!outerContainer.classList.contains('sidebarOpen'), 'sidebar closes on click');
|
||||
|
||||
//
|
||||
// Page change from prev/next buttons
|
||||
//
|
||||
var prevPage = document.querySelector('button#previous'),
|
||||
nextPage = document.querySelector('button#next');
|
||||
|
||||
var pageNumber = document.querySelector('input#pageNumber');
|
||||
is(parseInt(pageNumber.value), 1, 'initial page is 1');
|
||||
|
||||
//
|
||||
// Bookmark button
|
||||
//
|
||||
var viewBookmark = document.querySelector('a#viewBookmark');
|
||||
viewBookmark.click();
|
||||
ok(viewBookmark.href.length > 0, 'viewBookmark button has href');
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys PDF.js viewer opened document.
|
||||
*/
|
||||
function closePDFViewer(window, callback) {
|
||||
var viewer = window.wrappedJSObject.PDFViewerApplication;
|
||||
viewer.close().then(callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -139,9 +139,7 @@ const TESTS = [
|
||||
}
|
||||
];
|
||||
|
||||
function test() {
|
||||
var tab;
|
||||
|
||||
add_task(function* test() {
|
||||
let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
|
||||
let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf');
|
||||
|
||||
@ -151,51 +149,73 @@ function test() {
|
||||
|
||||
info('Pref action: ' + handlerInfo.preferredAction);
|
||||
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" },
|
||||
function* (newTabBrowser) {
|
||||
yield waitForPdfJS(newTabBrowser);
|
||||
|
||||
tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf");
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
var newTabBrowser = gBrowser.getBrowserForTab(tab);
|
||||
newTabBrowser.addEventListener("load", function eventHandler() {
|
||||
newTabBrowser.removeEventListener("load", eventHandler, true);
|
||||
|
||||
var document = newTabBrowser.contentDocument,
|
||||
window = newTabBrowser.contentWindow;
|
||||
|
||||
// Runs tests after all 'load' event handlers have fired off
|
||||
window.addEventListener("documentload", function() {
|
||||
runTests(document, window, function () {
|
||||
var pageNumber = document.querySelector('input#pageNumber');
|
||||
is(pageNumber.value, pageNumber.max, "Document is left on the last page");
|
||||
finish();
|
||||
yield ContentTask.spawn(newTabBrowser, null, function* () {
|
||||
// Check if PDF is opened with internal viewer
|
||||
ok(content.document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in content.wrappedJSObject, "window content has PDFJS object");
|
||||
});
|
||||
}, false, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function runTests(document, window, finish) {
|
||||
// Check if PDF is opened with internal viewer
|
||||
ok(document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object");
|
||||
yield ContentTask.spawn(newTabBrowser, null, contentSetUp);
|
||||
|
||||
// Wait for outline items, the start the navigation actions
|
||||
waitForOutlineItems(document).then(function () {
|
||||
// The key navigation has to happen in page-fit, otherwise it won't scroll
|
||||
// trough a complete page
|
||||
setZoomToPageFit(document).then(function () {
|
||||
runNextTest(document, window, finish);
|
||||
}, function () {
|
||||
ok(false, "Current scale has been set to 'page-fit'");
|
||||
finish();
|
||||
yield Task.spawn(runTests(newTabBrowser));
|
||||
|
||||
yield ContentTask.spawn(newTabBrowser, null, function*() {
|
||||
let pageNumber = content.document.querySelector('input#pageNumber');
|
||||
is(pageNumber.value, pageNumber.max, "Document is left on the last page");
|
||||
});
|
||||
});
|
||||
}, function () {
|
||||
ok(false, "Outline items have been found");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
|
||||
function* contentSetUp() {
|
||||
/**
|
||||
* Outline Items gets appended to the document later on we have to
|
||||
* wait for them before we start to navigate though document
|
||||
*
|
||||
* @param document
|
||||
* @returns {deferred.promise|*}
|
||||
*/
|
||||
function waitForOutlineItems(document) {
|
||||
return new Promise((resolve, reject) => {
|
||||
document.addEventListener("outlineloaded", function outlineLoaded(evt) {
|
||||
document.removeEventListener("outlineloaded", outlineLoaded);
|
||||
var outlineCount = evt.detail.outlineCount;
|
||||
|
||||
if (document.querySelectorAll(".outlineItem").length === outlineCount) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The key navigation has to happen in page-fit, otherwise it won't scroll
|
||||
* through a complete page
|
||||
*
|
||||
* @param document
|
||||
* @returns {deferred.promise|*}
|
||||
*/
|
||||
function setZoomToPageFit(document) {
|
||||
return new Promise((resolve) => {
|
||||
document.addEventListener("pagerendered", function onZoom(e) {
|
||||
document.removeEventListener("pagerendered", onZoom);
|
||||
document.querySelector("#viewer").click();
|
||||
resolve();
|
||||
});
|
||||
|
||||
var select = document.querySelector("select#scaleSelect");
|
||||
select.selectedIndex = 2;
|
||||
select.dispatchEvent(new Event("change"));
|
||||
});
|
||||
}
|
||||
|
||||
yield waitForOutlineItems(content.document);
|
||||
yield setZoomToPageFit(content.document);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,99 +227,55 @@ function runTests(document, window, finish) {
|
||||
* @param test
|
||||
* @param callback
|
||||
*/
|
||||
function runNextTest(document, window, endCallback) {
|
||||
var test = TESTS.shift(),
|
||||
deferred = Promise.defer(),
|
||||
pageNumber = document.querySelector('input#pageNumber');
|
||||
function* runTests(browser) {
|
||||
yield ContentTask.spawn(browser, TESTS, function* (TESTS) {
|
||||
let window = content;
|
||||
let document = window.document;
|
||||
|
||||
// Add an event-listener to wait for page to change, afterwards resolve the promise
|
||||
var timeout = window.setTimeout(() => deferred.reject(), 5000);
|
||||
window.addEventListener('pagechange', function pageChange() {
|
||||
if (pageNumber.value == test.expectedPage) {
|
||||
window.removeEventListener('pagechange', pageChange);
|
||||
window.clearTimeout(timeout);
|
||||
deferred.resolve(pageNumber.value);
|
||||
for (let test of TESTS) {
|
||||
let deferred = {};
|
||||
deferred.promise = new Promise((resolve, reject) => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
let pageNumber = document.querySelector('input#pageNumber');
|
||||
|
||||
// Add an event-listener to wait for page to change, afterwards resolve the promise
|
||||
let timeout = window.setTimeout(() => deferred.reject(), 5000);
|
||||
window.addEventListener('pagechange', function pageChange() {
|
||||
if (pageNumber.value == test.expectedPage) {
|
||||
window.removeEventListener('pagechange', pageChange);
|
||||
window.clearTimeout(timeout);
|
||||
deferred.resolve(+pageNumber.value);
|
||||
}
|
||||
});
|
||||
|
||||
// Get the element and trigger the action for changing the page
|
||||
var el = document.querySelector(test.action.selector);
|
||||
ok(el, "Element '" + test.action.selector + "' has been found");
|
||||
|
||||
// The value option is for input case
|
||||
if (test.action.value)
|
||||
el.value = test.action.value;
|
||||
|
||||
// Dispatch the event for changing the page
|
||||
if (test.action.event == "keydown") {
|
||||
var ev = document.createEvent("KeyboardEvent");
|
||||
ev.initKeyEvent("keydown", true, true, null, false, false, false, false,
|
||||
test.action.keyCode, 0);
|
||||
el.dispatchEvent(ev);
|
||||
}
|
||||
else {
|
||||
var ev = new Event(test.action.event);
|
||||
}
|
||||
el.dispatchEvent(ev);
|
||||
|
||||
let pgNumber = yield deferred.promise;
|
||||
is(pgNumber, test.expectedPage, test.message);
|
||||
}
|
||||
});
|
||||
|
||||
// Get the element and trigger the action for changing the page
|
||||
var el = document.querySelector(test.action.selector);
|
||||
ok(el, "Element '" + test.action.selector + "' has been found");
|
||||
|
||||
// The value option is for input case
|
||||
if (test.action.value)
|
||||
el.value = test.action.value;
|
||||
|
||||
// Dispatch the event for changing the page
|
||||
if (test.action.event == "keydown") {
|
||||
var ev = document.createEvent("KeyboardEvent");
|
||||
ev.initKeyEvent("keydown", true, true, null, false, false, false, false,
|
||||
test.action.keyCode, 0);
|
||||
el.dispatchEvent(ev);
|
||||
}
|
||||
else {
|
||||
var ev = new Event(test.action.event);
|
||||
}
|
||||
el.dispatchEvent(ev);
|
||||
|
||||
|
||||
// When the promise gets resolved we call the next test if there are any left
|
||||
// or else we call the final callback which will end the test
|
||||
deferred.promise.then(function (pgNumber) {
|
||||
is(pgNumber, test.expectedPage, test.message);
|
||||
|
||||
if (TESTS.length)
|
||||
runNextTest(document, window, endCallback);
|
||||
else
|
||||
endCallback();
|
||||
}, function () {
|
||||
ok(false, "Test '" + test.message + "' failed with timeout.");
|
||||
endCallback();
|
||||
var viewer = content.wrappedJSObject.PDFViewerApplication;
|
||||
yield viewer.close();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Outline Items gets appended to the document latter on we have to
|
||||
* wait for them before we start to navigate though document
|
||||
*
|
||||
* @param document
|
||||
* @returns {deferred.promise|*}
|
||||
*/
|
||||
function waitForOutlineItems(document) {
|
||||
var deferred = Promise.defer();
|
||||
document.addEventListener("outlineloaded", function outlineLoaded(evt) {
|
||||
document.removeEventListener("outlineloaded", outlineLoaded);
|
||||
var outlineCount = evt.detail.outlineCount;
|
||||
|
||||
if (document.querySelectorAll(".outlineItem").length === outlineCount) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* The key navigation has to happen in page-fit, otherwise it won't scroll
|
||||
* trough a complete page
|
||||
*
|
||||
* @param document
|
||||
* @returns {deferred.promise|*}
|
||||
*/
|
||||
function setZoomToPageFit(document) {
|
||||
var deferred = Promise.defer();
|
||||
document.addEventListener("pagerendered", function onZoom(e) {
|
||||
document.removeEventListener("pagerendered", onZoom);
|
||||
document.querySelector("#viewer").click();
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
var select = document.querySelector("select#scaleSelect");
|
||||
select.selectedIndex = 2;
|
||||
select.dispatchEvent(new Event("change"));
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,7 @@
|
||||
const RELATIVE_DIR = "browser/extensions/pdfjs/test/";
|
||||
const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
|
||||
|
||||
function test() {
|
||||
var tab;
|
||||
|
||||
add_task(function* test() {
|
||||
let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
|
||||
let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
|
||||
let handlerInfo = mimeService.getFromTypeAndExtension('application/pdf', 'pdf');
|
||||
@ -17,70 +15,47 @@ function test() {
|
||||
|
||||
info('Pref action: ' + handlerInfo.preferredAction);
|
||||
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" },
|
||||
function* (browser) {
|
||||
// check that PDF is opened with internal viewer
|
||||
yield waitForPdfJS(browser);
|
||||
|
||||
tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf");
|
||||
var newTabBrowser = gBrowser.getBrowserForTab(tab);
|
||||
newTabBrowser.addEventListener("load", function eventHandler() {
|
||||
newTabBrowser.removeEventListener("load", eventHandler, true);
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
ok(content.document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in content.wrappedJSObject, "window content has PDFJS object");
|
||||
|
||||
var document = newTabBrowser.contentDocument,
|
||||
window = newTabBrowser.contentWindow;
|
||||
//open sidebar
|
||||
var sidebar = content.document.querySelector('button#sidebarToggle');
|
||||
var outerContainer = content.document.querySelector('div#outerContainer');
|
||||
|
||||
// Runs tests after all 'load' event handlers have fired off
|
||||
window.addEventListener("documentload", function() {
|
||||
runTests(document, window, function () {
|
||||
closePDFViewer(window, finish);
|
||||
sidebar.click();
|
||||
ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click');
|
||||
|
||||
// check that thumbnail view is open
|
||||
var thumbnailView = content.document.querySelector('div#thumbnailView');
|
||||
var outlineView = content.document.querySelector('div#outlineView');
|
||||
|
||||
is(thumbnailView.getAttribute('class'), null, 'Initial view is thumbnail view');
|
||||
is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden initially');
|
||||
|
||||
//switch to outline view
|
||||
var viewOutlineButton = content.document.querySelector('button#viewOutline');
|
||||
viewOutlineButton.click();
|
||||
|
||||
is(thumbnailView.getAttribute('class'), 'hidden', 'Thumbnail view is hidden when outline is selected');
|
||||
is(outlineView.getAttribute('class'), '', 'Outline view is visible when selected');
|
||||
|
||||
//switch back to thumbnail view
|
||||
var viewThumbnailButton = content.document.querySelector('button#viewThumbnail');
|
||||
viewThumbnailButton.click();
|
||||
|
||||
is(thumbnailView.getAttribute('class'), '', 'Thumbnail view is visible when selected');
|
||||
is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden when thumbnail is selected');
|
||||
|
||||
sidebar.click();
|
||||
|
||||
var viewer = content.wrappedJSObject.PDFViewerApplication;
|
||||
yield viewer.close();
|
||||
});
|
||||
}, false, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function runTests(document, window, callback) {
|
||||
// check that PDF is opened with internal viewer
|
||||
ok(document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object");
|
||||
|
||||
//open sidebar
|
||||
var sidebar = document.querySelector('button#sidebarToggle');
|
||||
var outerContainer = document.querySelector('div#outerContainer');
|
||||
|
||||
sidebar.click();
|
||||
ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click');
|
||||
|
||||
// check that thumbnail view is open
|
||||
var thumbnailView = document.querySelector('div#thumbnailView');
|
||||
var outlineView = document.querySelector('div#outlineView');
|
||||
|
||||
is(thumbnailView.getAttribute('class'), null, 'Initial view is thumbnail view');
|
||||
is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden initially');
|
||||
|
||||
//switch to outline view
|
||||
var viewOutlineButton = document.querySelector('button#viewOutline');
|
||||
viewOutlineButton.click();
|
||||
|
||||
is(outlineView.getAttribute('class'), '', 'Outline view is visible when selected');
|
||||
is(thumbnailView.getAttribute('class'), 'hidden', 'Thumbnail view is hidden when outline is selected');
|
||||
|
||||
//switch back to thumbnail view
|
||||
var viewThumbnailButton = document.querySelector('button#viewThumbnail');
|
||||
viewThumbnailButton.click();
|
||||
|
||||
is(thumbnailView.getAttribute('class'), '', 'Thumbnail view is visible when selected');
|
||||
is(outlineView.getAttribute('class'), 'hidden', 'Outline view is hidden when thumbnail is selected');
|
||||
|
||||
sidebar.click();
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys PDF.js viewer opened document.
|
||||
*/
|
||||
function closePDFViewer(window, callback) {
|
||||
var viewer = window.wrappedJSObject.PDFViewerApplication;
|
||||
viewer.close().then(callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -28,6 +28,7 @@ const TESTS = [
|
||||
{
|
||||
action: {
|
||||
keyboard: true,
|
||||
keyCode: 61,
|
||||
event: "+"
|
||||
},
|
||||
expectedZoom: 1, // 1 - zoom in
|
||||
@ -37,6 +38,7 @@ const TESTS = [
|
||||
{
|
||||
action: {
|
||||
keyboard: true,
|
||||
keyCode: 109,
|
||||
event: "-"
|
||||
},
|
||||
expectedZoom: -1, // -1 - zoom out
|
||||
@ -54,11 +56,7 @@ const TESTS = [
|
||||
}
|
||||
];
|
||||
|
||||
var initialWidth; // the initial width of the PDF document
|
||||
var previousWidth; // the width of the PDF document at previous step/test
|
||||
|
||||
function test() {
|
||||
var tab;
|
||||
add_task(function* test() {
|
||||
let handlerService = Cc["@mozilla.org/uriloader/handler-service;1"]
|
||||
.getService(Ci.nsIHandlerService);
|
||||
let mimeService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
|
||||
@ -72,114 +70,83 @@ function test() {
|
||||
|
||||
info('Pref action: ' + handlerInfo.preferredAction);
|
||||
|
||||
waitForExplicitFinish();
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: TESTROOT + "file_pdfjs_test.pdf" + "#zoom=100" },
|
||||
function* (newTabBrowser) {
|
||||
yield waitForPdfJS(newTabBrowser);
|
||||
|
||||
tab = gBrowser.selectedTab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf");
|
||||
var newTabBrowser = gBrowser.getBrowserForTab(tab);
|
||||
yield ContentTask.spawn(newTabBrowser, TESTS, function* (TESTS) {
|
||||
let document = content.document;
|
||||
|
||||
newTabBrowser.addEventListener("load", function eventHandler() {
|
||||
newTabBrowser.removeEventListener("load", eventHandler, true);
|
||||
function waitForRender() {
|
||||
return new Promise((resolve) => {
|
||||
document.addEventListener("pagerendered", function onPageRendered(e) {
|
||||
if(e.detail.pageNumber !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var document = newTabBrowser.contentDocument,
|
||||
window = newTabBrowser.contentWindow;
|
||||
document.removeEventListener("pagerendered", onPageRendered, true);
|
||||
resolve();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
// Runs tests after all 'load' event handlers have fired off
|
||||
window.addEventListener("documentload", function() {
|
||||
initialWidth = parseInt(document.querySelector("div#pageContainer1").style.width);
|
||||
previousWidth = initialWidth;
|
||||
runTests(document, window, function () {
|
||||
closePDFViewer(window, finish);
|
||||
// check that PDF is opened with internal viewer
|
||||
ok(content.document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in content.wrappedJSObject, "window content has PDFJS object");
|
||||
|
||||
let initialWidth, previousWidth;
|
||||
initialWidth = previousWidth =
|
||||
parseInt(content.document.querySelector("div#pageContainer1").style.width);
|
||||
|
||||
for (let test of TESTS) {
|
||||
// We zoom using an UI element
|
||||
var ev;
|
||||
if (test.action.selector) {
|
||||
// Get the element and trigger the action for changing the zoom
|
||||
var el = document.querySelector(test.action.selector);
|
||||
ok(el, "Element '" + test.action.selector + "' has been found");
|
||||
|
||||
if (test.action.index){
|
||||
el.selectedIndex = test.action.index;
|
||||
}
|
||||
|
||||
// Dispatch the event for changing the zoom
|
||||
ev = new Event(test.action.event);
|
||||
}
|
||||
// We zoom using keyboard
|
||||
else {
|
||||
// Simulate key press
|
||||
ev = new content.KeyboardEvent("keydown",
|
||||
{ key: test.action.event,
|
||||
keyCode: test.action.keyCode,
|
||||
ctrlKey: true });
|
||||
el = content;
|
||||
}
|
||||
|
||||
el.dispatchEvent(ev);
|
||||
yield waitForRender();
|
||||
|
||||
var pageZoomScale = content.document.querySelector('select#scaleSelect');
|
||||
|
||||
// The zoom value displayed in the zoom select
|
||||
var zoomValue = pageZoomScale.options[pageZoomScale.selectedIndex].innerHTML;
|
||||
|
||||
let pageContainer = content.document.querySelector('div#pageContainer1');
|
||||
let actualWidth = parseInt(pageContainer.style.width);
|
||||
|
||||
// the actual zoom of the PDF document
|
||||
let computedZoomValue = parseInt(((actualWidth/initialWidth).toFixed(2))*100) + "%";
|
||||
is(computedZoomValue, zoomValue, "Content has correct zoom");
|
||||
|
||||
// Check that document zooms in the expected way (in/out)
|
||||
let zoom = (actualWidth - previousWidth) * test.expectedZoom;
|
||||
ok(zoom > 0, test.message);
|
||||
|
||||
previousWidth = actualWidth;
|
||||
}
|
||||
|
||||
var viewer = content.wrappedJSObject.PDFViewerApplication;
|
||||
yield viewer.close();
|
||||
});
|
||||
}, false, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function runTests(document, window, callback) {
|
||||
// check that PDF is opened with internal viewer
|
||||
ok(document.querySelector('div#viewer'), "document content has viewer UI");
|
||||
ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object");
|
||||
|
||||
// Start the zooming tests after the document is loaded
|
||||
waitForDocumentLoad(document).then(function () {
|
||||
zoomPDF(document, window, TESTS.shift(), callback);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForDocumentLoad(document) {
|
||||
var deferred = Promise.defer();
|
||||
var interval = setInterval(function () {
|
||||
if (document.querySelector("div#pageContainer1") != null){
|
||||
clearInterval(interval);
|
||||
deferred.resolve();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function zoomPDF(document, window, test, endCallback) {
|
||||
var renderedPage;
|
||||
|
||||
document.addEventListener("pagerendered", function onPageRendered(e) {
|
||||
if(e.detail.pageNumber !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.removeEventListener("pagerendered", onPageRendered, true);
|
||||
|
||||
var pageZoomScale = document.querySelector('select#scaleSelect');
|
||||
|
||||
// The zoom value displayed in the zoom select
|
||||
var zoomValue = pageZoomScale.options[pageZoomScale.selectedIndex].innerHTML;
|
||||
|
||||
let pageContainer = document.querySelector('div#pageContainer1');
|
||||
let actualWidth = parseInt(pageContainer.style.width);
|
||||
|
||||
// the actual zoom of the PDF document
|
||||
let computedZoomValue = parseInt(((actualWidth/initialWidth).toFixed(2))*100) + "%";
|
||||
is(computedZoomValue, zoomValue, "Content has correct zoom");
|
||||
|
||||
// Check that document zooms in the expected way (in/out)
|
||||
let zoom = (actualWidth - previousWidth) * test.expectedZoom;
|
||||
ok(zoom > 0, test.message);
|
||||
|
||||
// Go to next test (if there is any) or finish
|
||||
var nextTest = TESTS.shift();
|
||||
if (nextTest) {
|
||||
previousWidth = actualWidth;
|
||||
zoomPDF(document, window, nextTest, endCallback);
|
||||
}
|
||||
else
|
||||
endCallback();
|
||||
}, true);
|
||||
|
||||
// We zoom using an UI element
|
||||
if (test.action.selector) {
|
||||
// Get the element and trigger the action for changing the zoom
|
||||
var el = document.querySelector(test.action.selector);
|
||||
ok(el, "Element '" + test.action.selector + "' has been found");
|
||||
|
||||
if (test.action.index){
|
||||
el.selectedIndex = test.action.index;
|
||||
}
|
||||
|
||||
// Dispatch the event for changing the zoom
|
||||
el.dispatchEvent(new Event(test.action.event));
|
||||
}
|
||||
// We zoom using keyboard
|
||||
else {
|
||||
// Simulate key press
|
||||
EventUtils.synthesizeKey(test.action.event, { ctrlKey: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys PDF.js viewer opened document.
|
||||
*/
|
||||
function closePDFViewer(window, callback) {
|
||||
var viewer = window.wrappedJSObject.PDFViewerApplication;
|
||||
viewer.close().then(callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
11
browser/extensions/pdfjs/test/head.js
Normal file
11
browser/extensions/pdfjs/test/head.js
Normal file
@ -0,0 +1,11 @@
|
||||
function waitForPdfJS(browser) {
|
||||
// Runs tests after all 'load' event handlers have fired off
|
||||
return ContentTask.spawn(browser, null, function* () {
|
||||
yield new Promise((resolve) => {
|
||||
content.addEventListener("documentload", function listener() {
|
||||
content.removeEventListener("documentload", listener, false);
|
||||
resolve();
|
||||
}, false, true);
|
||||
});
|
||||
});
|
||||
}
|
@ -349,7 +349,7 @@ var ShumwayCom = {
|
||||
},
|
||||
|
||||
getWeakMapKeys: function (weakMap) {
|
||||
var keys = Components.utils.nondeterministicGetWeakMapKeys(weakMap);
|
||||
var keys = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(weakMap);
|
||||
var result = new content.Array();
|
||||
keys.forEach(function (key) {
|
||||
result.push(key);
|
||||
|
@ -101,7 +101,7 @@ FINAL_TARGET ?= $(if $(XPI_NAME),$(DIST)/xpi-stage/$(XPI_NAME),$(DIST)/bin)$(DIS
|
||||
FINAL_TARGET_FROZEN := '$(FINAL_TARGET)'
|
||||
|
||||
ifdef XPI_NAME
|
||||
DEFINES += -DXPI_NAME=$(XPI_NAME)
|
||||
ACDEFINES += -DXPI_NAME=$(XPI_NAME)
|
||||
endif
|
||||
|
||||
# The VERSION_NUMBER is suffixed onto the end of the DLLs we ship.
|
||||
@ -533,7 +533,7 @@ sysinstall_cmd = install_cmd
|
||||
# overridden by the command line. (Besides, AB_CD is prettier).
|
||||
AB_CD = $(MOZ_UI_LOCALE)
|
||||
# Many locales directories want this definition.
|
||||
DEFINES += -DAB_CD=$(AB_CD)
|
||||
ACDEFINES += -DAB_CD=$(AB_CD)
|
||||
|
||||
ifndef L10NBASEDIR
|
||||
L10NBASEDIR = $(error L10NBASEDIR not defined by configure)
|
||||
@ -689,5 +689,3 @@ export CL_INCLUDES_PREFIX
|
||||
# in environment variables to prevent it from breking silently on
|
||||
# non-English systems.
|
||||
export NONASCII
|
||||
|
||||
DEFINES += -DNO_NSPR_10_SUPPORT
|
||||
|
9
config/external/nss/Makefile.in
vendored
9
config/external/nss/Makefile.in
vendored
@ -213,7 +213,7 @@ DEFAULT_GMAKE_FLAGS += \
|
||||
OS_PTHREAD= \
|
||||
$(NULL)
|
||||
|
||||
DEFAULT_GMAKE_FLAGS += ARCHFLAG='$(CFLAGS) -DCHECK_FORK_GETPID $(addprefix -DANDROID_VERSION=,$(ANDROID_VERSION)) -include $(topsrcdir)/security/manager/android_stub.h'
|
||||
DEFAULT_GMAKE_FLAGS += ARCHFLAG='$(filter-out -W%,$(CFLAGS)) -DCHECK_FORK_GETPID $(addprefix -DANDROID_VERSION=,$(ANDROID_VERSION)) -include $(topsrcdir)/security/manager/android_stub.h'
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -241,7 +241,7 @@ ifdef MOZ_NO_WLZDEFS
|
||||
DEFAULT_GMAKE_FLAGS += ZDEFS_FLAG=
|
||||
endif
|
||||
ifdef MOZ_CFLAGS_NSS
|
||||
DEFAULT_GMAKE_FLAGS += XCFLAGS='$(CFLAGS)'
|
||||
DEFAULT_GMAKE_FLAGS += XCFLAGS='$(filter-out -W%,$(CFLAGS))'
|
||||
DEFAULT_GMAKE_FLAGS += DARWIN_DYLIB_VERSIONS='-compatibility_version 1 -current_version 1 $(LDFLAGS)'
|
||||
endif
|
||||
ifeq (1_1,$(CLANG_CL)_$(MOZ_ASAN))
|
||||
@ -267,7 +267,10 @@ ifdef MOZ_FOLD_LIBS_FLAGS
|
||||
DEFAULT_GMAKE_FLAGS += XCFLAGS='$(MOZ_FOLD_LIBS_FLAGS)'
|
||||
endif
|
||||
|
||||
ifeq (1,$(ALLOW_COMPILER_WARNINGS))
|
||||
ifndef WARNINGS_AS_ERRORS
|
||||
DEFAULT_GMAKE_FLAGS += NSS_ENABLE_WERROR=0
|
||||
endif
|
||||
ifeq ($(OS_TARGET),Android)
|
||||
DEFAULT_GMAKE_FLAGS += NSS_ENABLE_WERROR=0
|
||||
endif
|
||||
|
||||
|
@ -35,8 +35,8 @@ process_py := $(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py
|
||||
%.xpt:
|
||||
@echo "$(@F)"
|
||||
$(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_CACHE_DIR) \
|
||||
$(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \
|
||||
$(dist_include_dir) $(@D) $(idl_deps_dir) $(libxul_sdk_includes) \
|
||||
$(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) --depsdir $(idl_deps_dir) \
|
||||
$(dist_idl_dir) $(dist_include_dir) $(@D) $(libxul_sdk_includes) \
|
||||
$(basename $(notdir $@)) $($(basename $(notdir $@))_deps)
|
||||
# When some IDL is added or removed, if the actual IDL file was already, or
|
||||
# still is, in the tree, simple dependencies can't detect that the XPT needs
|
||||
|
@ -13,7 +13,7 @@ include $(topsrcdir)/config/config.mk
|
||||
|
||||
XPI_NAME = test_jar_mn
|
||||
|
||||
DEFINES += \
|
||||
ACDEFINES += \
|
||||
-DAB_CD=ab-X-stuff \
|
||||
$(NULL)
|
||||
|
||||
|
@ -9172,6 +9172,9 @@ if test -z "$JS_SHARED_LIBRARY"; then
|
||||
fi
|
||||
AC_SUBST(JS_SHARED_LIBRARY)
|
||||
|
||||
# Avoid using obsolete NSPR features
|
||||
AC_DEFINE(NO_NSPR_10_SUPPORT)
|
||||
|
||||
MOZ_CREATE_CONFIG_STATUS()
|
||||
|
||||
if test "$COMPILE_ENVIRONMENT"; then
|
||||
|
@ -138,8 +138,8 @@ function test() {
|
||||
|
||||
is([...variables].length, 0,
|
||||
"VariablesView should have been emptied.");
|
||||
is(Cu.nondeterministicGetWeakMapKeys(variables._itemsByElement).length, 0,
|
||||
"VariablesView _itemsByElement map has been emptied.");
|
||||
is(ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(variables._itemsByElement).length,
|
||||
0, "VariablesView _itemsByElement map has been emptied.");
|
||||
is(variables._currHierarchy.size, 0,
|
||||
"VariablesView _currHierarchy map has been emptied.");
|
||||
is(variables._list.children.length, 0,
|
||||
|
@ -91,7 +91,7 @@ HeapSnapshot::Create(JSContext* cx,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
RefPtr<HeapSnapshot> snapshot = new HeapSnapshot(cx, global.GetAsSupports());
|
||||
if (!snapshot->init(buffer, size)) {
|
||||
if (!snapshot->init(cx, buffer, size)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
@ -203,7 +203,7 @@ HeapSnapshot::getOrInternString(InternedStringSet& internedStrings,
|
||||
: Nothing())
|
||||
|
||||
bool
|
||||
HeapSnapshot::saveNode(const protobuf::Node& node)
|
||||
HeapSnapshot::saveNode(const protobuf::Node& node, NodeIdSet& edgeReferents)
|
||||
{
|
||||
// NB: de-duplicated string properties must be read back and interned in the
|
||||
// same order here as they are written and serialized in
|
||||
@ -248,6 +248,9 @@ HeapSnapshot::saveNode(const protobuf::Node& node)
|
||||
return false;
|
||||
NodeId referent = protoEdge.referent();
|
||||
|
||||
if (NS_WARN_IF(!edgeReferents.put(referent)))
|
||||
return false;
|
||||
|
||||
const char16_t* edgeName = nullptr;
|
||||
if (protoEdge.EdgeNameOrRef_case() != protobuf::Edge::EDGENAMEORREF_NOT_SET) {
|
||||
Maybe<StringOrRef> edgeNameOrRef = GET_STRING_OR_REF(protoEdge, name);
|
||||
@ -402,7 +405,7 @@ StreamHasData(GzipInputStream& stream)
|
||||
}
|
||||
|
||||
bool
|
||||
HeapSnapshot::init(const uint8_t* buffer, uint32_t size)
|
||||
HeapSnapshot::init(JSContext* cx, const uint8_t* buffer, uint32_t size)
|
||||
{
|
||||
if (!nodes.init() || !frames.init())
|
||||
return false;
|
||||
@ -430,7 +433,12 @@ HeapSnapshot::init(const uint8_t* buffer, uint32_t size)
|
||||
return false;
|
||||
rootId = root.id();
|
||||
|
||||
if (NS_WARN_IF(!saveNode(root)))
|
||||
// The set of all node ids we've found edges pointing to.
|
||||
NodeIdSet edgeReferents(cx);
|
||||
if (NS_WARN_IF(!edgeReferents.init()))
|
||||
return false;
|
||||
|
||||
if (NS_WARN_IF(!saveNode(root, edgeReferents)))
|
||||
return false;
|
||||
|
||||
// Finally, the rest of the nodes in the core dump.
|
||||
@ -439,7 +447,15 @@ HeapSnapshot::init(const uint8_t* buffer, uint32_t size)
|
||||
protobuf::Node node;
|
||||
if (!parseMessage(gzipStream, node))
|
||||
return false;
|
||||
if (NS_WARN_IF(!saveNode(node)))
|
||||
if (NS_WARN_IF(!saveNode(node, edgeReferents)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the set of node ids referred to by edges we found and ensure that we
|
||||
// have the node corresponding to each id. If we don't have all of them, it is
|
||||
// unsafe to perform analyses of this heap snapshot.
|
||||
for (auto range = edgeReferents.all(); !range.empty(); range.popFront()) {
|
||||
if (NS_WARN_IF(!nodes.has(range.front())))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -59,11 +59,13 @@ class HeapSnapshot final : public nsISupports
|
||||
// Initialize this HeapSnapshot from the given buffer that contains a
|
||||
// serialized core dump. Do NOT take ownership of the buffer, only borrow it
|
||||
// for the duration of the call. Return false on failure.
|
||||
bool init(const uint8_t* buffer, uint32_t size);
|
||||
bool init(JSContext* cx, const uint8_t* buffer, uint32_t size);
|
||||
|
||||
using NodeIdSet = js::HashSet<NodeId>;
|
||||
|
||||
// Save the given `protobuf::Node` message in this `HeapSnapshot` as a
|
||||
// `DeserializedNode`.
|
||||
bool saveNode(const protobuf::Node& node);
|
||||
bool saveNode(const protobuf::Node& node, NodeIdSet& edgeReferents);
|
||||
|
||||
// Save the given `protobuf::StackFrame` message in this `HeapSnapshot` as a
|
||||
// `DeserializedStackFrame`. The saved stack frame's id is returned via the
|
||||
|
@ -5,6 +5,9 @@
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"DTD/xhtml1-strict.dtd">
|
||||
%htmlDTD;
|
||||
<!ENTITY % netErrorAppDTD
|
||||
SYSTEM "chrome://global/locale/netErrorApp.dtd">
|
||||
%netErrorAppDTD;
|
||||
<!ENTITY % netErrorDTD
|
||||
SYSTEM "chrome://global/locale/netError.dtd">
|
||||
%netErrorDTD;
|
||||
|
@ -11,6 +11,26 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ void
|
||||
ThreadSafeChromeUtils::NondeterministicGetWeakMapKeys(GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aMap,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!aMap.isObject()) {
|
||||
aRetval.setUndefined();
|
||||
} else {
|
||||
JSContext* cx = aGlobal.Context();
|
||||
JS::Rooted<JSObject*> objRet(cx);
|
||||
JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
|
||||
if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
} else {
|
||||
aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
||||
const dom::OriginAttributesDictionary& aAttrs,
|
||||
nsCString& aSuffix)
|
||||
|
@ -35,6 +35,11 @@ public:
|
||||
JSContext* cx,
|
||||
const nsAString& filePath,
|
||||
ErrorResult& rv);
|
||||
|
||||
static void NondeterministicGetWeakMapKeys(GlobalObject& aGlobal,
|
||||
JS::Handle<JS::Value> aMap,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
class ChromeUtils : public ThreadSafeChromeUtils
|
||||
|
@ -527,8 +527,9 @@ nsContentList::NamedItem(const nsAString& aName, bool aDoFlush)
|
||||
nsIContent *content = mElements[i];
|
||||
// XXX Should this pass eIgnoreCase?
|
||||
if (content &&
|
||||
(content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
||||
name, eCaseMatters) ||
|
||||
((content->IsHTMLElement() &&
|
||||
content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
||||
name, eCaseMatters)) ||
|
||||
content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
|
||||
name, eCaseMatters))) {
|
||||
return content->AsElement();
|
||||
|
@ -3641,7 +3641,7 @@ nsDOMWindowUtils::SetChromeMargin(int32_t aTop,
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
baseWindow->GetMainWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
nsIntMargin margins(aTop, aRight, aBottom, aLeft);
|
||||
LayoutDeviceIntMargin margins(aTop, aRight, aBottom, aLeft);
|
||||
return widget->SetNonClientMargins(margins);
|
||||
}
|
||||
}
|
||||
|
@ -13325,7 +13325,8 @@ nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
nsIntRect buttonRect = frame->GetScreenRect();
|
||||
LayoutDeviceIntRect buttonRect =
|
||||
LayoutDeviceIntRect::FromUnknownRect(frame->GetScreenRect());
|
||||
|
||||
// Get the widget rect in screen coordinates.
|
||||
nsIWidget *widget = GetNearestWidget();
|
||||
@ -13333,8 +13334,8 @@ nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
nsIntRect widgetRect;
|
||||
aError = widget->GetScreenBoundsUntyped(widgetRect);
|
||||
LayoutDeviceIntRect widgetRect;
|
||||
aError = widget->GetScreenBounds(widgetRect);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ function getIntPref(prefName, def) {
|
||||
|
||||
function handleWindowEvent(e) {
|
||||
if (this._browserElementParents) {
|
||||
let beps = Cu.nondeterministicGetWeakMapKeys(this._browserElementParents);
|
||||
let beps = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(this._browserElementParents);
|
||||
beps.forEach(bep => bep._handleOwnerEvent(e));
|
||||
}
|
||||
}
|
||||
|
@ -933,34 +933,37 @@ protected:
|
||||
{
|
||||
}
|
||||
|
||||
void DoCreateImageBitmapFromBlob(ErrorResult& aRv)
|
||||
// Returns true on success, false on failure.
|
||||
bool DoCreateImageBitmapFromBlob()
|
||||
{
|
||||
RefPtr<ImageBitmap> imageBitmap = CreateImageBitmap(aRv);
|
||||
RefPtr<ImageBitmap> imageBitmap = CreateImageBitmap();
|
||||
|
||||
// handle errors while creating ImageBitmap
|
||||
// (1) error occurs during reading of the object
|
||||
// (2) the image data is not in a supported file format
|
||||
// (3) the image data is corrupted
|
||||
// All these three cases should reject promise with null value
|
||||
if (aRv.Failed()) {
|
||||
mPromise->MaybeReject(aRv);
|
||||
return;
|
||||
if (!imageBitmap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageBitmap && mCropRect.isSome()) {
|
||||
imageBitmap->SetPictureRect(mCropRect.ref(), aRv);
|
||||
ErrorResult rv;
|
||||
imageBitmap->SetPictureRect(mCropRect.ref(), rv);
|
||||
|
||||
if (aRv.Failed()) {
|
||||
mPromise->MaybeReject(aRv);
|
||||
return;
|
||||
if (rv.Failed()) {
|
||||
mPromise->MaybeReject(rv);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(imageBitmap);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<ImageBitmap> CreateImageBitmap(ErrorResult& aRv) = 0;
|
||||
// Will return null on failure. In that case, mPromise will already
|
||||
// be rejected with the right thing.
|
||||
virtual already_AddRefed<ImageBitmap> CreateImageBitmap() = 0;
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
@ -982,17 +985,18 @@ public:
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
ErrorResult error;
|
||||
DoCreateImageBitmapFromBlob(error);
|
||||
DoCreateImageBitmapFromBlob();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
already_AddRefed<ImageBitmap> CreateImageBitmap(ErrorResult& aRv) override
|
||||
already_AddRefed<ImageBitmap> CreateImageBitmap() override
|
||||
{
|
||||
RefPtr<layers::Image> data = DecodeAndCropBlob(*mBlob, mCropRect, aRv);
|
||||
ErrorResult rv;
|
||||
RefPtr<layers::Image> data = DecodeAndCropBlob(*mBlob, mCropRect, rv);
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
mPromise->MaybeReject(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1054,23 +1058,22 @@ public:
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
ErrorResult error;
|
||||
DoCreateImageBitmapFromBlob(error);
|
||||
return !(error.Failed());
|
||||
return DoCreateImageBitmapFromBlob();
|
||||
}
|
||||
|
||||
private:
|
||||
already_AddRefed<ImageBitmap> CreateImageBitmap(ErrorResult& aRv) override
|
||||
already_AddRefed<ImageBitmap> CreateImageBitmap() override
|
||||
{
|
||||
RefPtr<layers::Image> data;
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<DecodeBlobInMainThreadSyncTask> task =
|
||||
new DecodeBlobInMainThreadSyncTask(mWorkerPrivate, *mBlob, mCropRect,
|
||||
aRv, getter_AddRefs(data));
|
||||
rv, getter_AddRefs(data));
|
||||
task->Dispatch(mWorkerPrivate->GetJSContext()); // This is a synchronous call.
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
mPromise->MaybeReject(aRv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
mPromise->MaybeReject(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -260,6 +260,7 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
||||
// if it is an app that is always precise, skip it
|
||||
nsAutoJSString origin;
|
||||
if (!origin.init(cx, id)) {
|
||||
JS_ClearPendingException(cx); // catch and ignore any exceptions
|
||||
continue;
|
||||
}
|
||||
if (mAlwaysPreciseApps.Contains(origin)) {
|
||||
@ -268,7 +269,8 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
||||
|
||||
// get the app setting object
|
||||
JS::RootedValue propertyValue(cx);
|
||||
if (!JS_GetPropertyById(cx, obj, id, &propertyValue) || !propertyValue.isObject()) {
|
||||
if (!JS_GetPropertyById(cx, obj, id, &propertyValue)) {
|
||||
JS_ClearPendingException(cx); // catch and ignore any exceptions
|
||||
continue;
|
||||
}
|
||||
JS::RootedObject settingObj(cx, &propertyValue.toObject());
|
||||
@ -280,6 +282,8 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
||||
JS::RootedValue fm(cx);
|
||||
if (JS_GetProperty(cx, settingObj, "type", &fm)) {
|
||||
settings->HandleTypeChange(fm);
|
||||
} else {
|
||||
JS_ClearPendingException(cx); // catch and ignore any exceptions
|
||||
}
|
||||
|
||||
#ifdef MOZ_APPROX_LOCATION
|
||||
@ -287,6 +291,8 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
||||
JS::RootedValue distance(cx);
|
||||
if (JS_GetProperty(cx, settingObj, "distance", &distance)) {
|
||||
settings->HandleApproxDistanceChange(distance);
|
||||
} else {
|
||||
JS_ClearPendingException(cx); // catch and ignore any exceptions
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -294,6 +300,8 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
||||
JS::RootedValue coords(cx);
|
||||
if (JS_GetProperty(cx, settingObj, "coords", &coords)) {
|
||||
settings->HandleFixedCoordsChange(coords);
|
||||
} else {
|
||||
JS_ClearPendingException(cx); // catch and ignore any exceptions
|
||||
}
|
||||
|
||||
// add the per-app setting object to the hashtable
|
||||
@ -337,11 +345,13 @@ nsGeolocationSettings::HandleGeolocationAlwaysPreciseChange(const JS::Value& aVa
|
||||
JS::RootedValue value(cx);
|
||||
|
||||
if (!JS_GetElement(cx, obj, i, &value) || !value.isString()) {
|
||||
JS_ClearPendingException(cx); // catch and ignore any exceptions
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoJSString origin;
|
||||
if (!origin.init(cx, value)) {
|
||||
JS_ClearPendingException(cx); // catch and ignore any exceptions
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1235,7 +1235,7 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys &&
|
||||
!IsMediaStreamURI(mLoadingSrc) &&
|
||||
!IsMediaSourceURI(mLoadingSrc) &&
|
||||
Preferences::GetBool("media.eme.mse-only", true)) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
@ -28,7 +28,13 @@ interface nsIServiceWorkerInfo : nsISupports
|
||||
readonly attribute DOMString cacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(e908bc07-0a4c-443f-a546-2109bf1f4A01)]
|
||||
[scriptable, uuid(87e63548-d440-4b8a-b158-65ad1de0211E)]
|
||||
interface nsIServiceWorkerRegistrationInfoListener : nsISupports
|
||||
{
|
||||
void onChange();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(72faba24-0a1b-4284-bad3-d44c044d6d95)]
|
||||
interface nsIServiceWorkerRegistrationInfo : nsISupports
|
||||
{
|
||||
readonly attribute nsIPrincipal principal;
|
||||
@ -39,6 +45,10 @@ interface nsIServiceWorkerRegistrationInfo : nsISupports
|
||||
readonly attribute nsIServiceWorkerInfo installingWorker;
|
||||
readonly attribute nsIServiceWorkerInfo waitingWorker;
|
||||
readonly attribute nsIServiceWorkerInfo activeWorker;
|
||||
|
||||
void addListener(in nsIServiceWorkerRegistrationInfoListener listener);
|
||||
|
||||
void removeListener(in nsIServiceWorkerRegistrationInfoListener listener);
|
||||
};
|
||||
|
||||
[scriptable, uuid(9e523e7c-ad6f-4df0-8077-c74aebbc679d)]
|
||||
|
@ -92,6 +92,12 @@
|
||||
<p>These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.</p>
|
||||
">
|
||||
|
||||
<!ENTITY securityOverride.linkText "Or you can add an exception…">
|
||||
<!ENTITY securityOverride.warningContent "
|
||||
<p>You should not add an exception if you are using an internet connection that you do not trust completely or if you are not used to seeing a warning for this server.</p>
|
||||
<p>If you still wish to add an exception for this site, you can do so in your advanced encryption settings.</p>
|
||||
">
|
||||
|
||||
<!ENTITY cspBlocked.title "Blocked by Content Security Policy">
|
||||
<!ENTITY cspBlocked.longDesc "<p>The browser prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
|
||||
|
||||
@ -100,10 +106,3 @@
|
||||
|
||||
<!ENTITY remoteXUL.title "Remote XUL">
|
||||
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
|
||||
|
||||
<!-- Include app-specific error messages - do not change this in localization!
|
||||
Some applications might override netErrorApp.dtd with their specific version,
|
||||
this inclusion needs to be intact for that approach to work correctly.
|
||||
Please, try to keep this at the end of the file. -->
|
||||
<!ENTITY % netErrorAppDTD SYSTEM "chrome://global/locale/netErrorApp.dtd">
|
||||
%netErrorAppDTD;
|
||||
|
@ -2,12 +2,22 @@
|
||||
- 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/. -->
|
||||
|
||||
<!-- Error messages that are likely to be overridden by applications go in this
|
||||
file, all messages that likely don't need to tie into app-specific UI
|
||||
should go into netError.dtd -->
|
||||
<!-- This file exists to allow applications to override one or more messages
|
||||
from netError.dtd; Applications which want to do this should override
|
||||
this file with their own version of netErrorApp.dtd -->
|
||||
|
||||
<!-- An example (from Firefox):
|
||||
|
||||
<!ENTITY securityOverride.linkText "Or you can add an exception…">
|
||||
<!ENTITY securityOverride.getMeOutOfHereButton "Get me out of here!">
|
||||
<!ENTITY securityOverride.exceptionButtonLabel "Add Exception…">
|
||||
|
||||
<!ENTITY securityOverride.warningContent "
|
||||
<p>You should not add an exception if you are using an internet connection that you do not trust completely or if you are not used to seeing a warning for this server.</p>
|
||||
<p>If you still wish to add an exception for this site, you can do so in your advanced encryption settings.</p>
|
||||
|
||||
<button id='getMeOutOfHereButton'>&securityOverride.getMeOutOfHereButton;</button>
|
||||
<button id='exceptionDialogButton'>&securityOverride.exceptionButtonLabel;</button>
|
||||
">
|
||||
|
||||
-->
|
||||
|
@ -629,6 +629,8 @@ skip-if = toolkit == 'android' # bug 1149374
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
|
||||
[test_eme_requestKeySystemAccess.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_setMediaKeys_before_attach_MediaSource.html]
|
||||
skip-if = toolkit == 'android' # bug 1149374
|
||||
[test_eme_stream_capture_blocked_case1.html]
|
||||
tags=msg capturestream
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
|
||||
|
@ -0,0 +1,41 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Encrypted Media Extensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function beginTest() {
|
||||
var video = document.createElement("video");
|
||||
|
||||
navigator.requestMediaKeySystemAccess("org.w3.clearkey", [{initDataTypes: ["cenc"]}])
|
||||
.then(function(keySystemAccess) {
|
||||
return keySystemAccess.createMediaKeys();
|
||||
})
|
||||
.then(mediaKeys => {
|
||||
return video.setMediaKeys(mediaKeys);
|
||||
})
|
||||
.then(() => {
|
||||
var ms = new MediaSource();
|
||||
ms.addEventListener("sourceopen", ()=>{ok(true, "MediaSource should open"); SimpleTest.finish();});
|
||||
video.addEventListener("error", ()=>{ok(false, "Shouldn't error."); SimpleTest.finish();});
|
||||
video.src = URL.createObjectURL(ms);
|
||||
});
|
||||
}
|
||||
|
||||
if (!IsMacOSSnowLeopardOrEarlier()) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SetupEMEPref(beginTest);
|
||||
} else {
|
||||
todo(false, "Test disabled on this platform.");
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -2526,35 +2526,30 @@ QuotaManager::UpdateOriginAccessTime(PersistenceType aPersistenceType,
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
QuotaManager::RemoveQuotaCallback(const nsACString& aKey,
|
||||
nsAutoPtr<GroupInfoPair>& aValue,
|
||||
void* aUserArg)
|
||||
{
|
||||
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
|
||||
NS_ASSERTION(aValue, "Null pointer!");
|
||||
|
||||
RefPtr<GroupInfo> groupInfo =
|
||||
aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
|
||||
if (groupInfo) {
|
||||
groupInfo->LockedRemoveOriginInfos();
|
||||
}
|
||||
|
||||
groupInfo = aValue->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
|
||||
if (groupInfo) {
|
||||
groupInfo->LockedRemoveOriginInfos();
|
||||
}
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
QuotaManager::RemoveQuota()
|
||||
{
|
||||
MutexAutoLock lock(mQuotaMutex);
|
||||
|
||||
mGroupInfoPairs.Enumerate(RemoveQuotaCallback, nullptr);
|
||||
for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<GroupInfoPair>& pair = iter.Data();
|
||||
|
||||
MOZ_ASSERT(!iter.Key().IsEmpty(), "Empty key!");
|
||||
MOZ_ASSERT(pair, "Null pointer!");
|
||||
|
||||
RefPtr<GroupInfo> groupInfo =
|
||||
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
|
||||
if (groupInfo) {
|
||||
groupInfo->LockedRemoveOriginInfos();
|
||||
}
|
||||
|
||||
groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
|
||||
if (groupInfo) {
|
||||
groupInfo->LockedRemoveOriginInfos();
|
||||
}
|
||||
|
||||
iter.Remove();
|
||||
}
|
||||
|
||||
NS_ASSERTION(mTemporaryStorageUsage == 0, "Should be zero!");
|
||||
}
|
||||
|
@ -461,11 +461,6 @@ private:
|
||||
const nsACString& aOrigin,
|
||||
nsAutoCString& _retval);
|
||||
|
||||
static PLDHashOperator
|
||||
RemoveQuotaCallback(const nsACString& aKey,
|
||||
nsAutoPtr<GroupInfoPair>& aValue,
|
||||
void* aUserArg);
|
||||
|
||||
mozilla::Mutex mQuotaMutex;
|
||||
|
||||
nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
|
||||
|
@ -31,6 +31,18 @@ interface ThreadSafeChromeUtils {
|
||||
*/
|
||||
[Throws, NewObject]
|
||||
static HeapSnapshot readHeapSnapshot(DOMString filePath);
|
||||
|
||||
/**
|
||||
* Return the keys in a weak map. This operation is
|
||||
* non-deterministic because it is affected by the scheduling of the
|
||||
* garbage collector and the cycle collector.
|
||||
*
|
||||
* @param aMap weak map or other JavaScript value
|
||||
* @returns If aMap is a weak map object, return the keys of the weak
|
||||
* map as an array. Otherwise, return undefined.
|
||||
*/
|
||||
[Throws, NewObject]
|
||||
static any nondeterministicGetWeakMapKeys(any map);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -158,12 +158,6 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!baseURI) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> scriptURI;
|
||||
rv = NS_NewURI(getter_AddRefs(scriptURI), aScriptURL, nullptr, baseURI);
|
||||
|
@ -436,6 +436,36 @@ ServiceWorkerRegistrationInfo::GetActiveWorker(nsIServiceWorkerInfo **aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerRegistrationInfo::AddListener(
|
||||
nsIServiceWorkerRegistrationInfoListener *aListener)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!aListener || mListeners.Contains(aListener)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mListeners.AppendElement(aListener);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerRegistrationInfo::RemoveListener(
|
||||
nsIServiceWorkerRegistrationInfoListener *aListener)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!aListener || !mListeners.Contains(aListener)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mListeners.RemoveElement(aListener);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerInfo>
|
||||
ServiceWorkerRegistrationInfo::GetServiceWorkerInfoById(uint64_t aId)
|
||||
{
|
||||
@ -970,6 +1000,7 @@ public:
|
||||
}
|
||||
|
||||
mRegistration->mScriptSpec = mScriptSpec;
|
||||
mRegistration->NotifyListenersOnChange();
|
||||
swm->StoreRegistration(mPrincipal, mRegistration);
|
||||
} else {
|
||||
MOZ_ASSERT(mJobType == UPDATE_JOB);
|
||||
@ -1162,6 +1193,7 @@ public:
|
||||
|
||||
mRegistration->mInstallingWorker = mUpdateAndInstallInfo.forget();
|
||||
mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
|
||||
mRegistration->NotifyListenersOnChange();
|
||||
|
||||
Succeed();
|
||||
// The job should NOT call fail from this point on.
|
||||
@ -1329,6 +1361,7 @@ private:
|
||||
|
||||
mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget();
|
||||
mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
|
||||
mRegistration->NotifyListenersOnChange();
|
||||
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
|
||||
WhichServiceWorker::INSTALLING_WORKER | WhichServiceWorker::WAITING_WORKER);
|
||||
|
||||
@ -1648,6 +1681,7 @@ ServiceWorkerRegistrationInfo::Activate()
|
||||
mActiveWorker = activatingWorker.forget();
|
||||
mWaitingWorker = nullptr;
|
||||
mActiveWorker->UpdateState(ServiceWorkerState::Activating);
|
||||
NotifyListenersOnChange();
|
||||
|
||||
// FIXME(nsm): Unlink appcache if there is one.
|
||||
|
||||
@ -2462,6 +2496,15 @@ ServiceWorkerRegistrationInfo::IsLastUpdateCheckTimeOverOneDay() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrationInfo::NotifyListenersOnChange()
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> listeners(mListeners);
|
||||
for (size_t index = 0; index < listeners.Length(); ++index) {
|
||||
listeners[index]->OnChange();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::LoadRegistration(
|
||||
const ServiceWorkerRegistrationData& aRegistration)
|
||||
@ -3883,7 +3926,7 @@ ServiceWorkerManager::AddListener(nsIServiceWorkerManagerListener* aListener)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (mListeners.Contains(aListener)) {
|
||||
if (!aListener || mListeners.Contains(aListener)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
@ -3897,7 +3940,7 @@ ServiceWorkerManager::RemoveListener(nsIServiceWorkerManagerListener* aListener)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!mListeners.Contains(aListener)) {
|
||||
if (!aListener || !mListeners.Contains(aListener)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,8 @@ public:
|
||||
RefPtr<ServiceWorkerInfo> mWaitingWorker;
|
||||
RefPtr<ServiceWorkerInfo> mInstallingWorker;
|
||||
|
||||
nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners;
|
||||
|
||||
uint64_t mLastUpdateCheckTime;
|
||||
|
||||
// When unregister() is called on a registration, it is not immediately
|
||||
@ -138,6 +140,9 @@ public:
|
||||
|
||||
bool
|
||||
IsLastUpdateCheckTimeOverOneDay() const;
|
||||
|
||||
void
|
||||
NotifyListenersOnChange();
|
||||
};
|
||||
|
||||
class ServiceWorkerUpdateFinishCallback
|
||||
|
@ -3,11 +3,15 @@ skip-if = buildapp == 'b2g' || os == 'android'
|
||||
support-files =
|
||||
app/*
|
||||
app2/*
|
||||
chrome_helpers.js
|
||||
serviceworkermanager_iframe.html
|
||||
serviceworkerregistrationinfo_iframe.html
|
||||
worker.js
|
||||
worker2.js
|
||||
|
||||
[test_aboutserviceworkers.html]
|
||||
skip-if = true #bug 1193319
|
||||
[test_app_installation.html]
|
||||
[test_privateBrowsing.html]
|
||||
[test_serviceworkermanager.xul]
|
||||
[test_serviceworkerregistrationinfo.xul]
|
||||
|
59
dom/workers/test/serviceworkers/chrome_helpers.js
Normal file
59
dom/workers/test/serviceworkers/chrome_helpers.js
Normal file
@ -0,0 +1,59 @@
|
||||
let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].
|
||||
getService(Ci.nsIServiceWorkerManager);
|
||||
|
||||
let EXAMPLE_URL = "https://example.com/chrome/dom/workers/test/serviceworkers/";
|
||||
|
||||
function waitForIframeLoad(iframe) {
|
||||
return new Promise(function (resolve) {
|
||||
iframe.onload = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
function waitForRegister(scope, callback) {
|
||||
return new Promise(function (resolve) {
|
||||
let listener = {
|
||||
onRegister: function (registration) {
|
||||
if (registration.scope !== scope) {
|
||||
return;
|
||||
}
|
||||
swm.removeListener(listener);
|
||||
resolve(callback ? callback(registration) : registration);
|
||||
}
|
||||
};
|
||||
swm.addListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForUnregister(scope) {
|
||||
return new Promise(function (resolve) {
|
||||
let listener = {
|
||||
onUnregister: function (registration) {
|
||||
if (registration.scope !== scope) {
|
||||
return;
|
||||
}
|
||||
swm.removeListener(listener);
|
||||
resolve(registration);
|
||||
}
|
||||
};
|
||||
swm.addListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForServiceWorkerRegistrationChange(registration, callback) {
|
||||
return new Promise(function (resolve) {
|
||||
let listener = {
|
||||
onChange: function () {
|
||||
registration.removeListener(listener);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
resolve(callback ? callback() : undefined);
|
||||
}
|
||||
};
|
||||
registration.addListener(listener);
|
||||
});
|
||||
}
|
@ -9,13 +9,21 @@
|
||||
}
|
||||
var promise = navigator.serviceWorker.register("worker.js");
|
||||
window.onmessage = function (event) {
|
||||
if (event.data !== "unregister") {
|
||||
if (event.data !== "register") {
|
||||
return;
|
||||
}
|
||||
promise.then(function (registration) {
|
||||
registration.unregister();
|
||||
promise = promise.then(function (registration) {
|
||||
return navigator.serviceWorker.register("worker2.js");
|
||||
});
|
||||
window.onmessage = null;
|
||||
window.onmessage = function (event) {
|
||||
if (event.data !== "unregister") {
|
||||
return;
|
||||
}
|
||||
promise.then(function (registration) {
|
||||
registration.unregister();
|
||||
});
|
||||
window.onmessage = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
window.onmessage = function (event) {
|
||||
if (event.data !== "register") {
|
||||
return;
|
||||
}
|
||||
var promise = navigator.serviceWorker.register("worker.js");
|
||||
window.onmessage = function (event) {
|
||||
if (event.data !== "register") {
|
||||
return;
|
||||
}
|
||||
promise.then(function (registration) {
|
||||
return navigator.serviceWorker.register("worker2.js");
|
||||
});
|
||||
};
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
This is a test page.
|
||||
</body>
|
||||
<html>
|
@ -8,53 +8,10 @@
|
||||
onload="test();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript" src="chrome_helpers.js"/>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].
|
||||
getService(Ci.nsIServiceWorkerManager);
|
||||
|
||||
function waitForIframeLoad(iframe) {
|
||||
return new Promise(function (resolve) {
|
||||
iframe.onload = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
function waitForRegister(scope) {
|
||||
return new Promise(function (resolve) {
|
||||
let listener = {
|
||||
onRegister: function (registration) {
|
||||
if (registration.scope !== scope) {
|
||||
return;
|
||||
}
|
||||
swm.removeListener(listener);
|
||||
resolve(registration);
|
||||
}
|
||||
};
|
||||
swm.addListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForUnregister(scope) {
|
||||
return new Promise(function (resolve) {
|
||||
let listener = {
|
||||
onUnregister: function (registration) {
|
||||
if (registration.scope !== scope) {
|
||||
return;
|
||||
}
|
||||
swm.removeListener(listener);
|
||||
resolve(registration);
|
||||
}
|
||||
};
|
||||
swm.addListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
let EXAMPLE_URL = "https://example.com/chrome/dom/workers/test/serviceworkers/";
|
||||
let IFRAME_URL = EXAMPLE_URL + "serviceworkermanager_iframe.html";
|
||||
|
||||
function test() {
|
||||
@ -64,7 +21,7 @@
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]}, function () {
|
||||
Task.spawn(function *() {
|
||||
Task.spawn(function* () {
|
||||
let registrations = swm.getAllRegistrations();
|
||||
is(registrations.length, 0);
|
||||
|
||||
@ -84,11 +41,23 @@
|
||||
is(registrations.queryElementAt(0, Ci.nsIServiceWorkerRegistrationInfo),
|
||||
registration);
|
||||
|
||||
info("Check that the service worker manager does not notify its " +
|
||||
"listeners when a service worker is registered with the same " +
|
||||
"scope as an existing registration.");
|
||||
let listener = {
|
||||
onRegister: function () {
|
||||
ok(false, "Listener should not have been notified.");
|
||||
}
|
||||
};
|
||||
swm.addListener(listener);
|
||||
iframe.contentWindow.postMessage("register", "*");
|
||||
|
||||
info("Check that the service worker manager notifies its listeners " +
|
||||
"when a service worker is unregistered.");
|
||||
promise = waitForUnregister(EXAMPLE_URL);
|
||||
iframe.contentWindow.postMessage("unregister", "*");
|
||||
registration = yield promise;
|
||||
swm.removeListener(listener);
|
||||
|
||||
registrations = swm.getAllRegistrations();
|
||||
is(registrations.length, 0);
|
||||
|
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<window title="Test for ServiceWorkerRegistrationInfo"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript" src="chrome_helpers.js"/>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
let IFRAME_URL = EXAMPLE_URL + "serviceworkerregistrationinfo_iframe.html";
|
||||
|
||||
function test() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]}, function () {
|
||||
Task.spawn(function* () {
|
||||
let iframe = $("iframe");
|
||||
let promise = waitForIframeLoad(iframe);
|
||||
iframe.src = IFRAME_URL;
|
||||
yield promise;
|
||||
|
||||
// The change handler is not guaranteed to be called within the same
|
||||
// tick of the event loop as the one in which the change happened.
|
||||
// Because of this, the exact state of the service worker registration
|
||||
// is only known until the handler returns.
|
||||
//
|
||||
// Because then-handlers are resolved asynchronously, the following
|
||||
// checks are done using callbacks, which are called synchronously
|
||||
// when then handler is called. These callbacks can return a promise,
|
||||
// which is used to resolve the promise returned by the function.
|
||||
|
||||
info("Check that a service worker registration notifies its " +
|
||||
"listeners when its state changes.");
|
||||
promise = waitForRegister(EXAMPLE_URL, function (registration) {
|
||||
is(registration.scriptSpec, "");
|
||||
ok(registration.installingWorker === null);
|
||||
ok(registration.waitingWorker === null);
|
||||
ok(registration.activeWorker === null);
|
||||
|
||||
return waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
is(registration.scriptSpec, EXAMPLE_URL + "worker.js");
|
||||
|
||||
return waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
ok(registration.installingWorker !== null);
|
||||
ok(registration.waitingWorker === null);
|
||||
ok(registration.activeWorker === null);
|
||||
|
||||
return waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
ok(registration.installingWorker === null);
|
||||
ok(registration.waitingWorker !== null);
|
||||
ok(registration.activeWorker === null);
|
||||
|
||||
return waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
ok(registration.installingWorker === null);
|
||||
ok(registration.waitingWorker === null);
|
||||
ok(registration.activeWorker !== null);
|
||||
|
||||
return registration;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
iframe.contentWindow.postMessage("register", "*");
|
||||
let registration = yield promise;
|
||||
|
||||
promise = waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
is(registration.scriptSpec, EXAMPLE_URL + "worker2.js");
|
||||
|
||||
return waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
ok(registration.installingWorker !== null);
|
||||
ok(registration.waitingWorker === null);
|
||||
ok(registration.activeWorker !== null);
|
||||
|
||||
return waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
ok(registration.installingWorker === null);
|
||||
ok(registration.waitingWorker !== null);
|
||||
ok(registration.activeWorker !== null);
|
||||
|
||||
return waitForServiceWorkerRegistrationChange(registration, function () {
|
||||
ok(registration.installingWorker === null);
|
||||
ok(registration.waitingWorker === null);
|
||||
ok(registration.activeWorker !== null);
|
||||
|
||||
return registration;
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
iframe.contentWindow.postMessage("register", "*");
|
||||
yield promise;
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
<iframe id="iframe"></iframe>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
@ -2007,7 +2007,7 @@ public:
|
||||
explicit MarginSetter(nsIWidget* aWidget) :
|
||||
mWidget(aWidget), mMargin(-1, -1, -1, -1)
|
||||
{}
|
||||
MarginSetter(nsIWidget *aWidget, const nsIntMargin& aMargin) :
|
||||
MarginSetter(nsIWidget *aWidget, const LayoutDeviceIntMargin& aMargin) :
|
||||
mWidget(aWidget), mMargin(aMargin)
|
||||
{}
|
||||
|
||||
@ -2021,7 +2021,7 @@ public:
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsIntMargin mMargin;
|
||||
LayoutDeviceIntMargin mMargin;
|
||||
};
|
||||
|
||||
void
|
||||
@ -2046,7 +2046,9 @@ nsXULElement::SetChromeMargins(const nsAttrValue* aValue)
|
||||
gotMargins = nsContentUtils::ParseIntMarginValue(tmp, margins);
|
||||
}
|
||||
if (gotMargins) {
|
||||
nsContentUtils::AddScriptRunner(new MarginSetter(mainWidget, margins));
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new MarginSetter(
|
||||
mainWidget, LayoutDeviceIntMargin::FromUnknownMargin(margins)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,19 @@ struct IntMarginTyped:
|
||||
IntMarginTyped() : Super() {}
|
||||
IntMarginTyped(int32_t aTop, int32_t aRight, int32_t aBottom, int32_t aLeft) :
|
||||
Super(aTop, aRight, aBottom, aLeft) {}
|
||||
|
||||
// XXX When all of the code is ported, the following functions to convert
|
||||
// to and from unknown types should be removed.
|
||||
|
||||
static IntMarginTyped<units> FromUnknownMargin(const IntMarginTyped<UnknownUnits>& aMargin) {
|
||||
return IntMarginTyped<units>(aMargin.top, aMargin.right,
|
||||
aMargin.bottom, aMargin.left);
|
||||
}
|
||||
|
||||
IntMarginTyped<UnknownUnits> ToUnknownMargin() const {
|
||||
return IntMarginTyped<UnknownUnits>(this->top, this->right,
|
||||
this->bottom, this->left);
|
||||
}
|
||||
};
|
||||
typedef IntMarginTyped<UnknownUnits> IntMargin;
|
||||
|
||||
@ -83,8 +96,8 @@ struct IntRectTyped :
|
||||
void RoundIn() {}
|
||||
void RoundOut() {}
|
||||
|
||||
// XXX When all of the code is ported, the following functions to convert to and from
|
||||
// unknown types should be removed.
|
||||
// XXX When all of the code is ported, the following functions to convert
|
||||
// to and from unknown types should be removed.
|
||||
|
||||
static IntRectTyped<units> FromUnknownRect(const IntRectTyped<UnknownUnits>& rect) {
|
||||
return IntRectTyped<units>(rect.x, rect.y, rect.width, rect.height);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "ImageContainer.h"
|
||||
#include "HeapCopyOfStackArray.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "GrallocImages.h"
|
||||
@ -330,8 +331,8 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoArrayPtr<char> buffer(new char[length]);
|
||||
mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer);
|
||||
auto buffer = MakeUnique<char[]>(length);
|
||||
mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer.get());
|
||||
|
||||
printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
|
||||
break;
|
||||
@ -349,8 +350,8 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoArrayPtr<char> buffer(new char[length]);
|
||||
mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer);
|
||||
auto buffer = MakeUnique<char[]>(length);
|
||||
mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer.get());
|
||||
|
||||
printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
|
||||
break;
|
||||
@ -369,8 +370,8 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoArrayPtr<char> buffer(new char[length]);
|
||||
mGL->fGetProgramInfoLog(program, length, nullptr, buffer);
|
||||
auto buffer = MakeUnique<char[]>(length);
|
||||
mGL->fGetProgramInfoLog(program, length, nullptr, buffer.get());
|
||||
|
||||
printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get());
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ BufferRecycleBin::BufferRecycleBin()
|
||||
}
|
||||
|
||||
void
|
||||
BufferRecycleBin::RecycleBuffer(uint8_t* aBuffer, uint32_t aSize)
|
||||
BufferRecycleBin::RecycleBuffer(UniquePtr<uint8_t[]> aBuffer, uint32_t aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
@ -124,19 +124,19 @@ BufferRecycleBin::RecycleBuffer(uint8_t* aBuffer, uint32_t aSize)
|
||||
mRecycledBuffers.Clear();
|
||||
}
|
||||
mRecycledBufferSize = aSize;
|
||||
mRecycledBuffers.AppendElement(aBuffer);
|
||||
mRecycledBuffers.AppendElement(Move(aBuffer));
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
UniquePtr<uint8_t[]>
|
||||
BufferRecycleBin::GetBuffer(uint32_t aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize)
|
||||
return new uint8_t[aSize];
|
||||
return MakeUnique<uint8_t[]>(aSize);
|
||||
|
||||
uint32_t last = mRecycledBuffers.Length() - 1;
|
||||
uint8_t* result = mRecycledBuffers[last].forget();
|
||||
UniquePtr<uint8_t[]> result = Move(mRecycledBuffers[last]);
|
||||
mRecycledBuffers.RemoveElementAt(last);
|
||||
return result;
|
||||
}
|
||||
@ -439,7 +439,7 @@ PlanarYCbCrImage::PlanarYCbCrImage()
|
||||
RecyclingPlanarYCbCrImage::~RecyclingPlanarYCbCrImage()
|
||||
{
|
||||
if (mBuffer) {
|
||||
mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
|
||||
mRecycleBin->RecycleBuffer(Move(mBuffer), mBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,7 +454,7 @@ RecyclingPlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
// - mImplData is not used
|
||||
// Not owned:
|
||||
// - mRecycleBin
|
||||
size_t size = mBuffer.SizeOfExcludingThis(aMallocSizeOf);
|
||||
size_t size = aMallocSizeOf(mBuffer.get());
|
||||
|
||||
// Could add in the future:
|
||||
// - mBackendData (from base class)
|
||||
@ -462,7 +462,7 @@ RecyclingPlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
return size;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
UniquePtr<uint8_t[]>
|
||||
RecyclingPlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
|
||||
{
|
||||
return mRecycleBin->GetBuffer(aSize);
|
||||
@ -509,7 +509,7 @@ RecyclingPlanarYCbCrImage::CopyData(const Data& aData)
|
||||
// update buffer size
|
||||
mBufferSize = size;
|
||||
|
||||
mData.mYChannel = mBuffer;
|
||||
mData.mYChannel = mBuffer.get();
|
||||
mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
|
||||
mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
|
||||
|
||||
@ -555,7 +555,7 @@ RecyclingPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
|
||||
// update buffer size
|
||||
mBufferSize = aSize;
|
||||
}
|
||||
return mBuffer;
|
||||
return mBuffer.get();
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::SourceSurface>
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#ifndef XPCOM_GLUE_AVOID_NSPR
|
||||
/**
|
||||
@ -203,9 +204,9 @@ class BufferRecycleBin final {
|
||||
public:
|
||||
BufferRecycleBin();
|
||||
|
||||
void RecycleBuffer(uint8_t* aBuffer, uint32_t aSize);
|
||||
void RecycleBuffer(mozilla::UniquePtr<uint8_t[]> aBuffer, uint32_t aSize);
|
||||
// Returns a recycled buffer of the right size, or allocates a new buffer.
|
||||
uint8_t* GetBuffer(uint32_t aSize);
|
||||
mozilla::UniquePtr<uint8_t[]> GetBuffer(uint32_t aSize);
|
||||
|
||||
private:
|
||||
typedef mozilla::Mutex Mutex;
|
||||
@ -221,7 +222,7 @@ private:
|
||||
|
||||
// We should probably do something to prune this list on a timer so we don't
|
||||
// eat excess memory while video is paused...
|
||||
nsTArray<nsAutoArrayPtr<uint8_t> > mRecycledBuffers;
|
||||
nsTArray<mozilla::UniquePtr<uint8_t[]>> mRecycledBuffers;
|
||||
// This is only valid if mRecycledBuffers is non-empty
|
||||
uint32_t mRecycledBufferSize;
|
||||
};
|
||||
@ -733,13 +734,11 @@ protected:
|
||||
|
||||
/**
|
||||
* Return a buffer to store image data in.
|
||||
* The default implementation returns memory that can
|
||||
* be freed wit delete[]
|
||||
*/
|
||||
uint8_t* AllocateBuffer(uint32_t aSize);
|
||||
mozilla::UniquePtr<uint8_t[]> AllocateBuffer(uint32_t aSize);
|
||||
|
||||
RefPtr<BufferRecycleBin> mRecycleBin;
|
||||
nsAutoArrayPtr<uint8_t> mBuffer;
|
||||
mozilla::UniquePtr<uint8_t[]> mBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1914,8 +1914,9 @@ Layer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
}
|
||||
if (GetIsFixedPosition()) {
|
||||
LayerPoint anchor = GetFixedPositionAnchor();
|
||||
aStream << nsPrintfCString(" [isFixedPosition scrollId=%lld anchor=%s%s]",
|
||||
aStream << nsPrintfCString(" [isFixedPosition scrollId=%lld sides=0x%x anchor=%s%s]",
|
||||
GetFixedPositionScrollContainerId(),
|
||||
GetFixedPositionSides(),
|
||||
ToString(anchor).c_str(),
|
||||
IsClipFixed() ? "" : " scrollingClip").get();
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/MacIOSurfaceTextureClientOGL.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "YCbCrUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -55,12 +56,12 @@ MacIOSurfaceImage::GetAsSourceSurface()
|
||||
size_t cbCrWidth = mSurface->GetDevicePixelWidth(1);
|
||||
size_t cbCrHeight = mSurface->GetDevicePixelHeight(1);
|
||||
|
||||
nsAutoArrayPtr<uint8_t> cbPlane(new uint8_t[cbCrWidth * cbCrHeight]);
|
||||
nsAutoArrayPtr<uint8_t> crPlane(new uint8_t[cbCrWidth * cbCrHeight]);
|
||||
auto cbPlane = MakeUnique<uint8_t[]>(cbCrWidth * cbCrHeight);
|
||||
auto crPlane = MakeUnique<uint8_t[]>(cbCrWidth * cbCrHeight);
|
||||
|
||||
uint8_t* src = (uint8_t*)mSurface->GetBaseAddressOfPlane(1);
|
||||
uint8_t* cbDest = cbPlane;
|
||||
uint8_t* crDest = crPlane;
|
||||
uint8_t* cbDest = cbPlane.get();
|
||||
uint8_t* crDest = crPlane.get();
|
||||
|
||||
for (size_t i = 0; i < cbCrHeight; i++) {
|
||||
uint8_t* rowSrc = src + cbCrStride * i;
|
||||
@ -79,8 +80,8 @@ MacIOSurfaceImage::GetAsSourceSurface()
|
||||
data.mYChannel = (uint8_t*)mSurface->GetBaseAddressOfPlane(0);
|
||||
data.mYStride = mSurface->GetBytesPerRow(0);
|
||||
data.mYSize = IntSize(mSurface->GetDevicePixelWidth(0), mSurface->GetDevicePixelHeight(0));
|
||||
data.mCbChannel = cbPlane;
|
||||
data.mCrChannel = crPlane;
|
||||
data.mCbChannel = cbPlane.get();
|
||||
data.mCrChannel = crPlane.get();
|
||||
data.mCbCrStride = cbCrWidth;
|
||||
data.mCbCrSize = IntSize(cbCrWidth, cbCrHeight);
|
||||
data.mPicSize = data.mYSize;
|
||||
|
@ -231,9 +231,12 @@ APZEventState::ProcessLongTap(const nsCOMPtr<nsIPresShell>& aPresShell,
|
||||
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
|
||||
|
||||
APZES_LOG("Contextmenu event handled: %d\n", eventHandled);
|
||||
|
||||
// If no one handle context menu, fire MOZLONGTAP event
|
||||
if (!eventHandled) {
|
||||
if (eventHandled) {
|
||||
// If the contextmenu event was handled then we're showing a contextmenu,
|
||||
// and so we should remove any activation
|
||||
mActiveElementManager->ClearActivation();
|
||||
} else {
|
||||
// If no one handle context menu, fire MOZLONGTAP event
|
||||
LayoutDevicePoint currentPoint =
|
||||
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid)
|
||||
* widget->GetDefaultScale();
|
||||
@ -407,7 +410,8 @@ APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
|
||||
}
|
||||
case APZStateChange::StartPanning:
|
||||
{
|
||||
mActiveElementManager->HandlePanStart();
|
||||
// The user started to pan, so we don't want anything to be :active.
|
||||
mActiveElementManager->ClearActivation();
|
||||
break;
|
||||
}
|
||||
case APZStateChange::EndTouch:
|
||||
@ -423,6 +427,17 @@ APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZEventState::ProcessClusterHit()
|
||||
{
|
||||
// If we hit a cluster of links then we shouldn't activate any of them,
|
||||
// as we will be showing the zoomed view. (This is only called on Fennec).
|
||||
#ifndef MOZ_ANDROID_APZ
|
||||
MOZ_ASSERT(false);
|
||||
#endif
|
||||
mActiveElementManager->ClearActivation();
|
||||
}
|
||||
|
||||
bool
|
||||
APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault)
|
||||
{
|
||||
|
@ -69,6 +69,7 @@ public:
|
||||
ViewID aViewId,
|
||||
APZStateChange aChange,
|
||||
int aArg);
|
||||
void ProcessClusterHit();
|
||||
private:
|
||||
~APZEventState();
|
||||
bool SendPendingTouchPreventedResponse(bool aPreventDefault);
|
||||
|
@ -101,12 +101,9 @@ ActiveElementManager::TriggerElementActivation()
|
||||
}
|
||||
|
||||
void
|
||||
ActiveElementManager::HandlePanStart()
|
||||
ActiveElementManager::ClearActivation()
|
||||
{
|
||||
AEM_LOG("Handle pan start\n");
|
||||
|
||||
// The user started to pan, so we don't want mTarget to be :active.
|
||||
// Make it not :active, and clear any pending task to make it :active.
|
||||
AEM_LOG("Clearing element activation\n");
|
||||
CancelTask();
|
||||
ResetActive();
|
||||
}
|
||||
|
@ -45,9 +45,9 @@ public:
|
||||
*/
|
||||
void HandleTouchStart(bool aCanBePan);
|
||||
/**
|
||||
* Handle the start of panning.
|
||||
* Clear the active element.
|
||||
*/
|
||||
void HandlePanStart();
|
||||
void ClearActivation();
|
||||
/**
|
||||
* Handle a touch-end or touch-cancel event.
|
||||
* @param aWasClick whether the touch was a click
|
||||
|
@ -28,6 +28,7 @@ class APZEventState;
|
||||
// tree.
|
||||
class ChromeProcessController : public mozilla::layers::GeckoContentController
|
||||
{
|
||||
protected:
|
||||
typedef mozilla::layers::FrameMetrics FrameMetrics;
|
||||
typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
|
||||
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
|
||||
#include "gfxUtils.h" // for gfxUtils
|
||||
#include "mozilla/mozalloc.h" // for operator delete[], etc
|
||||
#include "nsAutoPtr.h" // for nsRefPtr, nsAutoArrayPtr
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAutoRef.h" // for nsCountedRef
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ERROR, NS_ASSERTION
|
||||
@ -44,7 +45,7 @@ public:
|
||||
if (mDecodedBuffer) {
|
||||
// Right now this only happens if the Image was never drawn, otherwise
|
||||
// this will have been tossed away at surface destruction.
|
||||
mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride);
|
||||
mRecycleBin->RecycleBuffer(Move(mDecodedBuffer), mSize.height * mStride);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,12 +62,12 @@ public:
|
||||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
size_t size = RecyclingPlanarYCbCrImage::SizeOfExcludingThis(aMallocSizeOf);
|
||||
size += mDecodedBuffer.SizeOfExcludingThis(aMallocSizeOf);
|
||||
size += aMallocSizeOf(mDecodedBuffer.get());
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoArrayPtr<uint8_t> mDecodedBuffer;
|
||||
UniquePtr<uint8_t[]> mDecodedBuffer;
|
||||
gfx::IntSize mScaleHint;
|
||||
int mStride;
|
||||
bool mDelayedConversion;
|
||||
@ -125,7 +126,7 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer, mStride);
|
||||
gfx::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer.get(), mStride);
|
||||
SetOffscreenFormat(iFormat);
|
||||
mSize = size;
|
||||
|
||||
@ -154,7 +155,7 @@ BasicPlanarYCbCrImage::GetAsSourceSurface()
|
||||
// We create the target out of mDecodedBuffer, and get a snapshot from it.
|
||||
// The draw target is destroyed on scope exit and the surface owns the data.
|
||||
RefPtr<gfx::DrawTarget> drawTarget
|
||||
= gfxPlatform::GetPlatform()->CreateDrawTargetForData(mDecodedBuffer,
|
||||
= gfxPlatform::GetPlatform()->CreateDrawTargetForData(mDecodedBuffer.get(),
|
||||
mSize,
|
||||
mStride,
|
||||
gfx::ImageFormatToSurfaceFormat(format));
|
||||
@ -165,7 +166,7 @@ BasicPlanarYCbCrImage::GetAsSourceSurface()
|
||||
surface = drawTarget->Snapshot();
|
||||
}
|
||||
|
||||
mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride);
|
||||
mRecycleBin->RecycleBuffer(Move(mDecodedBuffer), mSize.height * mStride);
|
||||
|
||||
mSourceSurface = surface;
|
||||
return surface.forget();
|
||||
|
@ -976,7 +976,7 @@ LayerManagerComposite::RenderToPresentationSurface()
|
||||
}
|
||||
GLContext* gl = compositor->gl();
|
||||
GLContextEGL* egl = GLContextEGL::Cast(gl);
|
||||
const IntSize windowSize = mirrorScreen->GetNaturalBoundsUntyped().Size();
|
||||
const IntSize windowSize = mirrorScreen->GetNaturalBounds().Size().ToUnknownSize();
|
||||
#endif
|
||||
|
||||
if ((windowSize.width <= 0) || (windowSize.height <= 0)) {
|
||||
|
@ -149,6 +149,7 @@ CompositorD3D11::CompositorD3D11(nsIWidget* aWidget)
|
||||
, mWidget(aWidget)
|
||||
, mHwnd(nullptr)
|
||||
, mDisableSequenceForNextFrame(false)
|
||||
, mVerifyBuffersFailed(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1219,9 +1220,10 @@ CompositorD3D11::VerifyBufferSize()
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((swapDesc.BufferDesc.Width == mSize.width &&
|
||||
if (((swapDesc.BufferDesc.Width == mSize.width &&
|
||||
swapDesc.BufferDesc.Height == mSize.height) ||
|
||||
mSize.width <= 0 || mSize.height <= 0) {
|
||||
mSize.width <= 0 || mSize.height <= 0) &&
|
||||
!mVerifyBuffersFailed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1241,6 +1243,7 @@ CompositorD3D11::VerifyBufferSize()
|
||||
if (Failed(hr)) {
|
||||
gfxCriticalNote << "D3D11 swap resize buffers failed " << hexa(hr) << " on " << mSize;
|
||||
}
|
||||
mVerifyBuffersFailed = FAILED(hr);
|
||||
|
||||
return Succeeded(hr);
|
||||
}
|
||||
|
@ -199,6 +199,8 @@ private:
|
||||
// This is the clip rect applied to the default DrawTarget (i.e. the window)
|
||||
gfx::IntRect mCurrentClip;
|
||||
nsIntRegion mInvalidRegion;
|
||||
|
||||
bool mVerifyBuffersFailed;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -513,7 +513,7 @@ ShadowLayerForwarder::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::
|
||||
const nsIWidget::Configuration& configuration = aConfigurations[idx];
|
||||
mPluginWindowData.AppendElement(PluginWindowData(configuration.mWindowID,
|
||||
configuration.mClipRegion,
|
||||
configuration.mBounds,
|
||||
configuration.mBounds.ToUnknownRect(),
|
||||
configuration.mVisible));
|
||||
}
|
||||
}
|
||||
@ -598,6 +598,7 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
||||
if (mutant->GetIsFixedPosition()) {
|
||||
common.fixedPositionScrollContainerId() = mutant->GetFixedPositionScrollContainerId();
|
||||
common.fixedPositionAnchor() = mutant->GetFixedPositionAnchor();
|
||||
common.fixedPositionSides() = mutant->GetFixedPositionSides();
|
||||
common.isClipFixed() = mutant->IsClipFixed();
|
||||
}
|
||||
common.isStickyPosition() = mutant->GetIsStickyPosition();
|
||||
|
@ -740,13 +740,13 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
|
||||
|
||||
// RGBA
|
||||
size_t bufferSize = clampedRect.width * clampedRect.height * 4;
|
||||
nsAutoArrayPtr<uint8_t> buf(new uint8_t[bufferSize]);
|
||||
auto buf = MakeUnique<uint8_t[]>(bufferSize);
|
||||
|
||||
mGLContext->fReadPixels(clampedRect.x, clampedRect.y,
|
||||
clampedRect.width, clampedRect.height,
|
||||
LOCAL_GL_RGBA,
|
||||
LOCAL_GL_UNSIGNED_BYTE,
|
||||
buf);
|
||||
buf.get());
|
||||
mGLContext->fTexImage2D(mFBOTextureTarget,
|
||||
0,
|
||||
LOCAL_GL_RGBA,
|
||||
@ -754,7 +754,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
|
||||
0,
|
||||
LOCAL_GL_RGBA,
|
||||
LOCAL_GL_UNSIGNED_BYTE,
|
||||
buf);
|
||||
buf.get());
|
||||
}
|
||||
GLenum error = mGLContext->fGetError();
|
||||
if (error != LOCAL_GL_NO_ERROR) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "gfxFontUtils.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -247,9 +248,9 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
||||
}
|
||||
|
||||
// retrieve the laid-out glyph data from the CTRun
|
||||
nsAutoArrayPtr<CGGlyph> glyphsArray;
|
||||
nsAutoArrayPtr<CGPoint> positionsArray;
|
||||
nsAutoArrayPtr<CFIndex> glyphToCharArray;
|
||||
UniquePtr<CGGlyph[]> glyphsArray;
|
||||
UniquePtr<CGPoint[]> positionsArray;
|
||||
UniquePtr<CFIndex[]> glyphToCharArray;
|
||||
const CGGlyph* glyphs = nullptr;
|
||||
const CGPoint* positions = nullptr;
|
||||
const CFIndex* glyphToChar = nullptr;
|
||||
@ -264,7 +265,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
||||
// may become an attractive option.
|
||||
glyphs = ::CTRunGetGlyphsPtr(aCTRun);
|
||||
if (!glyphs) {
|
||||
glyphsArray = new (std::nothrow) CGGlyph[numGlyphs];
|
||||
glyphsArray = MakeUniqueFallible<CGGlyph[]>(numGlyphs);
|
||||
if (!glyphsArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -274,7 +275,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
||||
|
||||
positions = ::CTRunGetPositionsPtr(aCTRun);
|
||||
if (!positions) {
|
||||
positionsArray = new (std::nothrow) CGPoint[numGlyphs];
|
||||
positionsArray = MakeUniqueFallible<CGPoint[]>(numGlyphs);
|
||||
if (!positionsArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -287,7 +288,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
||||
// or the stringRange of the glyph run
|
||||
glyphToChar = ::CTRunGetStringIndicesPtr(aCTRun);
|
||||
if (!glyphToChar) {
|
||||
glyphToCharArray = new (std::nothrow) CFIndex[numGlyphs];
|
||||
glyphToCharArray = MakeUniqueFallible<CFIndex[]>(numGlyphs);
|
||||
if (!glyphToCharArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "gfxAndroidPlatform.h"
|
||||
#include "mozilla/Omnijar.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "nsIInputStream.h"
|
||||
#define gfxToolkitPlatform gfxAndroidPlatform
|
||||
|
||||
@ -1069,12 +1070,12 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
|
||||
uint32_t bufSize = item->RealSize();
|
||||
// We use fallible allocation here; if there's not enough RAM, we'll simply
|
||||
// ignore the bundled fonts and fall back to the device's installed fonts.
|
||||
nsAutoArrayPtr<uint8_t> buf(new (fallible) uint8_t[bufSize]);
|
||||
auto buf = MakeUniqueFallible<uint8_t[]>(bufSize);
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsZipCursor cursor(item, aArchive, buf, bufSize);
|
||||
nsZipCursor cursor(item, aArchive, buf.get(), bufSize);
|
||||
uint8_t* data = cursor.Copy(&bufSize);
|
||||
NS_ASSERTION(data && bufSize == item->RealSize(),
|
||||
"error reading bundled font");
|
||||
@ -1085,13 +1086,13 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
|
||||
FT_Library ftLibrary = gfxAndroidPlatform::GetPlatform()->GetFTLibrary();
|
||||
|
||||
FT_Face dummy;
|
||||
if (FT_Err_Ok != FT_New_Memory_Face(ftLibrary, buf, bufSize, 0, &dummy)) {
|
||||
if (FT_Err_Ok != FT_New_Memory_Face(ftLibrary, buf.get(), bufSize, 0, &dummy)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (FT_Long i = 0; i < dummy->num_faces; i++) {
|
||||
FT_Face face;
|
||||
if (FT_Err_Ok != FT_New_Memory_Face(ftLibrary, buf, bufSize, i, &face)) {
|
||||
if (FT_Err_Ok != FT_New_Memory_Face(ftLibrary, buf.get(), bufSize, i, &face)) {
|
||||
continue;
|
||||
}
|
||||
AddFaceToList(aEntryName, i, kStandard, FT2FontFamily::kVisible,
|
||||
|
@ -211,7 +211,7 @@ nsresult gfxFontEntry::InitializeUVSMap()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint8_t* uvsData;
|
||||
UniquePtr<uint8_t[]> uvsData;
|
||||
unsigned int cmapLen;
|
||||
const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
|
||||
nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
|
||||
@ -223,7 +223,7 @@ nsresult gfxFontEntry::InitializeUVSMap()
|
||||
return rv;
|
||||
}
|
||||
|
||||
mUVSData = uvsData;
|
||||
mUVSData = Move(uvsData);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -234,7 +234,7 @@ uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS)
|
||||
InitializeUVSMap();
|
||||
|
||||
if (mUVSData) {
|
||||
return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData, aCh, aVS);
|
||||
return gfxFontUtils::MapUVSToGlyphFormat14(mUVSData.get(), aCh, aVS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "nsDataHashtable.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
typedef struct gr_face gr_face;
|
||||
|
||||
@ -429,7 +430,7 @@ public:
|
||||
|
||||
RefPtr<gfxCharacterMap> mCharacterMap;
|
||||
uint32_t mUVSOffset;
|
||||
nsAutoArrayPtr<uint8_t> mUVSData;
|
||||
mozilla::UniquePtr<uint8_t[]> mUVSData;
|
||||
nsAutoPtr<gfxUserFontData> mUserFontData;
|
||||
nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
|
||||
// list of gfxFonts that are using SVG glyphs
|
||||
|
@ -289,7 +289,7 @@ gfxFontUtils::ReadCMAPTableFormat4(const uint8_t *aBuf, uint32_t aLength,
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
|
||||
uint8_t*& aTable)
|
||||
UniquePtr<uint8_t[]>& aTable)
|
||||
{
|
||||
enum {
|
||||
OffsetFormat = 0,
|
||||
@ -371,8 +371,8 @@ gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
|
||||
}
|
||||
}
|
||||
|
||||
aTable = new uint8_t[tablelen];
|
||||
memcpy(aTable, aBuf, tablelen);
|
||||
aTable = MakeUnique<uint8_t[]>(tablelen);
|
||||
memcpy(aTable.get(), aBuf, tablelen);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "zlib.h"
|
||||
#include <algorithm>
|
||||
@ -786,7 +787,7 @@ public:
|
||||
|
||||
static nsresult
|
||||
ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength,
|
||||
uint8_t*& aTable);
|
||||
mozilla::UniquePtr<uint8_t[]>& aTable);
|
||||
|
||||
static uint32_t
|
||||
FindPreferredSubtable(const uint8_t *aBuf, uint32_t aBufLength,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "mozilla/Likely.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/gfx/Logging.h" // for gfxCriticalError
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
|
||||
@ -2107,7 +2108,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext,
|
||||
// we need to do numeral processing even on 8-bit text,
|
||||
// in case we're converting Western to Hindi/Arabic digits
|
||||
int32_t numOption = gfxPlatform::GetPlatform()->GetBidiNumeralOption();
|
||||
nsAutoArrayPtr<char16_t> transformedString;
|
||||
UniquePtr<char16_t[]> transformedString;
|
||||
if (numOption != IBMBIDI_NUMERAL_NOMINAL) {
|
||||
// scan the string for numerals that may need to be transformed;
|
||||
// if we find any, we'll make a local copy here and use that for
|
||||
@ -2119,7 +2120,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext,
|
||||
char16_t newCh = HandleNumberInChar(origCh, prevIsArabic, numOption);
|
||||
if (newCh != origCh) {
|
||||
if (!transformedString) {
|
||||
transformedString = new char16_t[aLength];
|
||||
transformedString = MakeUnique<char16_t[]>(aLength);
|
||||
if (sizeof(T) == sizeof(char16_t)) {
|
||||
memcpy(transformedString.get(), aString, i * sizeof(char16_t));
|
||||
} else {
|
||||
|
@ -168,7 +168,8 @@ extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE;
|
||||
|
||||
namespace js {
|
||||
|
||||
template <> struct GCMethods<jsid>
|
||||
template <>
|
||||
struct GCMethods<jsid>
|
||||
{
|
||||
static jsid initial() { return JSID_VOID; }
|
||||
static void postBarrier(jsid* idp, jsid prev, jsid next) {}
|
||||
|
@ -148,13 +148,6 @@ TryPreserveReflector(JSContext* cx, HandleObject obj)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
WeakMapPostWriteBarrier(JSRuntime* rt, ObjectValueMap* weakMap, JSObject* key)
|
||||
{
|
||||
if (key && IsInsideNursery(key))
|
||||
rt->gc.storeBuffer.putGeneric(gc::HashKeyRef<ObjectValueMap, JSObject*>(weakMap, key));
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
||||
HandleObject key, HandleValue value)
|
||||
@ -189,7 +182,6 @@ SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
WeakMapPostWriteBarrier(cx->runtime(), map, key.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3881,6 +3881,9 @@ fi
|
||||
MOZ_SUBCONFIGURE_FFI()
|
||||
MOZ_SUBCONFIGURE_JEMALLOC()
|
||||
|
||||
# Avoid using obsolete NSPR features
|
||||
AC_DEFINE(NO_NSPR_10_SUPPORT)
|
||||
|
||||
dnl Spit out some output
|
||||
dnl ========================================================
|
||||
MOZ_CREATE_CONFIG_STATUS()
|
||||
|
@ -7126,12 +7126,25 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Class methods are not enumerable.
|
||||
if (type == ClassBody) {
|
||||
switch (op) {
|
||||
case JSOP_INITPROP: op = JSOP_INITHIDDENPROP; break;
|
||||
case JSOP_INITPROP_GETTER: op = JSOP_INITHIDDENPROP_GETTER; break;
|
||||
case JSOP_INITPROP_SETTER: op = JSOP_INITHIDDENPROP_SETTER; break;
|
||||
default: MOZ_CRASH("Invalid op");
|
||||
}
|
||||
}
|
||||
|
||||
if (isIndex) {
|
||||
objp.set(nullptr);
|
||||
switch (op) {
|
||||
case JSOP_INITPROP: op = JSOP_INITELEM; break;
|
||||
case JSOP_INITPROP_GETTER: op = JSOP_INITELEM_GETTER; break;
|
||||
case JSOP_INITPROP_SETTER: op = JSOP_INITELEM_SETTER; break;
|
||||
case JSOP_INITPROP: op = JSOP_INITELEM; break;
|
||||
case JSOP_INITHIDDENPROP: op = JSOP_INITHIDDENELEM; break;
|
||||
case JSOP_INITPROP_GETTER: op = JSOP_INITELEM_GETTER; break;
|
||||
case JSOP_INITHIDDENPROP_GETTER: op = JSOP_INITHIDDENELEM_GETTER; break;
|
||||
case JSOP_INITPROP_SETTER: op = JSOP_INITELEM_SETTER; break;
|
||||
case JSOP_INITHIDDENPROP_SETTER: op = JSOP_INITHIDDENELEM_SETTER; break;
|
||||
default: MOZ_CRASH("Invalid op");
|
||||
}
|
||||
if (!emit1(op))
|
||||
@ -7144,6 +7157,8 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp,
|
||||
return false;
|
||||
|
||||
if (objp) {
|
||||
MOZ_ASSERT(type == ObjectLiteral);
|
||||
MOZ_ASSERT(!IsHiddenInitOp(op));
|
||||
MOZ_ASSERT(!objp->inDictionaryMode());
|
||||
Rooted<jsid> id(cx, AtomToId(key->pn_atom));
|
||||
RootedValue undefinedValue(cx, UndefinedValue());
|
||||
@ -8466,11 +8481,9 @@ CGBlockScopeList::findEnclosingScope(uint32_t index)
|
||||
// scope contains POS, it should still be open, so its length should
|
||||
// be zero.
|
||||
return list[index].index;
|
||||
} else {
|
||||
// Conversely, if the length is not zero, it should not contain
|
||||
// POS.
|
||||
MOZ_ASSERT_IF(inPrologue == list[index].endInPrologue, list[index].end <= pos);
|
||||
}
|
||||
// Conversely, if the length is not zero, it should not contain POS.
|
||||
MOZ_ASSERT_IF(inPrologue == list[index].endInPrologue, list[index].end <= pos);
|
||||
}
|
||||
|
||||
return BlockScopeNote::NoBlockScopeIndex;
|
||||
|
@ -162,7 +162,8 @@ MovableCellHasher<T>::match(const Key& k, const Lookup& l)
|
||||
template struct MovableCellHasher<JSObject*>;
|
||||
template struct MovableCellHasher<GlobalObject*>;
|
||||
template struct MovableCellHasher<SavedFrame*>;
|
||||
template struct MovableCellHasher<ReadBarriered<ScopeObject*>>;
|
||||
template struct MovableCellHasher<ScopeObject*>;
|
||||
template struct MovableCellHasher<JSScript*>;
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
@ -482,7 +482,9 @@ class RelocatablePtr : public WriteBarrieredBase<T>
|
||||
{
|
||||
public:
|
||||
RelocatablePtr() : WriteBarrieredBase<T>(GCMethods<T>::initial()) {}
|
||||
explicit RelocatablePtr(T v) : WriteBarrieredBase<T>(v) {
|
||||
|
||||
// Implicitly adding barriers is a reasonable default.
|
||||
MOZ_IMPLICIT RelocatablePtr(const T& v) : WriteBarrieredBase<T>(v) {
|
||||
this->post(GCMethods<T>::initial(), this->value);
|
||||
}
|
||||
|
||||
@ -560,14 +562,18 @@ class ReadBarriered : public ReadBarrieredBase<T>
|
||||
public:
|
||||
ReadBarriered() : ReadBarrieredBase<T>(GCMethods<T>::initial()) {}
|
||||
|
||||
// It is okay to add barriers implicitly.
|
||||
MOZ_IMPLICIT ReadBarriered(const T& v) : ReadBarrieredBase<T>(v) {
|
||||
this->post(GCMethods<T>::initial(), v);
|
||||
}
|
||||
|
||||
// Copy is creating a new edge, so we must read barrier the source edge.
|
||||
explicit ReadBarriered(const ReadBarriered& v) : ReadBarrieredBase<T>(v) {
|
||||
this->post(GCMethods<T>::initial(), v.get());
|
||||
}
|
||||
|
||||
// Move retains the lifetime status of the source edge, so does not fire
|
||||
// the read barrier of the defunct edge.
|
||||
ReadBarriered(ReadBarriered&& v)
|
||||
: ReadBarrieredBase<T>(mozilla::Forward<ReadBarriered<T>>(v))
|
||||
{
|
||||
@ -604,6 +610,7 @@ class ReadBarriered : public ReadBarrieredBase<T>
|
||||
|
||||
const T operator->() const { return get(); }
|
||||
|
||||
T* unsafeGet() { return &this->value; }
|
||||
T const* unsafeGet() const { return &this->value; }
|
||||
|
||||
void set(const T& v)
|
||||
@ -799,6 +806,41 @@ struct MovableCellHasher
|
||||
static void rekey(Key& k, const Key& newKey) { k = newKey; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MovableCellHasher<PreBarriered<T>>
|
||||
{
|
||||
using Key = PreBarriered<T>;
|
||||
using Lookup = T;
|
||||
|
||||
static HashNumber hash(const Lookup& l) { return MovableCellHasher<T>::hash(l); }
|
||||
static bool match(const Key& k, const Lookup& l) { return MovableCellHasher<T>::match(k, l); }
|
||||
static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MovableCellHasher<RelocatablePtr<T>>
|
||||
{
|
||||
using Key = RelocatablePtr<T>;
|
||||
using Lookup = T;
|
||||
|
||||
static HashNumber hash(const Lookup& l) { return MovableCellHasher<T>::hash(l); }
|
||||
static bool match(const Key& k, const Lookup& l) { return MovableCellHasher<T>::match(k, l); }
|
||||
static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MovableCellHasher<ReadBarriered<T>>
|
||||
{
|
||||
using Key = ReadBarriered<T>;
|
||||
using Lookup = T;
|
||||
|
||||
static HashNumber hash(const Lookup& l) { return MovableCellHasher<T>::hash(l); }
|
||||
static bool match(const Key& k, const Lookup& l) {
|
||||
return MovableCellHasher<T>::match(k.unbarrieredGet(), l);
|
||||
}
|
||||
static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); }
|
||||
};
|
||||
|
||||
/* Useful for hashtables with a HeapPtr as key. */
|
||||
template <class T>
|
||||
struct HeapPtrHasher
|
||||
|
@ -1964,6 +1964,12 @@ BaselineCompiler::emit_JSOP_INITELEM()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITHIDDENELEM()
|
||||
{
|
||||
return emit_JSOP_INITELEM();
|
||||
}
|
||||
|
||||
typedef bool (*MutateProtoFn)(JSContext* cx, HandlePlainObject obj, HandleValue newProto);
|
||||
static const VMFunction MutateProtoInfo = FunctionInfo<MutateProtoFn>(MutatePrototype);
|
||||
|
||||
@ -2569,7 +2575,9 @@ bool
|
||||
BaselineCompiler::emitInitPropGetterSetter()
|
||||
{
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOP_INITPROP_GETTER ||
|
||||
JSOp(*pc) == JSOP_INITPROP_SETTER);
|
||||
JSOp(*pc) == JSOP_INITHIDDENPROP_GETTER ||
|
||||
JSOp(*pc) == JSOP_INITPROP_SETTER ||
|
||||
JSOp(*pc) == JSOP_INITHIDDENPROP_SETTER);
|
||||
|
||||
// Keep values on the stack for the decompiler.
|
||||
frame.syncStack(0);
|
||||
@ -2597,12 +2605,24 @@ BaselineCompiler::emit_JSOP_INITPROP_GETTER()
|
||||
return emitInitPropGetterSetter();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITHIDDENPROP_GETTER()
|
||||
{
|
||||
return emitInitPropGetterSetter();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITPROP_SETTER()
|
||||
{
|
||||
return emitInitPropGetterSetter();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITHIDDENPROP_SETTER()
|
||||
{
|
||||
return emitInitPropGetterSetter();
|
||||
}
|
||||
|
||||
typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandleValue,
|
||||
HandleObject);
|
||||
static const VMFunction InitElemGetterSetterInfo =
|
||||
@ -2612,7 +2632,9 @@ bool
|
||||
BaselineCompiler::emitInitElemGetterSetter()
|
||||
{
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOP_INITELEM_GETTER ||
|
||||
JSOp(*pc) == JSOP_INITELEM_SETTER);
|
||||
JSOp(*pc) == JSOP_INITHIDDENELEM_GETTER ||
|
||||
JSOp(*pc) == JSOP_INITELEM_SETTER ||
|
||||
JSOp(*pc) == JSOP_INITHIDDENELEM_SETTER);
|
||||
|
||||
// Load index and value in R0 and R1, but keep values on the stack for the
|
||||
// decompiler.
|
||||
@ -2641,12 +2663,24 @@ BaselineCompiler::emit_JSOP_INITELEM_GETTER()
|
||||
return emitInitElemGetterSetter();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITHIDDENELEM_GETTER()
|
||||
{
|
||||
return emitInitElemGetterSetter();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITELEM_SETTER()
|
||||
{
|
||||
return emitInitElemGetterSetter();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITHIDDENELEM_SETTER()
|
||||
{
|
||||
return emitInitElemGetterSetter();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITELEM_INC()
|
||||
{
|
||||
|
@ -208,7 +208,12 @@ namespace jit {
|
||||
_(JSOP_SUPERCALL) \
|
||||
_(JSOP_SPREADSUPERCALL) \
|
||||
_(JSOP_THROWSETCONST) \
|
||||
_(JSOP_THROWSETALIASEDCONST)
|
||||
_(JSOP_THROWSETALIASEDCONST) \
|
||||
_(JSOP_INITHIDDENPROP_GETTER) \
|
||||
_(JSOP_INITHIDDENPROP_SETTER) \
|
||||
_(JSOP_INITHIDDENELEM) \
|
||||
_(JSOP_INITHIDDENELEM_GETTER) \
|
||||
_(JSOP_INITHIDDENELEM_SETTER)
|
||||
|
||||
class BaselineCompiler : public BaselineCompilerSpecific
|
||||
{
|
||||
|
@ -3477,6 +3477,7 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
||||
MOZ_ASSERT(op == JSOP_SETELEM ||
|
||||
op == JSOP_STRICTSETELEM ||
|
||||
op == JSOP_INITELEM ||
|
||||
op == JSOP_INITHIDDENELEM ||
|
||||
op == JSOP_INITELEM_ARRAY ||
|
||||
op == JSOP_INITELEM_INC);
|
||||
|
||||
@ -3494,8 +3495,8 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
||||
oldInitLength = GetAnyBoxedOrUnboxedInitializedLength(obj);
|
||||
}
|
||||
|
||||
if (op == JSOP_INITELEM) {
|
||||
if (!InitElemOperation(cx, obj, index, rhs))
|
||||
if (op == JSOP_INITELEM || op == JSOP_INITHIDDENELEM) {
|
||||
if (!InitElemOperation(cx, pc, obj, index, rhs))
|
||||
return false;
|
||||
} else if (op == JSOP_INITELEM_ARRAY) {
|
||||
MOZ_ASSERT(uint32_t(index.toInt32()) <= INT32_MAX,
|
||||
|
@ -4848,7 +4848,7 @@ CodeGenerator::visitNewStringObject(LNewStringObject* lir)
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef bool(*InitElemFn)(JSContext* cx, HandleObject obj,
|
||||
typedef bool(*InitElemFn)(JSContext* cx, jsbytecode* pc, HandleObject obj,
|
||||
HandleValue id, HandleValue value);
|
||||
static const VMFunction InitElemInfo =
|
||||
FunctionInfo<InitElemFn>(InitElemOperation);
|
||||
@ -4861,6 +4861,7 @@ CodeGenerator::visitInitElem(LInitElem* lir)
|
||||
pushArg(ToValue(lir, LInitElem::ValueIndex));
|
||||
pushArg(ToValue(lir, LInitElem::IdIndex));
|
||||
pushArg(objReg);
|
||||
pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
|
||||
|
||||
callVM(InitElemInfo, lir);
|
||||
}
|
||||
|
@ -161,6 +161,7 @@ IonBuilder::IonBuilder(JSContext* analysisContext, CompileCompartment* comp,
|
||||
maybeFallbackFunctionGetter_(nullptr)
|
||||
{
|
||||
script_ = info->script();
|
||||
scriptHasIonScript_ = script_->hasIonScript();
|
||||
pc = info->startPC();
|
||||
abortReason_ = AbortReason_Disable;
|
||||
|
||||
@ -1838,6 +1839,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
return jsop_newobject();
|
||||
|
||||
case JSOP_INITELEM:
|
||||
case JSOP_INITHIDDENELEM:
|
||||
return jsop_initelem();
|
||||
|
||||
case JSOP_INITELEM_ARRAY:
|
||||
@ -1857,13 +1859,17 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
}
|
||||
|
||||
case JSOP_INITPROP_GETTER:
|
||||
case JSOP_INITPROP_SETTER: {
|
||||
case JSOP_INITHIDDENPROP_GETTER:
|
||||
case JSOP_INITPROP_SETTER:
|
||||
case JSOP_INITHIDDENPROP_SETTER: {
|
||||
PropertyName* name = info().getAtom(pc)->asPropertyName();
|
||||
return jsop_initprop_getter_setter(name);
|
||||
}
|
||||
|
||||
case JSOP_INITELEM_GETTER:
|
||||
case JSOP_INITHIDDENELEM_GETTER:
|
||||
case JSOP_INITELEM_SETTER:
|
||||
case JSOP_INITHIDDENELEM_SETTER:
|
||||
return jsop_initelem_getter_setter();
|
||||
|
||||
case JSOP_FUNCALL:
|
||||
|
@ -1016,6 +1016,10 @@ class IonBuilder
|
||||
// A builder is inextricably tied to a particular script.
|
||||
JSScript* script_;
|
||||
|
||||
// script->hasIonScript() at the start of the compilation. Used to avoid
|
||||
// calling hasIonScript() from background compilation threads.
|
||||
bool scriptHasIonScript_;
|
||||
|
||||
// If off thread compilation is successful, the final code generator is
|
||||
// attached here. Code has been generated, but not linked (there is not yet
|
||||
// an IonScript). This is heap allocated, and must be explicitly destroyed,
|
||||
@ -1035,6 +1039,7 @@ class IonBuilder
|
||||
JSObject* checkNurseryObject(JSObject* obj);
|
||||
|
||||
JSScript* script() const { return script_; }
|
||||
bool scriptHasIonScript() const { return scriptHasIonScript_; }
|
||||
|
||||
CodeGenerator* backgroundCodegen() const { return backgroundCodegen_; }
|
||||
void setBackgroundCodegen(CodeGenerator* codegen) { backgroundCodegen_ = codegen; }
|
||||
|
@ -136,7 +136,7 @@ class StringifyContext
|
||||
: sb(sb),
|
||||
gap(gap),
|
||||
replacer(cx, replacer),
|
||||
stack(cx, TraceableHashSet<JSObject*>(cx)),
|
||||
stack(cx, TraceableHashSet<JSObject*, MovableCellHasher<JSObject*>>(cx)),
|
||||
propertyList(propertyList),
|
||||
depth(0)
|
||||
{}
|
||||
@ -148,7 +148,7 @@ class StringifyContext
|
||||
StringBuffer& sb;
|
||||
const StringBuffer& gap;
|
||||
RootedObject replacer;
|
||||
Rooted<TraceableHashSet<JSObject*>> stack;
|
||||
Rooted<TraceableHashSet<JSObject*, MovableCellHasher<JSObject*>>> stack;
|
||||
const AutoIdVector& propertyList;
|
||||
uint32_t depth;
|
||||
};
|
||||
@ -324,7 +324,7 @@ class CycleDetector
|
||||
}
|
||||
|
||||
private:
|
||||
MutableHandle<TraceableHashSet<JSObject*>> stack;
|
||||
MutableHandle<TraceableHashSet<JSObject*, MovableCellHasher<JSObject*>>> stack;
|
||||
HandleObject obj_;
|
||||
};
|
||||
|
||||
|
@ -703,6 +703,14 @@ IsGetPropPC(jsbytecode* pc)
|
||||
return op == JSOP_LENGTH || op == JSOP_GETPROP || op == JSOP_CALLPROP;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsHiddenInitOp(JSOp op)
|
||||
{
|
||||
return op == JSOP_INITHIDDENPROP || op == JSOP_INITHIDDENELEM ||
|
||||
op == JSOP_INITHIDDENPROP_GETTER || op == JSOP_INITHIDDENELEM_GETTER ||
|
||||
op == JSOP_INITHIDDENPROP_SETTER || op == JSOP_INITHIDDENELEM_SETTER;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsStrictSetPC(jsbytecode* pc)
|
||||
{
|
||||
|
@ -18,9 +18,9 @@ using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
inline HashNumber
|
||||
DefaultHasher<WatchKey>::hash(const Lookup& key)
|
||||
WatchKeyHasher::hash(const Lookup& key)
|
||||
{
|
||||
return DefaultHasher<JSObject*>::hash(key.object.get()) ^ HashId(key.id.get());
|
||||
return MovableCellHasher<PreBarrieredObject>::hash(key.object) ^ HashId(key.id);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -20,6 +20,9 @@ struct WatchKey {
|
||||
WatchKey() {}
|
||||
WatchKey(JSObject* obj, jsid id) : object(obj), id(id) {}
|
||||
WatchKey(const WatchKey& key) : object(key.object.get()), id(key.id.get()) {}
|
||||
|
||||
// These are traced unconditionally during minor GC, so do not require
|
||||
// post-barriers.
|
||||
PreBarrieredObject object;
|
||||
PreBarrieredId id;
|
||||
|
||||
@ -40,14 +43,14 @@ struct Watchpoint {
|
||||
: handler(handler), closure(closure), held(held) {}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DefaultHasher<WatchKey>
|
||||
struct WatchKeyHasher
|
||||
{
|
||||
typedef WatchKey Lookup;
|
||||
static inline js::HashNumber hash(const Lookup& key);
|
||||
|
||||
static bool match(const WatchKey& k, const Lookup& l) {
|
||||
return k.object == l.object && k.id.get() == l.id.get();
|
||||
return MovableCellHasher<PreBarrieredObject>::match(k.object, l.object) &&
|
||||
DefaultHasher<PreBarrieredId>::match(k.id, l.id);
|
||||
}
|
||||
|
||||
static void rekey(WatchKey& k, const WatchKey& newKey) {
|
||||
@ -58,7 +61,7 @@ struct DefaultHasher<WatchKey>
|
||||
|
||||
class WatchpointMap {
|
||||
public:
|
||||
typedef HashMap<WatchKey, Watchpoint, DefaultHasher<WatchKey>, SystemAllocPolicy> Map;
|
||||
typedef HashMap<WatchKey, Watchpoint, WatchKeyHasher, SystemAllocPolicy> Map;
|
||||
|
||||
bool init();
|
||||
bool watch(JSContext* cx, HandleObject obj, HandleId id,
|
||||
|
@ -188,8 +188,6 @@ ObjectWeakMap::add(JSContext* cx, JSObject* obj, JSObject* target)
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
if (IsInsideNursery(obj))
|
||||
cx->runtime()->gc.storeBuffer.putGeneric(StoreBufferRef(&map, obj));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -392,11 +392,14 @@ extern JSObject*
|
||||
InitWeakMapClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
|
||||
class ObjectValueMap : public WeakMap<PreBarrieredObject, RelocatableValue>
|
||||
class ObjectValueMap : public WeakMap<RelocatablePtrObject, RelocatableValue,
|
||||
MovableCellHasher<RelocatablePtrObject>>
|
||||
{
|
||||
public:
|
||||
ObjectValueMap(JSContext* cx, JSObject* obj)
|
||||
: WeakMap<PreBarrieredObject, RelocatableValue>(cx, obj) {}
|
||||
: WeakMap<RelocatablePtrObject, RelocatableValue,
|
||||
MovableCellHasher<RelocatablePtrObject>>(cx, obj)
|
||||
{}
|
||||
|
||||
virtual bool findZoneEdges();
|
||||
};
|
||||
@ -405,9 +408,7 @@ class ObjectValueMap : public WeakMap<PreBarrieredObject, RelocatableValue>
|
||||
// Generic weak map for mapping objects to other objects.
|
||||
class ObjectWeakMap
|
||||
{
|
||||
private:
|
||||
ObjectValueMap map;
|
||||
typedef gc::HashKeyRef<ObjectValueMap, JSObject*> StoreBufferRef;
|
||||
|
||||
public:
|
||||
explicit ObjectWeakMap(JSContext* cx);
|
||||
|
@ -52,20 +52,20 @@ for (let a of [testClass,
|
||||
var aMethDesc = Object.getOwnPropertyDescriptor(a.prototype, \"__proto__\");
|
||||
assertEq(aMethDesc.writable, true);
|
||||
assertEq(aMethDesc.configurable, true);
|
||||
assertEq(aMethDesc.enumerable, true);
|
||||
assertEq(aMethDesc.enumerable, false);
|
||||
aMethDesc.value();
|
||||
assertEq(methodCalled, true);
|
||||
|
||||
var aGetDesc = Object.getOwnPropertyDescriptor(a.prototype, \"getter\");
|
||||
assertEq(aGetDesc.configurable, true);
|
||||
assertEq(aGetDesc.enumerable, true);
|
||||
assertEq(aGetDesc.enumerable, false);
|
||||
aGetDesc.get();
|
||||
assertThrowsInstanceOf(() => new aGetDesc.get, TypeError);
|
||||
assertEq(getterCalled, true);
|
||||
|
||||
var aSetDesc = Object.getOwnPropertyDescriptor(a.prototype, \"setter\");
|
||||
assertEq(aSetDesc.configurable, true);
|
||||
assertEq(aSetDesc.enumerable, true);
|
||||
assertEq(aSetDesc.enumerable, false);
|
||||
aSetDesc.set();
|
||||
assertThrowsInstanceOf(() => new aSetDesc.set, TypeError);
|
||||
assertEq(setterCalled, true);
|
||||
@ -74,7 +74,7 @@ for (let a of [testClass,
|
||||
assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticMethod\"), undefined);
|
||||
var aStaticMethDesc = Object.getOwnPropertyDescriptor(a, \"staticMethod\");
|
||||
assertEq(aStaticMethDesc.configurable, true);
|
||||
assertEq(aStaticMethDesc.enumerable, true);
|
||||
assertEq(aStaticMethDesc.enumerable, false);
|
||||
assertEq(aStaticMethDesc.writable, true);
|
||||
aStaticMethDesc.value();
|
||||
assertThrowsInstanceOf(() => new aStaticMethDesc.value, TypeError);
|
||||
@ -83,7 +83,7 @@ for (let a of [testClass,
|
||||
assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticGetter\"), undefined);
|
||||
var aStaticGetDesc = Object.getOwnPropertyDescriptor(a, \"staticGetter\");
|
||||
assertEq(aStaticGetDesc.configurable, true);
|
||||
assertEq(aStaticGetDesc.enumerable, true);
|
||||
assertEq(aStaticGetDesc.enumerable, false);
|
||||
aStaticGetDesc.get();
|
||||
assertThrowsInstanceOf(() => new aStaticGetDesc.get, TypeError);
|
||||
assertEq(staticGetterCalled, true);
|
||||
@ -91,7 +91,7 @@ for (let a of [testClass,
|
||||
assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticSetter\"), undefined);
|
||||
var aStaticSetDesc = Object.getOwnPropertyDescriptor(a, \"staticSetter\");
|
||||
assertEq(aStaticSetDesc.configurable, true);
|
||||
assertEq(aStaticSetDesc.enumerable, true);
|
||||
assertEq(aStaticSetDesc.enumerable, false);
|
||||
aStaticSetDesc.set();
|
||||
assertThrowsInstanceOf(() => new aStaticSetDesc.set, TypeError);
|
||||
assertEq(staticSetterCalled, true);
|
||||
|
@ -1082,6 +1082,8 @@ InnerViewTable::addView(JSContext* cx, ArrayBufferObject* buffer, ArrayBufferVie
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
// ViewVector has one inline element, so the first insertion is
|
||||
// guaranteed to succeed.
|
||||
MOZ_ALWAYS_TRUE(p->value().append(view));
|
||||
}
|
||||
|
||||
@ -1138,11 +1140,8 @@ InnerViewTable::sweep(JSRuntime* rt)
|
||||
return;
|
||||
|
||||
for (Map::Enum e(map); !e.empty(); e.popFront()) {
|
||||
JSObject* key = e.front().key();
|
||||
if (sweepEntry(&key, e.front().value()))
|
||||
if (sweepEntry(&e.front().mutableKey(), e.front().value()))
|
||||
e.removeFront();
|
||||
else if (key != e.front().key())
|
||||
e.rekeyFront(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1153,15 +1152,13 @@ InnerViewTable::sweepAfterMinorGC(JSRuntime* rt)
|
||||
|
||||
if (nurseryKeysValid) {
|
||||
for (size_t i = 0; i < nurseryKeys.length(); i++) {
|
||||
JSObject* key = nurseryKeys[i];
|
||||
Map::Ptr p = map.lookup(key);
|
||||
JSObject* buffer = MaybeForwarded(nurseryKeys[i]);
|
||||
Map::Ptr p = map.lookup(buffer);
|
||||
if (!p)
|
||||
continue;
|
||||
|
||||
if (sweepEntry(&key, p->value()))
|
||||
map.remove(nurseryKeys[i]);
|
||||
else
|
||||
map.rekeyIfMoved(nurseryKeys[i], key);
|
||||
if (sweepEntry(&p->mutableKey(), p->value()))
|
||||
map.remove(buffer);
|
||||
}
|
||||
nurseryKeys.clear();
|
||||
} else {
|
||||
|
@ -501,9 +501,17 @@ class InnerViewTable
|
||||
friend class ArrayBufferObject;
|
||||
|
||||
private:
|
||||
// This key is a raw pointer and not a ReadBarriered because the post-
|
||||
// barrier would hold nursery-allocated entries live unconditionally. It is
|
||||
// a very common pattern in low-level and performance-oriented JavaScript
|
||||
// to create hundreds or thousands of very short lived temporary views on a
|
||||
// larger buffer; having to tenured all of these would be a catastrophic
|
||||
// performance regression. Thus, it is vital that nursery pointers in this
|
||||
// map not be held live. Special support is required in the minor GC,
|
||||
// implemented in sweepAfterMinorGC.
|
||||
typedef HashMap<JSObject*,
|
||||
ViewVector,
|
||||
DefaultHasher<JSObject*>,
|
||||
MovableCellHasher<JSObject*>,
|
||||
SystemAllocPolicy> Map;
|
||||
|
||||
// For all objects sharing their storage with some other view, this maps
|
||||
@ -511,7 +519,10 @@ class InnerViewTable
|
||||
Map map;
|
||||
|
||||
// List of keys from innerViews where either the source or at least one
|
||||
// target is in the nursery.
|
||||
// target is in the nursery. The raw pointer to a JSObject is allowed here
|
||||
// because this vector is cleared after every minor collection. Users in
|
||||
// sweepAfterMinorCollection must be careful to use MaybeForwarded before
|
||||
// touching these pointers.
|
||||
Vector<JSObject*, 0, SystemAllocPolicy> nurseryKeys;
|
||||
|
||||
// Whether nurseryKeys is a complete list.
|
||||
|
@ -1462,7 +1462,8 @@ Debugger::onTrap(JSContext* cx, MutableHandleValue vp)
|
||||
* global the script is running against.
|
||||
*/
|
||||
Debugger* dbg = bp->debugger;
|
||||
if (dbg->enabled && dbg->debuggees.lookup(scriptGlobal)) {
|
||||
bool hasDebuggee = dbg->enabled && dbg->debuggees.has(scriptGlobal);
|
||||
if (hasDebuggee) {
|
||||
Maybe<AutoCompartment> ac;
|
||||
ac.emplace(cx, dbg->object);
|
||||
|
||||
@ -2536,13 +2537,8 @@ Debugger::markAll(JSTracer* trc)
|
||||
{
|
||||
JSRuntime* rt = trc->runtime();
|
||||
for (Debugger* dbg : rt->debuggerList) {
|
||||
WeakGlobalObjectSet& debuggees = dbg->debuggees;
|
||||
for (WeakGlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
|
||||
GlobalObject* global = e.front().unbarrieredGet();
|
||||
TraceManuallyBarrieredEdge(trc, &global, "Global Object");
|
||||
if (global != e.front().unbarrieredGet())
|
||||
e.rekeyFront(global, ReadBarrieredGlobalObject(global));
|
||||
}
|
||||
for (WeakGlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
|
||||
TraceManuallyBarrieredEdge(trc, e.mutableFront().unsafeGet(), "Global Object");
|
||||
|
||||
HeapPtrNativeObject& dbgobj = dbg->toJSObjectRef();
|
||||
TraceEdge(trc, &dbgobj, "Debugger Object");
|
||||
|
@ -42,7 +42,7 @@ class Breakpoint;
|
||||
class DebuggerMemory;
|
||||
|
||||
typedef HashSet<ReadBarrieredGlobalObject,
|
||||
DefaultHasher<ReadBarrieredGlobalObject>,
|
||||
MovableCellHasher<ReadBarrieredGlobalObject>,
|
||||
SystemAllocPolicy> WeakGlobalObjectSet;
|
||||
|
||||
/*
|
||||
@ -70,10 +70,11 @@ typedef HashSet<ReadBarrieredGlobalObject,
|
||||
* transitions.
|
||||
*/
|
||||
template <class UnbarrieredKey, bool InvisibleKeysOk=false>
|
||||
class DebuggerWeakMap : private WeakMap<PreBarriered<UnbarrieredKey>, RelocatablePtrObject>
|
||||
class DebuggerWeakMap : private WeakMap<RelocatablePtr<UnbarrieredKey>, RelocatablePtrObject,
|
||||
MovableCellHasher<RelocatablePtr<UnbarrieredKey>>>
|
||||
{
|
||||
private:
|
||||
typedef PreBarriered<UnbarrieredKey> Key;
|
||||
typedef RelocatablePtr<UnbarrieredKey> Key;
|
||||
typedef RelocatablePtrObject Value;
|
||||
|
||||
typedef HashMap<JS::Zone*,
|
||||
@ -85,7 +86,7 @@ class DebuggerWeakMap : private WeakMap<PreBarriered<UnbarrieredKey>, Relocatabl
|
||||
JSCompartment* compartment;
|
||||
|
||||
public:
|
||||
typedef WeakMap<Key, Value, DefaultHasher<Key> > Base;
|
||||
typedef WeakMap<Key, Value, MovableCellHasher<Key>> Base;
|
||||
|
||||
explicit DebuggerWeakMap(JSContext* cx)
|
||||
: Base(cx),
|
||||
@ -156,13 +157,9 @@ class DebuggerWeakMap : private WeakMap<PreBarriered<UnbarrieredKey>, Relocatabl
|
||||
/* Override sweep method to also update our edge cache. */
|
||||
void sweep() {
|
||||
for (Enum e(*static_cast<Base*>(this)); !e.empty(); e.popFront()) {
|
||||
Key k(e.front().key());
|
||||
if (gc::IsAboutToBeFinalized(&k)) {
|
||||
if (gc::IsAboutToBeFinalized(&e.front().mutableKey())) {
|
||||
decZoneCount(e.front().key()->zone());
|
||||
e.removeFront();
|
||||
decZoneCount(k->zone());
|
||||
} else {
|
||||
// markKeys() should have done any necessary relocation.
|
||||
MOZ_ASSERT(k == e.front().key());
|
||||
}
|
||||
}
|
||||
Base::assertEntriesNotAboutToBeFinalized();
|
||||
|
@ -762,8 +762,8 @@ IonBuilderHasHigherPriority(jit::IonBuilder* first, jit::IonBuilder* second)
|
||||
return first->optimizationInfo().level() < second->optimizationInfo().level();
|
||||
|
||||
// A script without an IonScript has precedence on one with.
|
||||
if (first->script()->hasIonScript() != second->script()->hasIonScript())
|
||||
return !first->script()->hasIonScript();
|
||||
if (first->scriptHasIonScript() != second->scriptHasIonScript())
|
||||
return !first->scriptHasIonScript();
|
||||
|
||||
// A higher warm-up counter indicates a higher priority.
|
||||
return first->script()->getWarmUpCount() / first->script()->length() >
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user