This commit is contained in:
Ryan VanderMeulen 2017-06-05 09:12:18 -04:00
Родитель ed8480d850 76f4ddb420
Коммит 0a3b9074de
83 изменённых файлов: 7998 добавлений и 1487 удалений

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

@ -9,10 +9,10 @@
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent", XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
"resource://gre/modules/ExtensionParent.jsm"); "resource://gre/modules/ExtensionParent.jsm");
Cu.import("resource://gre/modules/ExtensionUtils.jsm"); Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var { var {
extensionStylesheets,
promiseEvent, promiseEvent,
} = ExtensionUtils; } = ExtensionUtils;
@ -61,7 +61,7 @@ function getBrowser(sidebar) {
"chrome://extensions/content/ext-browser-content.js", false); "chrome://extensions/content/ext-browser-content.js", false);
browser.messageManager.sendAsyncMessage("Extension:InitBrowser", { browser.messageManager.sendAsyncMessage("Extension:InitBrowser", {
stylesheets: extensionStylesheets, stylesheets: ExtensionParent.extensionStylesheets,
}); });
} }
return browser; return browser;

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

@ -24,7 +24,6 @@ Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var { var {
DefaultWeakMap, DefaultWeakMap,
extensionStylesheets,
promiseEvent, promiseEvent,
} = ExtensionUtils; } = ExtensionUtils;
@ -160,7 +159,7 @@ class BasePopup {
let sheets = []; let sheets = [];
if (this.browserStyle) { if (this.browserStyle) {
sheets.push(...extensionStylesheets); sheets.push(...ExtensionParent.extensionStylesheets);
} }
if (!this.fixedWidth) { if (!this.fixedWidth) {
sheets.push(...standaloneStylesheets); sheets.push(...standaloneStylesheets);

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

@ -19,9 +19,14 @@ Cu.import("resource://gre/modules/EventEmitter.jsm");
var { var {
DefaultWeakMap, DefaultWeakMap,
IconDetails,
} = ExtensionUtils; } = ExtensionUtils;
Cu.import("resource://gre/modules/ExtensionParent.jsm");
var {
IconDetails,
} = ExtensionParent;
const POPUP_PRELOAD_TIMEOUT_MS = 200; const POPUP_PRELOAD_TIMEOUT_MS = 200;
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

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

@ -2,9 +2,8 @@
/* vim: set sts=2 sw=2 et tw=80: */ /* vim: set sts=2 sw=2 et tw=80: */
"use strict"; "use strict";
var { XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
PlatformInfo, "resource://gre/modules/ExtensionParent.jsm");
} = ExtensionUtils;
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
@ -71,6 +70,7 @@ this.commands = class extends ExtensionAPI {
let commands = new Map(); let commands = new Map();
// For Windows, chrome.runtime expects 'win' while chrome.commands // For Windows, chrome.runtime expects 'win' while chrome.commands
// expects 'windows'. We can special case this for now. // expects 'windows'. We can special case this for now.
let {PlatformInfo} = ExtensionParent;
let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os; let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
for (let [name, command] of Object.entries(manifest.commands)) { for (let [name, command] of Object.entries(manifest.commands)) {
let suggested_key = command.suggested_key || {}; let suggested_key = command.suggested_key || {};

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

@ -9,9 +9,14 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
var { var {
ExtensionError, ExtensionError,
IconDetails,
} = ExtensionUtils; } = ExtensionUtils;
Cu.import("resource://gre/modules/ExtensionParent.jsm");
var {
IconDetails,
} = ExtensionParent;
const ACTION_MENU_TOP_LEVEL_LIMIT = 6; const ACTION_MENU_TOP_LEVEL_LIMIT = 6;
// Map[Extension -> Map[ID -> MenuItem]] // Map[Extension -> Map[ID -> MenuItem]]

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

@ -6,7 +6,7 @@
var { var {
SpreadArgs, SpreadArgs,
} = ExtensionUtils; } = ExtensionCommon;
this.devtools_inspectedWindow = class extends ExtensionAPI { this.devtools_inspectedWindow = class extends ExtensionAPI {
getAPI(context) { getAPI(context) {

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

@ -8,11 +8,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
"resource:///modules/E10SUtils.jsm"); "resource:///modules/E10SUtils.jsm");
var { var {
IconDetails,
watchExtensionProxyContextLoad, watchExtensionProxyContextLoad,
} = ExtensionParent; } = ExtensionParent;
var { var {
IconDetails,
promiseEvent, promiseEvent,
} = ExtensionUtils; } = ExtensionUtils;

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

@ -8,9 +8,14 @@ XPCOMUtils.defineLazyModuleGetter(this, "PanelPopup",
var { var {
DefaultWeakMap, DefaultWeakMap,
IconDetails,
} = ExtensionUtils; } = ExtensionUtils;
Cu.import("resource://gre/modules/ExtensionParent.jsm");
var {
IconDetails,
} = ExtensionParent;
// WeakMap[Extension -> PageAction] // WeakMap[Extension -> PageAction]
let pageActionMap = new WeakMap(); let pageActionMap = new WeakMap();

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

@ -9,11 +9,16 @@ XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
XPCOMUtils.defineLazyModuleGetter(this, "Services", XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm"); "resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ExtensionParent.jsm");
var { var {
ExtensionError, ExtensionError,
IconDetails,
} = ExtensionUtils; } = ExtensionUtils;
var {
IconDetails,
} = ExtensionParent;
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
// WeakMap[Extension -> SidebarAction] // WeakMap[Extension -> SidebarAction]

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

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.8.398 Current extension version is: 1.8.423
Taken from upstream commit: 96377832 Taken from upstream commit: 8654635b

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

@ -144,7 +144,7 @@ Factory.prototype = {
registrar.unregisterFactory(this._classID2, this._factory); registrar.unregisterFactory(this._classID2, this._factory);
} }
this._factory = null; this._factory = null;
} },
}; };
var PdfJs = { var PdfJs = {
@ -344,6 +344,6 @@ var PdfJs = {
delete this._pdfStreamConverterFactory; delete this._pdfStreamConverterFactory;
this._registered = false; this._registered = false;
} },
}; };

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

@ -65,5 +65,5 @@ this.PdfJsTelemetry = {
onTimeToView(ms) { onTimeToView(ms) {
let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_TIME_TO_VIEW_MS"); let histogram = Services.telemetry.getHistogramById("PDF_VIEWER_TIME_TO_VIEW_MS");
histogram.add(ms); histogram.add(ms);
} },
}; };

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

@ -201,7 +201,7 @@ PdfDataListener.prototype = {
if (this.errorCode) { if (this.errorCode) {
value(null, this.errorCode); value(null, this.errorCode);
} }
} },
}; };
/** /**
@ -216,7 +216,7 @@ class ChromeActions {
firstPageInfo: false, firstPageInfo: false,
streamTypesUsed: [], streamTypesUsed: [],
fontTypesUsed: [], fontTypesUsed: [],
startAt: Date.now() startAt: Date.now(),
}; };
} }
@ -304,7 +304,7 @@ class ChromeActions {
onDataAvailable(aRequest, aContext, aDataInputStream, aOffset, aCount) { onDataAvailable(aRequest, aContext, aDataInputStream, aOffset, aCount) {
this.extListener.onDataAvailable(aRequest, aContext, aDataInputStream, this.extListener.onDataAvailable(aRequest, aContext, aDataInputStream,
aOffset, aCount); aOffset, aCount);
} },
}; };
channel.asyncOpen2(listener); channel.asyncOpen2(listener);
@ -573,7 +573,7 @@ class RangedChromeActions extends ChromeActions {
return; return;
} }
this.headers[aHeader] = aValue; this.headers[aHeader] = aValue;
} },
}; };
if (originalRequest.visitRequestHeaders) { if (originalRequest.visitRequestHeaders) {
originalRequest.visitRequestHeaders(httpHeaderVisitor); originalRequest.visitRequestHeaders(httpHeaderVisitor);
@ -670,7 +670,7 @@ class RangedChromeActions extends ChromeActions {
pdfjsLoadAction: "rangeProgress", pdfjsLoadAction: "rangeProgress",
loaded: evt.loaded, loaded: evt.loaded,
}, "*"); }, "*");
} },
}); });
} }
@ -763,7 +763,8 @@ class RequestListener {
response = function sendResponse(aResponse) { response = function sendResponse(aResponse) {
try { try {
var listener = doc.createEvent("CustomEvent"); var listener = doc.createEvent("CustomEvent");
let detail = Cu.cloneInto({ response: aResponse }, doc.defaultView); let detail = Cu.cloneInto({ response: aResponse, },
doc.defaultView);
listener.initCustomEvent("pdf.js.response", true, false, detail); listener.initCustomEvent("pdf.js.response", true, false, detail);
return message.dispatchEvent(listener); return message.dispatchEvent(listener);
} catch (e) { } catch (e) {
@ -996,7 +997,7 @@ PdfStreamConverter.prototype = {
domWindow.frameElement.className === "previewPluginContentFrame"; domWindow.frameElement.className === "previewPluginContentFrame";
PdfJsTelemetry.onEmbed(isObjectEmbed); PdfJsTelemetry.onEmbed(isObjectEmbed);
} }
} },
}; };
// Keep the URL the same so the browser sees it as the same. // Keep the URL the same so the browser sees it as the same.
@ -1031,6 +1032,6 @@ PdfStreamConverter.prototype = {
} }
delete this.dataListener; delete this.dataListener;
delete this.binaryStream; delete this.binaryStream;
} },
}; };

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

@ -204,7 +204,7 @@ var PdfjsChromeUtils = {
query: aEvent.detail.query, query: aEvent.detail.query,
caseSensitive: aEvent.detail.caseSensitive, caseSensitive: aEvent.detail.caseSensitive,
highlightAll: aEvent.detail.highlightAll, highlightAll: aEvent.detail.highlightAll,
findPrevious: aEvent.detail.findPrevious findPrevious: aEvent.detail.findPrevious,
}; };
let browser = aEvent.currentTarget.browser; let browser = aEvent.currentTarget.browser;
@ -329,7 +329,7 @@ var PdfjsChromeUtils = {
callback() { callback() {
messageSent = true; messageSent = true;
sendMessage(true); sendMessage(true);
} },
}]; }];
notificationBox.appendNotification(data.message, "pdfjs-fallback", null, notificationBox.appendNotification(data.message, "pdfjs-fallback", null,
notificationBox.PRIORITY_INFO_LOW, notificationBox.PRIORITY_INFO_LOW,
@ -347,6 +347,6 @@ var PdfjsChromeUtils = {
} }
sendMessage(false); sendMessage(false);
}); });
} },
}; };

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

@ -65,35 +65,35 @@ var PdfjsContentUtils = {
clearUserPref(aPrefName) { clearUserPref(aPrefName) {
this._mm.sendSyncMessage("PDFJS:Parent:clearUserPref", { this._mm.sendSyncMessage("PDFJS:Parent:clearUserPref", {
name: aPrefName name: aPrefName,
}); });
}, },
setIntPref(aPrefName, aPrefValue) { setIntPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setIntPref", { this._mm.sendSyncMessage("PDFJS:Parent:setIntPref", {
name: aPrefName, name: aPrefName,
value: aPrefValue value: aPrefValue,
}); });
}, },
setBoolPref(aPrefName, aPrefValue) { setBoolPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setBoolPref", { this._mm.sendSyncMessage("PDFJS:Parent:setBoolPref", {
name: aPrefName, name: aPrefName,
value: aPrefValue value: aPrefValue,
}); });
}, },
setCharPref(aPrefName, aPrefValue) { setCharPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setCharPref", { this._mm.sendSyncMessage("PDFJS:Parent:setCharPref", {
name: aPrefName, name: aPrefName,
value: aPrefValue value: aPrefValue,
}); });
}, },
setStringPref(aPrefName, aPrefValue) { setStringPref(aPrefName, aPrefValue) {
this._mm.sendSyncMessage("PDFJS:Parent:setStringPref", { this._mm.sendSyncMessage("PDFJS:Parent:setStringPref", {
name: aPrefName, name: aPrefName,
value: aPrefValue value: aPrefValue,
}); });
}, },
@ -140,6 +140,6 @@ var PdfjsContentUtils = {
} }
break; break;
} }
} },
}; };

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

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

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

@ -119,7 +119,7 @@ var FontInspector = (function FontInspectorClosure() {
download.href = url[1]; download.href = url[1];
} else if (fontObj.data) { } else if (fontObj.data) {
url = URL.createObjectURL(new Blob([fontObj.data], { url = URL.createObjectURL(new Blob([fontObj.data], {
type: fontObj.mimeType type: fontObj.mimeType,
})); }));
download.href = url; download.href = url;
} }
@ -154,7 +154,7 @@ var FontInspector = (function FontInspectorClosure() {
resetSelection(); resetSelection();
} }
}, 2000); }, 2000);
} },
}; };
})(); })();
@ -243,7 +243,7 @@ var StepperManager = (function StepperManagerClosure() {
saveBreakPoints: function saveBreakPoints(pageIndex, bps) { saveBreakPoints: function saveBreakPoints(pageIndex, bps) {
breakPoints[pageIndex] = bps; breakPoints[pageIndex] = bps;
sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints)); sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints));
} },
}; };
})(); })();
@ -433,7 +433,7 @@ var Stepper = (function StepperClosure() {
row.style.backgroundColor = null; row.style.backgroundColor = null;
} }
} }
} },
}; };
return Stepper; return Stepper;
})(); })();
@ -497,7 +497,7 @@ var Stats = (function Stats() {
cleanup() { cleanup() {
stats = []; stats = [];
clear(this.panel); clear(this.panel);
} },
}; };
})(); })();
@ -615,6 +615,6 @@ window.PDFBug = (function PDFBugClosure() {
tools[j].panel.setAttribute('hidden', 'true'); tools[j].panel.setAttribute('hidden', 'true');
} }
} }
} },
}; };
})(); })();

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

@ -1,157 +0,0 @@
"use strict";
// Small subset of the webL10n API by Fabien Cazenave for pdf.js extension.
(function(window) {
var gLanguage = "";
var gExternalLocalizerServices = null;
var gReadyState = "loading";
// fetch an l10n objects
function getL10nData(key) {
var response = gExternalLocalizerServices.getStrings(key);
var data = JSON.parse(response);
if (!data) {
console.warn("[l10n] #" + key + " missing for [" + gLanguage + "]");
}
return data;
}
// replace {{arguments}} with their values
function substArguments(text, args) {
if (!args) {
return text;
}
return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function(all, name) {
return (name in args ? args[name] : "{{" + name + "}}");
});
}
// translate a string
function translateString(key, args, fallback) {
var i = key.lastIndexOf(".");
var name, property;
if (i >= 0) {
name = key.substring(0, i);
property = key.substring(i + 1);
} else {
name = key;
property = "textContent";
}
var data = getL10nData(name);
var value = (data && data[property]) || fallback;
if (!value) {
return "{{" + key + "}}";
}
return substArguments(value, args);
}
// translate an HTML element
function translateElement(element) {
if (!element || !element.dataset) {
return;
}
// get the related l10n object
var key = element.dataset.l10nId;
var data = getL10nData(key);
if (!data) {
return;
}
// get arguments (if any)
// TODO: more flexible parser?
var args;
if (element.dataset.l10nArgs) {
try {
args = JSON.parse(element.dataset.l10nArgs);
} catch (e) {
console.warn("[l10n] could not parse arguments for #" + key + "");
}
}
// translate element
// TODO: security check?
for (var k in data) {
element[k] = substArguments(data[k], args);
}
}
// translate an HTML subtree
function translateFragment(element) {
element = element || document.querySelector("html");
// check all translatable children (= w/ a `data-l10n-id' attribute)
var children = element.querySelectorAll("*[data-l10n-id]");
var elementCount = children.length;
for (var i = 0; i < elementCount; i++) {
translateElement(children[i]);
}
// translate element itself if necessary
if (element.dataset.l10nId) {
translateElement(element);
}
}
function translateDocument() {
gLanguage = gExternalLocalizerServices.getLocale();
translateFragment();
gReadyState = "complete";
// fire a 'localized' DOM event
var evtObject = document.createEvent("Event");
evtObject.initEvent("localized", false, false);
evtObject.language = gLanguage;
window.dispatchEvent(evtObject);
}
window.addEventListener("DOMContentLoaded", function() {
if (gExternalLocalizerServices) {
translateDocument();
}
// ... else see setExternalLocalizerServices below
});
// Public API
document.mozL10n = {
// get a localized string
get: translateString,
// get the document language
getLanguage() {
return gLanguage;
},
// get the direction (ltr|rtl) of the current language
getDirection() {
// http://www.w3.org/International/questions/qa-scripts
// Arabic, Hebrew, Farsi, Pashto, Urdu
var rtlList = ["ar", "he", "fa", "ps", "ur"];
// use the short language code for "full" codes like 'ar-sa' (issue 5440)
var shortCode = gLanguage.split("-")[0];
return (rtlList.indexOf(shortCode) >= 0) ? "rtl" : "ltr";
},
getReadyState() {
return gReadyState;
},
setExternalLocalizerServices(externalLocalizerServices) {
gExternalLocalizerServices = externalLocalizerServices;
// ... in case if we missed DOMContentLoaded above.
if (window.document.readyState === "interactive" ||
window.document.readyState === "complete") {
translateDocument();
}
},
// translate an element or document fragment
translate: translateFragment
};
})(this);

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

@ -28,7 +28,6 @@ See https://github.com/adobe-type-tools/cmap-resources
<!-- This snippet is used in the Firefox extension (included from viewer.html) --> <!-- This snippet is used in the Firefox extension (included from viewer.html) -->
<base href="resource://pdf.js/web/"> <base href="resource://pdf.js/web/">
<script src="l10n.js"></script>
<script src="../build/pdf.js"></script> <script src="../build/pdf.js"></script>
@ -37,7 +36,6 @@ See https://github.com/adobe-type-tools/cmap-resources
<script src="viewer.js"></script> <script src="viewer.js"></script>
</head> </head>

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

3
config/external/icu/common/moz.build поставляемый
Просмотреть файл

@ -8,9 +8,6 @@ Library('icuuc')
FINAL_LIBRARY = 'icu' FINAL_LIBRARY = 'icu'
DEFINES['U_COMMON_IMPLEMENTATION'] = True DEFINES['U_COMMON_IMPLEMENTATION'] = True
# This normally gets defined in the SDK but our WINVER is too low.
#FIXME: should probably stop including mozilla-config.h
DEFINES['LOCALE_SNAME'] = 0x5c
LOCAL_INCLUDES += ['/intl/icu/source/i18n'] LOCAL_INCLUDES += ['/intl/icu/source/i18n']

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

@ -330,6 +330,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
nsIFrame* targetFrame = target->GetPrimaryFrame(); nsIFrame* targetFrame = target->GetPrimaryFrame();
nsRect targetRect; nsRect targetRect;
Maybe<nsRect> intersectionRect; Maybe<nsRect> intersectionRect;
bool isSameDoc = root && root->GetComposedDoc() == target->GetComposedDoc();
if (rootFrame && targetFrame) { if (rootFrame && targetFrame) {
// If mRoot is set we are testing intersection with a container element // If mRoot is set we are testing intersection with a container element
@ -338,7 +339,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
// Skip further processing of this target if it is not in the same // Skip further processing of this target if it is not in the same
// Document as the intersection root, e.g. if root is an element of // Document as the intersection root, e.g. if root is an element of
// the main document and target an element from an embedded iframe. // the main document and target an element from an embedded iframe.
if (target->GetComposedDoc() != root->GetComposedDoc()) { if (!isSameDoc) {
continue; continue;
} }
// Skip further processing of this target if is not a descendant of the // Skip further processing of this target if is not a descendant of the
@ -410,12 +411,12 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
intersectionRectRelativeToRoot, intersectionRectRelativeToRoot,
rootIntersectionRect rootIntersectionRect
); );
if (intersectionRect.isSome()) { if (intersectionRect.isSome() && !isSameDoc) {
intersectionRect = Some(nsLayoutUtils::TransformFrameRectToAncestor( nsRect rect = intersectionRect.value();
nsLayoutUtils::GetContainingBlockForClientRect(rootFrame), nsPresContext* presContext = targetFrame->PresContext();
intersectionRect.value(), nsLayoutUtils::TransformRect(rootFrame,
targetFrame->PresContext()->PresShell()->GetRootScrollFrame() presContext->PresShell()->GetRootScrollFrame(), rect);
)); intersectionRect = Some(rect);
} }
} }

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

@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/StructuredCloneBlob.h"
#include "js/StructuredClone.h"
#include "js/Utility.h"
#include "jswrapper.h"
#include "xpcpublic.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/StructuredCloneTags.h"
namespace mozilla {
namespace dom {
StructuredCloneBlob::StructuredCloneBlob()
: StructuredCloneHolder(CloningSupported, TransferringNotSupported,
StructuredCloneScope::DifferentProcess)
{};
/* static */ already_AddRefed<StructuredCloneBlob>
StructuredCloneBlob::Constructor(GlobalObject& aGlobal, JS::HandleValue aValue,
JS::HandleObject aTargetGlobal,
ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
Maybe<JSAutoCompartment> ac;
JS::RootedValue value(cx, aValue);
if (aTargetGlobal) {
ac.emplace(cx, aTargetGlobal);
if (!JS_WrapValue(cx, &value)) {
aRv.NoteJSContextException(cx);
return nullptr;
}
} else if (value.isObject()) {
JS::RootedObject obj(cx, js::CheckedUnwrap(&value.toObject()));
if (!obj) {
js::ReportAccessDenied(cx);
aRv.NoteJSContextException(cx);
return nullptr;
}
ac.emplace(cx, obj);
value = JS::ObjectValue(*obj);
}
holder->Write(cx, value, aRv);
if (aRv.Failed()) {
return nullptr;
}
return holder.forget();
}
void
StructuredCloneBlob::Deserialize(JSContext* aCx, JS::HandleObject aTargetScope,
JS::MutableHandleValue aResult, ErrorResult& aRv)
{
JS::RootedObject scope(aCx, js::CheckedUnwrap(aTargetScope));
if (!scope) {
js::ReportAccessDenied(aCx);
aRv.NoteJSContextException(aCx);
return;
}
{
JSAutoCompartment ac(aCx, scope);
Read(xpc::NativeGlobal(scope), aCx, aResult, aRv);
if (aRv.Failed()) {
return;
}
}
if (!JS_WrapValue(aCx, aResult)) {
aResult.set(JS::UndefinedValue());
aRv.NoteJSContextException(aCx);
}
}
/* static */ JSObject*
StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader)
{
JS::RootedObject obj(aCx);
{
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
if (!holder->ReadStructuredCloneInternal(aCx, aReader) ||
!holder->WrapObject(aCx, nullptr, &obj)) {
return nullptr;
}
}
return obj.get();
}
bool
StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader)
{
uint32_t length;
uint32_t version;
if (!JS_ReadUint32Pair(aReader, &length, &version)) {
return false;
}
JSStructuredCloneData data(length, length, 4096);
if (!JS_ReadBytes(aReader, data.Start(), length)) {
return false;
}
mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(mStructuredCloneScope,
&StructuredCloneHolder::sCallbacks,
this);
mBuffer->adopt(Move(data), version, &StructuredCloneHolder::sCallbacks);
return true;
}
bool
StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter)
{
auto& data = mBuffer->data();
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_HOLDER, 0) ||
!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION)) {
return false;
}
auto iter = data.Iter();
while (!iter.Done()) {
if (!JS_WriteBytes(aWriter, iter.Data(), iter.RemainingInSegment())) {
return false;
}
iter.Advance(data, iter.RemainingInSegment());
}
return true;
}
bool
StructuredCloneBlob::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto, JS::MutableHandleObject aResult)
{
return StructuredCloneHolderBinding::Wrap(aCx, this, aGivenProto, aResult);
}
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_StructuredCloneBlob_h
#define mozilla_dom_StructuredCloneBlob_h
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "mozilla/dom/StructuredCloneHolderBinding.h"
#include "mozilla/RefCounted.h"
#include "jsapi.h"
#include "nsISupports.h"
namespace mozilla {
namespace dom {
class StructuredCloneBlob : public StructuredCloneHolder
, public RefCounted<StructuredCloneBlob>
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(StructuredCloneBlob)
explicit StructuredCloneBlob();
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader);
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter);
static already_AddRefed<StructuredCloneBlob>
Constructor(GlobalObject& aGlobal, JS::HandleValue aValue, JS::HandleObject aTargetGlobal, ErrorResult& aRv);
void Deserialize(JSContext* aCx, JS::HandleObject aTargetScope,
JS::MutableHandleValue aResult, ErrorResult& aRv);
nsISupports* GetParentObject() const { return nullptr; }
JSObject* GetWrapper() const { return nullptr; }
bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandleObject aResult);
protected:
template <typename T, detail::RefCountAtomicity>
friend class detail::RefCounted;
~StructuredCloneBlob() = default;
private:
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_StructuredCloneBlob_h

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

@ -10,6 +10,7 @@
#include "mozilla/AutoRestore.h" #include "mozilla/AutoRestore.h"
#include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/CryptoKey.h" #include "mozilla/dom/CryptoKey.h"
#include "mozilla/dom/StructuredCloneBlob.h"
#include "mozilla/dom/Directory.h" #include "mozilla/dom/Directory.h"
#include "mozilla/dom/DirectoryBinding.h" #include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
@ -357,6 +358,10 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
return ReadStructuredCloneImageData(aCx, aReader); return ReadStructuredCloneImageData(aCx, aReader);
} }
if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
return StructuredCloneBlob::ReadStructuredClone(aCx, aReader);
}
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) { if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
if (!global) { if (!global) {
@ -453,6 +458,14 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
} }
} }
// See if this is a StructuredCloneBlob object.
{
StructuredCloneBlob* holder = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, aObj, holder))) {
return holder->WriteStructuredClone(aCx, aWriter);
}
}
// Handle URLSearchParams cloning // Handle URLSearchParams cloning
{ {
URLSearchParams* usp = nullptr; URLSearchParams* usp = nullptr;

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

@ -62,6 +62,8 @@ enum StructuredCloneTags {
SCTAG_DOM_INPUTSTREAM, SCTAG_DOM_INPUTSTREAM,
SCTAG_DOM_STRUCTURED_CLONE_HOLDER,
// When adding a new tag for IDB, please don't add it to the end of the list! // When adding a new tag for IDB, please don't add it to the end of the list!
// Tags that are supported by IDB must not ever change. See the static assert // Tags that are supported by IDB must not ever change. See the static assert
// in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback. // in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback.

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

@ -196,6 +196,7 @@ EXPORTS.mozilla.dom += [
'SameProcessMessageQueue.h', 'SameProcessMessageQueue.h',
'ScreenOrientation.h', 'ScreenOrientation.h',
'ShadowRoot.h', 'ShadowRoot.h',
'StructuredCloneBlob.h',
'StructuredCloneHolder.h', 'StructuredCloneHolder.h',
'StructuredCloneTags.h', 'StructuredCloneTags.h',
'StyleSheetList.h', 'StyleSheetList.h',
@ -338,6 +339,7 @@ UNIFIED_SOURCES += [
'SameProcessMessageQueue.cpp', 'SameProcessMessageQueue.cpp',
'ScreenOrientation.cpp', 'ScreenOrientation.cpp',
'ShadowRoot.cpp', 'ShadowRoot.cpp',
'StructuredCloneBlob.cpp',
'StructuredCloneHolder.cpp', 'StructuredCloneHolder.cpp',
'StyleSheetList.cpp', 'StyleSheetList.cpp',
'SubtleCrypto.cpp', 'SubtleCrypto.cpp',

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

@ -3893,6 +3893,10 @@ nsDOMWindowUtils::GetContentAPZTestData(JSContext* aContext,
if (!clm->GetAPZTestData().ToJS(aOutContentTestData, aContext)) { if (!clm->GetAPZTestData().ToJS(aOutContentTestData, aContext)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} else if (WebRenderLayerManager* wrlm = lm->AsWebRenderLayerManager()) {
if (!wrlm->GetAPZTestData().ToJS(aOutContentTestData, aContext)) {
return NS_ERROR_FAILURE;
}
} }
} }
@ -3908,13 +3912,20 @@ nsDOMWindowUtils::GetCompositorAPZTestData(JSContext* aContext,
if (!lm) { if (!lm) {
return NS_OK; return NS_OK;
} }
APZTestData compositorSideData;
if (ClientLayerManager* clm = lm->AsClientLayerManager()) { if (ClientLayerManager* clm = lm->AsClientLayerManager()) {
APZTestData compositorSideData;
clm->GetCompositorSideAPZTestData(&compositorSideData); clm->GetCompositorSideAPZTestData(&compositorSideData);
if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) { } else if (WebRenderLayerManager* wrlm = lm->AsWebRenderLayerManager()) {
if (!wrlm->WrBridge()) {
return NS_ERROR_UNEXPECTED;
}
if (!wrlm->WrBridge()->SendGetAPZTestData(&compositorSideData)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} }
if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) {
return NS_ERROR_FAILURE;
}
} }
return NS_OK; return NS_OK;

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

@ -0,0 +1,98 @@
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
const global = this;
add_task(async function test_structuredCloneHolder() {
let principal = Services.scriptSecurityManager.createCodebasePrincipal(
Services.io.newURI("http://example.com/"), {});
let sandbox = Cu.Sandbox(principal);
const obj = {foo: [{bar: "baz"}]};
let holder = new StructuredCloneHolder(obj);
// Test same-compartment deserialization
let res = holder.deserialize(global);
notEqual(res, obj, "Deserialized result is a different object from the original");
deepEqual(res, obj, "Deserialized result is deeply equivalent to the original");
equal(Cu.getObjectPrincipal(res), Cu.getObjectPrincipal(global),
"Deserialized result has the correct principal");
// Test non-object-value round-trip.
equal(new StructuredCloneHolder("foo").deserialize(global), "foo",
"Round-tripping non-object values works as expected");
// Test cross-compartment deserialization
res = holder.deserialize(sandbox);
notEqual(res, obj, "Cross-compartment-deserialized result is a different object from the original");
deepEqual(res, obj, "Cross-compartment-deserialized result is deeply equivalent to the original");
equal(Cu.getObjectPrincipal(res), principal,
"Cross-compartment-deserialized result has the correct principal");
// Test message manager transportability
const MSG = "StructuredCloneHolder";
let resultPromise = new Promise(resolve => {
Services.ppmm.addMessageListener(MSG, resolve);
});
Services.cpmm.sendAsyncMessage(MSG, holder);
res = await resultPromise;
ok(res.data instanceof StructuredCloneHolder,
"Sending structured clone holders through message managers works as expected");
deepEqual(res.data.deserialize(global), obj,
"Sending structured clone holders through message managers works as expected");
});
// Test that X-rays passed to an exported function are serialized
// through their exported wrappers.
add_task(async function test_structuredCloneHolder_xray() {
let principal = Services.scriptSecurityManager.createCodebasePrincipal(
Services.io.newURI("http://example.com/"), {});
let sandbox1 = Cu.Sandbox(principal, {wantXrays: true});
let sandbox2 = Cu.Sandbox(principal, {wantXrays: true});
Cu.evalInSandbox(`this.x = {y: "z", get z() { return "q" }}`, sandbox2);
sandbox1.x = sandbox2.x;
let holder;
Cu.exportFunction(function serialize(val) {
holder = new StructuredCloneHolder(val, sandbox1);
}, sandbox1, {defineAs: "serialize"});
Cu.evalInSandbox(`serialize(x)`, sandbox1);
const obj = {y: "z"};
let res = holder.deserialize(global);
deepEqual(res, obj, "Deserialized result is deeply equivalent to the expected object");
deepEqual(res, sandbox2.x, "Deserialized result is deeply equivalent to the X-ray-wrapped object");
equal(Cu.getObjectPrincipal(res), Cu.getObjectPrincipal(global),
"Deserialized result has the correct principal");
});

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

@ -38,6 +38,7 @@ head = head_xml.js
head = head_xml.js head = head_xml.js
[test_range.js] [test_range.js]
head = head_xml.js head = head_xml.js
[test_structuredcloneholder.js]
[test_thirdpartyutil.js] [test_thirdpartyutil.js]
[test_treewalker.js] [test_treewalker.js]
head = head_xml.js head = head_xml.js

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

@ -798,6 +798,11 @@ DOMInterfaces = {
'implicitJSContext': [ 'close' ], 'implicitJSContext': [ 'close' ],
}, },
'StructuredCloneHolder': {
'nativeType': 'mozilla::dom::StructuredCloneBlob',
'wrapperCache': False,
},
'StyleSheet': { 'StyleSheet': {
'nativeType': 'mozilla::StyleSheet', 'nativeType': 'mozilla::StyleSheet',
'headerFile': 'mozilla/StyleSheetInlines.h', 'headerFile': 'mozilla/StyleSheetInlines.h',

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

@ -0,0 +1,27 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* A holder for structured-clonable data which can itself be cloned with
* little overhead, and deserialized into an arbitrary global.
*/
[ChromeOnly, Exposed=(Window,System,Worker),
/**
* Serializes the given value to an opaque structured clone blob, and
* returns the result.
*
* The serialization happens in the compartment of the given global or, if no
* global is provided, the compartment of the data value.
*/
Constructor(any data, optional object? global = null)]
interface StructuredCloneHolder {
/**
* Deserializes the structured clone data in the scope of the given global,
* and returns the result.
*/
[Throws]
any deserialize(object global);
};

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

@ -790,6 +790,7 @@ WEBIDL_FILES = [
'StorageEvent.webidl', 'StorageEvent.webidl',
'StorageManager.webidl', 'StorageManager.webidl',
'StorageType.webidl', 'StorageType.webidl',
'StructuredCloneHolder.webidl',
'StyleSheet.webidl', 'StyleSheet.webidl',
'StyleSheetList.webidl', 'StyleSheetList.webidl',
'SubtleCrypto.webidl', 'SubtleCrypto.webidl',

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

@ -1334,9 +1334,10 @@ CompositorBridgeParent::FlushApzRepaints(const uint64_t& aLayersId)
} }
void void
CompositorBridgeParent::GetAPZTestData(const LayerTransactionParent* aLayerTree, CompositorBridgeParent::GetAPZTestData(const uint64_t& aLayersId,
APZTestData* aOutData) APZTestData* aOutData)
{ {
MOZ_ASSERT(aLayersId == 0 || aLayersId == mRootLayerTreeID);
MonitorAutoLock lock(*sIndirectLayerTreesLock); MonitorAutoLock lock(*sIndirectLayerTreesLock);
*aOutData = sIndirectLayerTrees[mRootLayerTreeID].mApzTestData; *aOutData = sIndirectLayerTrees[mRootLayerTreeID].mApzTestData;
} }

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

@ -109,7 +109,7 @@ public:
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) = 0; virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) = 0;
virtual CompositorAnimationStorage* GetAnimationStorage(const uint64_t& aId) { return nullptr; } virtual CompositorAnimationStorage* GetAnimationStorage(const uint64_t& aId) { return nullptr; }
virtual void FlushApzRepaints(const uint64_t& aLayersId) = 0; virtual void FlushApzRepaints(const uint64_t& aLayersId) = 0;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree, virtual void GetAPZTestData(const uint64_t& aLayersId,
APZTestData* aOutData) { } APZTestData* aOutData) { }
virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId, virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId,
const uint64_t& aInputBlockId, const uint64_t& aInputBlockId,
@ -232,7 +232,7 @@ public:
override; override;
virtual CompositorAnimationStorage* GetAnimationStorage(const uint64_t& aId) override; virtual CompositorAnimationStorage* GetAnimationStorage(const uint64_t& aId) override;
virtual void FlushApzRepaints(const uint64_t& aLayersId) override; virtual void FlushApzRepaints(const uint64_t& aLayersId) override;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree, virtual void GetAPZTestData(const uint64_t& aLayersId,
APZTestData* aOutData) override; APZTestData* aOutData) override;
virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId, virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId,
const uint64_t& aInputBlockId, const uint64_t& aInputBlockId,

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

@ -437,13 +437,12 @@ CrossProcessCompositorBridgeParent::FlushApzRepaints(const uint64_t& aLayersId)
void void
CrossProcessCompositorBridgeParent::GetAPZTestData( CrossProcessCompositorBridgeParent::GetAPZTestData(
const LayerTransactionParent* aLayerTree, const uint64_t& aLayersId,
APZTestData* aOutData) APZTestData* aOutData)
{ {
uint64_t id = aLayerTree->GetId(); MOZ_ASSERT(aLayersId != 0);
MOZ_ASSERT(id != 0);
MonitorAutoLock lock(*sIndirectLayerTreesLock); MonitorAutoLock lock(*sIndirectLayerTreesLock);
*aOutData = sIndirectLayerTrees[id].mApzTestData; *aOutData = sIndirectLayerTrees[aLayersId].mApzTestData;
} }
void void

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

@ -105,7 +105,7 @@ public:
virtual CompositorAnimationStorage* virtual CompositorAnimationStorage*
GetAnimationStorage(const uint64_t& aId) override; GetAnimationStorage(const uint64_t& aId) override;
virtual void FlushApzRepaints(const uint64_t& aLayersId) override; virtual void FlushApzRepaints(const uint64_t& aLayersId) override;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree, virtual void GetAPZTestData(const uint64_t& aLayersId,
APZTestData* aOutData) override; APZTestData* aOutData) override;
virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId, virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId,
const uint64_t& aInputBlockId, const uint64_t& aInputBlockId,

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

@ -849,7 +849,7 @@ LayerTransactionParent::RecvFlushApzRepaints()
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData) LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData)
{ {
mCompositorBridge->GetAPZTestData(this, aOutData); mCompositorBridge->GetAPZTestData(GetId(), aOutData);
return IPC_OK(); return IPC_OK();
} }

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

@ -14,6 +14,7 @@ include WebRenderMessages;
include protocol PCompositorBridge; include protocol PCompositorBridge;
include protocol PTexture; include protocol PTexture;
using mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h";
using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h"; using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h"; using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h"; using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
@ -76,6 +77,7 @@ parent:
sync SetAsyncScrollOffset(ViewID scrollId, float x, float y); sync SetAsyncScrollOffset(ViewID scrollId, float x, float y);
sync SetAsyncZoom(ViewID scrollId, float zoom); sync SetAsyncZoom(ViewID scrollId, float zoom);
async FlushApzRepaints(); async FlushApzRepaints();
sync GetAPZTestData() returns (APZTestData data);
async Shutdown(); async Shutdown();
child: child:

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

@ -371,7 +371,7 @@ WebRenderBridgeParent::UpdateAPZ()
if (RefPtr<APZCTreeManager> apzc = cbp->GetAPZCTreeManager()) { if (RefPtr<APZCTreeManager> apzc = cbp->GetAPZCTreeManager()) {
apzc->UpdateHitTestingTree(rootLayersId, rootWrbp->GetScrollData(), apzc->UpdateHitTestingTree(rootLayersId, rootWrbp->GetScrollData(),
mScrollData.IsFirstPaint(), GetLayersId(), mScrollData.IsFirstPaint(), GetLayersId(),
/* TODO: propagate paint sequence number */ 0); mScrollData.GetPaintSequenceNumber());
} }
} }
@ -413,6 +413,9 @@ WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
const WrBuiltDisplayListDescriptor& dlDesc, const WrBuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData) const WebRenderScrollData& aScrollData)
{ {
if (mDestroyed) {
return IPC_OK();
}
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId, HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
aContentSize, dl, dlDesc, aScrollData); aContentSize, dl, dlDesc, aScrollData);
return IPC_OK(); return IPC_OK();
@ -429,6 +432,9 @@ WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize,
const WrBuiltDisplayListDescriptor& dlDesc, const WrBuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData) const WebRenderScrollData& aScrollData)
{ {
if (mDestroyed) {
return IPC_OK();
}
HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId, HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
aContentSize, dl, dlDesc, aScrollData); aContentSize, dl, dlDesc, aScrollData);
return IPC_OK(); return IPC_OK();
@ -695,6 +701,9 @@ WebRenderBridgeParent::RecvRemoveExternalImageId(const ExternalImageId& aImageId
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) WebRenderBridgeParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch)
{ {
if (mDestroyed) {
return IPC_OK();
}
mChildLayerObserverEpoch = aLayerObserverEpoch; mChildLayerObserverEpoch = aLayerObserverEpoch;
return IPC_OK(); return IPC_OK();
} }
@ -702,6 +711,9 @@ WebRenderBridgeParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverE
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvClearCachedResources() WebRenderBridgeParent::RecvClearCachedResources()
{ {
if (mDestroyed) {
return IPC_OK();
}
mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), false); mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), false);
return IPC_OK(); return IPC_OK();
} }
@ -732,6 +744,9 @@ mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId, WebRenderBridgeParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets) nsTArray<ScrollableLayerGuid>&& aTargets)
{ {
if (mDestroyed) {
return IPC_OK();
}
mCompositorBridge->SetConfirmedTargetAPZC(GetLayersId(), aBlockId, aTargets); mCompositorBridge->SetConfirmedTargetAPZC(GetLayersId(), aBlockId, aTargets);
return IPC_OK(); return IPC_OK();
} }
@ -741,6 +756,9 @@ WebRenderBridgeParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScr
const float& aX, const float& aX,
const float& aY) const float& aY)
{ {
if (mDestroyed) {
return IPC_OK();
}
RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aScrollId); RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aScrollId);
if (!apzc) { if (!apzc) {
return IPC_FAIL_NO_REASON(this); return IPC_FAIL_NO_REASON(this);
@ -753,6 +771,9 @@ mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollId, WebRenderBridgeParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollId,
const float& aZoom) const float& aZoom)
{ {
if (mDestroyed) {
return IPC_OK();
}
RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aScrollId); RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aScrollId);
if (!apzc) { if (!apzc) {
return IPC_FAIL_NO_REASON(this); return IPC_FAIL_NO_REASON(this);
@ -764,10 +785,20 @@ WebRenderBridgeParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollId,
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvFlushApzRepaints() WebRenderBridgeParent::RecvFlushApzRepaints()
{ {
if (mDestroyed) {
return IPC_OK();
}
mCompositorBridge->FlushApzRepaints(GetLayersId()); mCompositorBridge->FlushApzRepaints(GetLayersId());
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvGetAPZTestData(APZTestData* aOutData)
{
mCompositorBridge->GetAPZTestData(GetLayersId(), aOutData);
return IPC_OK();
}
void void
WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy) WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
{ {
@ -1067,6 +1098,9 @@ mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvNewCompositable(const CompositableHandle& aHandle, WebRenderBridgeParent::RecvNewCompositable(const CompositableHandle& aHandle,
const TextureInfo& aInfo) const TextureInfo& aInfo)
{ {
if (mDestroyed) {
return IPC_OK();
}
if (!AddCompositable(aHandle, aInfo)) { if (!AddCompositable(aHandle, aInfo)) {
return IPC_FAIL_NO_REASON(this); return IPC_FAIL_NO_REASON(this);
} }
@ -1076,6 +1110,9 @@ WebRenderBridgeParent::RecvNewCompositable(const CompositableHandle& aHandle,
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle) WebRenderBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle)
{ {
if (mDestroyed) {
return IPC_OK();
}
ReleaseCompositable(aHandle); ReleaseCompositable(aHandle);
return IPC_OK(); return IPC_OK();
} }
@ -1083,6 +1120,9 @@ WebRenderBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvInitReadLocks(ReadLockArray&& aReadLocks) WebRenderBridgeParent::RecvInitReadLocks(ReadLockArray&& aReadLocks)
{ {
if (mDestroyed) {
return IPC_OK();
}
if (!AddReadLocks(Move(aReadLocks))) { if (!AddReadLocks(Move(aReadLocks))) {
return IPC_FAIL_NO_REASON(this); return IPC_FAIL_NO_REASON(this);
} }

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

@ -126,6 +126,7 @@ public:
mozilla::ipc::IPCResult RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollId, mozilla::ipc::IPCResult RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollId,
const float& aZoom) override; const float& aZoom) override;
mozilla::ipc::IPCResult RecvFlushApzRepaints() override; mozilla::ipc::IPCResult RecvFlushApzRepaints() override;
mozilla::ipc::IPCResult RecvGetAPZTestData(APZTestData* data) override;
void ActorDestroy(ActorDestroyReason aWhy) override; void ActorDestroy(ActorDestroyReason aWhy) override;
void SetWebRenderProfilerEnabled(bool aEnabled); void SetWebRenderProfilerEnabled(bool aEnabled);

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

@ -20,6 +20,7 @@ namespace layers {
WebRenderCompositableHolder::AsyncImagePipelineHolder::AsyncImagePipelineHolder() WebRenderCompositableHolder::AsyncImagePipelineHolder::AsyncImagePipelineHolder()
: mInitialised(false) : mInitialised(false)
, mIsChanged(false) , mIsChanged(false)
, mUseExternalImage(false)
, mFilter(WrImageRendering::Auto) , mFilter(WrImageRendering::Auto)
, mMixBlendMode(WrMixBlendMode::Normal) , mMixBlendMode(WrMixBlendMode::Normal)
{} {}
@ -293,6 +294,7 @@ WebRenderCompositableHolder::UpdateImageKeys(wr::WebRenderAPI* aApi,
if (texture == aHolder->mCurrentTexture) { if (texture == aHolder->mCurrentTexture) {
// Reuse previous ImageKeys. // Reuse previous ImageKeys.
aKeys.AppendElements(aHolder->mKeys); aKeys.AppendElements(aHolder->mKeys);
aUseExternalImage = aHolder->mUseExternalImage;
return true; return true;
} }
@ -306,7 +308,7 @@ WebRenderCompositableHolder::UpdateImageKeys(wr::WebRenderAPI* aApi,
return true; return true;
} }
aUseExternalImage = GetImageKeyForTextureHost(aApi, texture, aKeys); aUseExternalImage = aHolder->mUseExternalImage = GetImageKeyForTextureHost(aApi, texture, aKeys);
MOZ_ASSERT(!aKeys.IsEmpty()); MOZ_ASSERT(!aKeys.IsEmpty());
aHolder->mKeys.AppendElements(aKeys); aHolder->mKeys.AppendElements(aKeys);
aHolder->mCurrentTexture = texture; aHolder->mCurrentTexture = texture;

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

@ -122,6 +122,7 @@ private:
bool mInitialised; bool mInitialised;
bool mIsChanged; bool mIsChanged;
bool mUseExternalImage;
LayerRect mScBounds; LayerRect mScBounds;
gfx::Matrix4x4 mScTransform; gfx::Matrix4x4 mScTransform;
gfx::MaybeIntSize mScaleToSize; gfx::MaybeIntSize mScaleToSize;

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

@ -32,6 +32,7 @@ WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
, mNeedsComposite(false) , mNeedsComposite(false)
, mIsFirstPaint(false) , mIsFirstPaint(false)
, mTarget(nullptr) , mTarget(nullptr)
, mPaintSequenceNumber(0)
{ {
MOZ_COUNT_CTOR(WebRenderLayerManager); MOZ_COUNT_CTOR(WebRenderLayerManager);
} }
@ -124,6 +125,13 @@ WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
bool bool
WebRenderLayerManager::BeginTransaction() WebRenderLayerManager::BeginTransaction()
{ {
// Increment the paint sequence number even if test logging isn't
// enabled in this process; it may be enabled in the parent process,
// and the parent process expects unique sequence numbers.
++mPaintSequenceNumber;
if (gfxPrefs::APZTestLoggingEnabled()) {
mApzTestData.StartNewPaint(mPaintSequenceNumber);
}
return true; return true;
} }
@ -209,6 +217,7 @@ WebRenderLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback
scrollData.SetIsFirstPaint(); scrollData.SetIsFirstPaint();
mIsFirstPaint = false; mIsFirstPaint = false;
} }
scrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
if (mRoot) { if (mRoot) {
PopulateScrollData(scrollData, mRoot.get()); PopulateScrollData(scrollData, mRoot.get());
} }

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

@ -8,6 +8,7 @@
#include "Layers.h" #include "Layers.h"
#include "mozilla/MozPromise.h" #include "mozilla/MozPromise.h"
#include "mozilla/layers/APZTestData.h"
#include "mozilla/layers/TransactionIdAllocator.h" #include "mozilla/layers/TransactionIdAllocator.h"
#include "mozilla/webrender/WebRenderTypes.h" #include "mozilla/webrender/WebRenderTypes.h"
@ -126,6 +127,16 @@ public:
void SetTransactionIncomplete() { mTransactionIncomplete = true; } void SetTransactionIncomplete() { mTransactionIncomplete = true; }
bool IsMutatedLayer(Layer* aLayer); bool IsMutatedLayer(Layer* aLayer);
// See equivalent function in ClientLayerManager
void LogTestDataForCurrentPaint(FrameMetrics::ViewID aScrollId,
const std::string& aKey,
const std::string& aValue) {
mApzTestData.LogTestDataForPaint(mPaintSequenceNumber, aScrollId, aKey, aValue);
}
// See equivalent function in ClientLayerManager
const APZTestData& GetAPZTestData() const
{ return mApzTestData; }
private: private:
/** /**
* Take a snapshot of the parent context, and copy * Take a snapshot of the parent context, and copy
@ -178,6 +189,11 @@ private:
// being drawn to the default target, and then copy those pixels // being drawn to the default target, and then copy those pixels
// back to mTarget. // back to mTarget.
RefPtr<gfxContext> mTarget; RefPtr<gfxContext> mTarget;
// See equivalent field in ClientLayerManager
uint32_t mPaintSequenceNumber;
// See equivalent field in ClientLayerManager
APZTestData mApzTestData;
}; };
} // namespace layers } // namespace layers

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

@ -80,6 +80,7 @@ WebRenderLayerScrollData::GetTransformTyped() const
WebRenderScrollData::WebRenderScrollData() WebRenderScrollData::WebRenderScrollData()
: mIsFirstPaint(false) : mIsFirstPaint(false)
, mPaintSequenceNumber(0)
{ {
} }
@ -151,5 +152,17 @@ WebRenderScrollData::IsFirstPaint() const
return mIsFirstPaint; return mIsFirstPaint;
} }
void
WebRenderScrollData::SetPaintSequenceNumber(uint32_t aPaintSequenceNumber)
{
mPaintSequenceNumber = aPaintSequenceNumber;
}
uint32_t
WebRenderScrollData::GetPaintSequenceNumber() const
{
return mPaintSequenceNumber;
}
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

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

@ -121,6 +121,8 @@ public:
void SetIsFirstPaint(); void SetIsFirstPaint();
bool IsFirstPaint() const; bool IsFirstPaint() const;
void SetPaintSequenceNumber(uint32_t aPaintSequenceNumber);
uint32_t GetPaintSequenceNumber() const;
friend struct IPC::ParamTraits<WebRenderScrollData>; friend struct IPC::ParamTraits<WebRenderScrollData>;
@ -146,6 +148,7 @@ private:
nsTArray<WebRenderLayerScrollData> mLayerScrollData; nsTArray<WebRenderLayerScrollData> mLayerScrollData;
bool mIsFirstPaint; bool mIsFirstPaint;
uint32_t mPaintSequenceNumber;
}; };
} // namespace layers } // namespace layers
@ -219,6 +222,7 @@ struct ParamTraits<mozilla::layers::WebRenderScrollData>
WriteParam(aMsg, aParam.mScrollMetadatas); WriteParam(aMsg, aParam.mScrollMetadatas);
WriteParam(aMsg, aParam.mLayerScrollData); WriteParam(aMsg, aParam.mLayerScrollData);
WriteParam(aMsg, aParam.mIsFirstPaint); WriteParam(aMsg, aParam.mIsFirstPaint);
WriteParam(aMsg, aParam.mPaintSequenceNumber);
} }
static bool static bool
@ -226,7 +230,8 @@ struct ParamTraits<mozilla::layers::WebRenderScrollData>
{ {
return ReadParam(aMsg, aIter, &aResult->mScrollMetadatas) return ReadParam(aMsg, aIter, &aResult->mScrollMetadatas)
&& ReadParam(aMsg, aIter, &aResult->mLayerScrollData) && ReadParam(aMsg, aIter, &aResult->mLayerScrollData)
&& ReadParam(aMsg, aIter, &aResult->mIsFirstPaint); && ReadParam(aMsg, aIter, &aResult->mIsFirstPaint)
&& ReadParam(aMsg, aIter, &aResult->mPaintSequenceNumber);
} }
}; };

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

@ -1048,6 +1048,8 @@ description =
description = test only description = test only
[PWebRenderBridge::SetAsyncZoom] [PWebRenderBridge::SetAsyncZoom]
description = test only description = test only
[PWebRenderBridge::GetAPZTestData]
description = test only
[PHal::GetCurrentBatteryInformation] [PHal::GetCurrentBatteryInformation]
description = description =
[PHal::GetCurrentNetworkInformation] [PHal::GetCurrentNetworkInformation]

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

@ -1,4 +1,3 @@
// |jit-test| allow-oom
if (getBuildConfiguration().debug === true) if (getBuildConfiguration().debug === true)
quit(0); quit(0);
function f(){}; function f(){};
@ -9,4 +8,4 @@ try {
} catch (e) { } catch (e) {
ex = e; ex = e;
} }
assertEq(ex instanceof InternalError, true); assertEq(ex === "out of memory" || (ex instanceof InternalError), true);

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

@ -33,7 +33,7 @@ class ArrayObject : public NativeObject
void setNonWritableLength(JSContext* cx) { void setNonWritableLength(JSContext* cx) {
if (getElementsHeader()->numShiftedElements() > 0) if (getElementsHeader()->numShiftedElements() > 0)
unshiftElements(); moveShiftedElements();
// When an array's length becomes non-writable, writes to indexes // When an array's length becomes non-writable, writes to indexes
// greater than or equal to the length don't change the array. We // greater than or equal to the length don't change the array. We

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

@ -185,7 +185,7 @@ NativeObject::tryShiftDenseElements(uint32_t count)
MOZ_ASSERT(count < header->initializedLength); MOZ_ASSERT(count < header->initializedLength);
if (MOZ_UNLIKELY(header->numShiftedElements() + count > ObjectElements::MaxShiftedElements)) { if (MOZ_UNLIKELY(header->numShiftedElements() + count > ObjectElements::MaxShiftedElements)) {
unshiftElements(); moveShiftedElements();
header = getElementsHeader(); header = getElementsHeader();
} }

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

@ -115,7 +115,7 @@ ObjectElements::FreezeElements(JSContext* cx, HandleNativeObject obj)
return true; return true;
if (obj->getElementsHeader()->numShiftedElements() > 0) if (obj->getElementsHeader()->numShiftedElements() > 0)
obj->unshiftElements(); obj->moveShiftedElements();
ObjectElements* header = obj->getElementsHeader(); ObjectElements* header = obj->getElementsHeader();
@ -707,7 +707,7 @@ NativeObject::maybeDensifySparseElements(JSContext* cx, HandleNativeObject obj)
} }
void void
NativeObject::unshiftElements() NativeObject::moveShiftedElements()
{ {
ObjectElements* header = getElementsHeader(); ObjectElements* header = getElementsHeader();
uint32_t numShifted = header->numShiftedElements(); uint32_t numShifted = header->numShiftedElements();
@ -723,7 +723,7 @@ NativeObject::unshiftElements()
elements_ = newHeader->elements(); elements_ = newHeader->elements();
// To move the elements, temporarily update initializedLength to include // To move the elements, temporarily update initializedLength to include
// both shifted and unshifted elements. // the shifted elements.
newHeader->initializedLength += numShifted; newHeader->initializedLength += numShifted;
// Move the elements. Initialize to |undefined| to ensure pre-barriers // Move the elements. Initialize to |undefined| to ensure pre-barriers
@ -739,14 +739,14 @@ NativeObject::unshiftElements()
} }
void void
NativeObject::maybeUnshiftElements() NativeObject::maybeMoveShiftedElements()
{ {
ObjectElements* header = getElementsHeader(); ObjectElements* header = getElementsHeader();
MOZ_ASSERT(header->numShiftedElements() > 0); MOZ_ASSERT(header->numShiftedElements() > 0);
// Unshift if less than a third of the allocated space is in use. // Move the elements if less than a third of the allocated space is in use.
if (header->capacity < header->numAllocatedElements() / 3) if (header->capacity < header->numAllocatedElements() / 3)
unshiftElements(); moveShiftedElements();
} }
// Given a requested capacity (in elements) and (potentially) the length of an // Given a requested capacity (in elements) and (potentially) the length of an
@ -847,22 +847,31 @@ NativeObject::growElements(JSContext* cx, uint32_t reqCapacity)
if (denseElementsAreCopyOnWrite()) if (denseElementsAreCopyOnWrite())
MOZ_CRASH(); MOZ_CRASH();
// If there are shifted elements, consider unshifting them first. If we // If there are shifted elements, consider moving them first. If we don't
// don't unshift here, the code below will include the shifted elements in // move them here, the code below will include the shifted elements in the
// the resize. // resize.
uint32_t numShifted = getElementsHeader()->numShiftedElements(); uint32_t numShifted = getElementsHeader()->numShiftedElements();
if (numShifted > 0) { if (numShifted > 0) {
maybeUnshiftElements(); // If the number of elements is small, it's cheaper to just move them as
// it may avoid a malloc/realloc. Note that there's no technical reason
// for using this particular value, but it works well in real-world use
// cases.
static const size_t MaxElementsToMoveEagerly = 20;
if (getElementsHeader()->initializedLength <= MaxElementsToMoveEagerly)
moveShiftedElements();
else
maybeMoveShiftedElements();
if (getDenseCapacity() >= reqCapacity) if (getDenseCapacity() >= reqCapacity)
return true; return true;
numShifted = getElementsHeader()->numShiftedElements(); numShifted = getElementsHeader()->numShiftedElements();
// Ensure |reqCapacity + numShifted| below won't overflow by forcing an // If |reqCapacity + numShifted| overflows, we just move all shifted
// unshift in that case. // elements to avoid the problem.
CheckedInt<uint32_t> checkedReqCapacity(reqCapacity); CheckedInt<uint32_t> checkedReqCapacity(reqCapacity);
checkedReqCapacity += numShifted; checkedReqCapacity += numShifted;
if (MOZ_UNLIKELY(!checkedReqCapacity.isValid())) { if (MOZ_UNLIKELY(!checkedReqCapacity.isValid())) {
unshiftElements(); moveShiftedElements();
numShifted = 0; numShifted = 0;
} }
} }
@ -932,10 +941,10 @@ NativeObject::shrinkElements(JSContext* cx, uint32_t reqCapacity)
if (!hasDynamicElements()) if (!hasDynamicElements())
return; return;
// If we have shifted elements, consider unshifting them. // If we have shifted elements, consider moving them.
uint32_t numShifted = getElementsHeader()->numShiftedElements(); uint32_t numShifted = getElementsHeader()->numShiftedElements();
if (numShifted > 0) { if (numShifted > 0) {
maybeUnshiftElements(); maybeMoveShiftedElements();
numShifted = getElementsHeader()->numShiftedElements(); numShifted = getElementsHeader()->numShiftedElements();
} }

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

@ -170,7 +170,7 @@ ArraySetLength(JSContext* cx, Handle<ArrayObject*> obj, HandleId id,
* to the next element and moving the ObjectElements header in memory (so it's * to the next element and moving the ObjectElements header in memory (so it's
* stored where the shifted Value used to be). * stored where the shifted Value used to be).
* *
* Shifted elements can be unshifted when we grow the array, when the array is * Shifted elements can be moved when we grow the array, when the array is
* frozen (for simplicity, shifted elements are not supported on objects that * frozen (for simplicity, shifted elements are not supported on objects that
* are frozen, have copy-on-write elements, or on arrays with non-writable * are frozen, have copy-on-write elements, or on arrays with non-writable
* length). * length).
@ -205,7 +205,7 @@ class ObjectElements
}; };
// The flags word stores both the flags and the number of shifted elements. // The flags word stores both the flags and the number of shifted elements.
// Allow shifting 2047 elements before unshifting. // Allow shifting 2047 elements before actually moving the elements.
static const size_t NumShiftedElementsBits = 11; static const size_t NumShiftedElementsBits = 11;
static const size_t MaxShiftedElements = (1 << NumShiftedElementsBits) - 1; static const size_t MaxShiftedElements = (1 << NumShiftedElementsBits) - 1;
static const size_t NumShiftedElementsShift = 32 - NumShiftedElementsBits; static const size_t NumShiftedElementsShift = 32 - NumShiftedElementsBits;
@ -1074,11 +1074,12 @@ class NativeObject : public ShapedObject
// Try to shift |count| dense elements, see the "Shifted elements" comment. // Try to shift |count| dense elements, see the "Shifted elements" comment.
inline bool tryShiftDenseElements(uint32_t count); inline bool tryShiftDenseElements(uint32_t count);
// Unshift all shifted elements so that numShiftedElements is 0. // Move the elements header and all shifted elements to the start of the
void unshiftElements(); // allocated elements space, so that numShiftedElements is 0 afterwards.
void moveShiftedElements();
// If this object has many shifted elements, unshift them. // If this object has many shifted elements call moveShiftedElements.
void maybeUnshiftElements(); void maybeMoveShiftedElements();
static bool goodElementsAllocationAmount(JSContext* cx, uint32_t reqAllocated, static bool goodElementsAllocationAmount(JSContext* cx, uint32_t reqAllocated,
uint32_t length, uint32_t* goodAmount); uint32_t length, uint32_t* goodAmount);

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

@ -20,6 +20,22 @@
#include <prio.h> #include <prio.h>
namespace mozilla { namespace mozilla {
// A specialization of GenericErrorResult which auto-converts to a nsresult.
// This should be removed when bug 1366511 is fixed.
template <>
class MOZ_MUST_USE_TYPE GenericErrorResult<nsresult>
{
nsresult mErrorValue;
template<typename V, typename E2> friend class Result;
public:
explicit GenericErrorResult(nsresult aErrorValue) : mErrorValue(aErrorValue) {}
operator nsresult() { return mErrorValue; }
};
namespace loader { namespace loader {
using mozilla::dom::AutoJSAPI; using mozilla::dom::AutoJSAPI;

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

@ -39,6 +39,9 @@
#include "nsXULAppAPI.h" #include "nsXULAppAPI.h"
#include "WrapperFactory.h" #include "WrapperFactory.h"
#include "AutoMemMap.h"
#include "ScriptPreloader-inl.h"
#include "mozilla/AddonPathService.h" #include "mozilla/AddonPathService.h"
#include "mozilla/scache/StartupCache.h" #include "mozilla/scache/StartupCache.h"
#include "mozilla/scache/StartupCacheUtils.h" #include "mozilla/scache/StartupCacheUtils.h"
@ -51,6 +54,7 @@
using namespace mozilla; using namespace mozilla;
using namespace mozilla::scache; using namespace mozilla::scache;
using namespace mozilla::loader;
using namespace xpc; using namespace xpc;
using namespace JS; using namespace JS;
@ -506,25 +510,6 @@ mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
aGlobal.set(global); aGlobal.set(global);
} }
// Some stack based classes for cleaning up on early return
class FileAutoCloser
{
public:
explicit FileAutoCloser(PRFileDesc* file) : mFile(file) {}
~FileAutoCloser() { PR_Close(mFile); }
private:
PRFileDesc* mFile;
};
class FileMapAutoCloser
{
public:
explicit FileMapAutoCloser(PRFileMap* map) : mMap(map) {}
~FileMapAutoCloser() { PR_CloseFileMap(mMap); }
private:
PRFileMap* mMap;
};
JSObject* JSObject*
mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx, mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
nsIFile* aComponentFile, nsIFile* aComponentFile,
@ -671,54 +656,13 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
.setSourceIsLazy(!!cache); .setSourceIsLazy(!!cache);
if (realFile) { if (realFile) {
int64_t fileSize; AutoMemMap map;
rv = aComponentFile->GetFileSize(&fileSize); MOZ_TRY(map.init(aComponentFile));
if (NS_FAILED(rv)) {
return rv;
}
int64_t maxSize = UINT32_MAX;
if (fileSize > maxSize) {
NS_ERROR("file too large");
return NS_ERROR_FAILURE;
}
PRFileDesc* fileHandle;
rv = aComponentFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
if (NS_FAILED(rv)) {
return NS_ERROR_FILE_NOT_FOUND;
}
// Make sure the file is closed, no matter how we return.
FileAutoCloser fileCloser(fileHandle);
// We don't provide the file size here. If we did, PR_CreateFileMap
// would simply stat() the file to verify that the size we provided
// didn't require extending the file. We know that the file doesn't
// need to be extended, so skip the extra work by not providing the
// size.
PRFileMap* map = PR_CreateFileMap(fileHandle, 0, PR_PROT_READONLY);
if (!map) {
NS_ERROR("Failed to create file map");
return NS_ERROR_FAILURE;
}
// Make sure the file map is closed, no matter how we return.
FileMapAutoCloser mapCloser(map);
uint32_t fileSize32 = fileSize;
char* buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
if (!buf) {
NS_WARNING("Failed to map file");
return NS_ERROR_FAILURE;
}
// Note: exceptions will get handled further down; // Note: exceptions will get handled further down;
// don't early return for them here. // don't early return for them here.
Compile(cx, options, buf, fileSize32, &script); auto buf = map.get<char>();
Compile(cx, options, buf.get(), map.size(), &script);
PR_MemUnmap(buf, fileSize32);
} else { } else {
rv = aInfo.EnsureScriptChannel(); rv = aInfo.EnsureScriptChannel();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

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

@ -9,9 +9,14 @@ add_task(function* test() {
const url = "http://mochi.test:8888/browser/js/xpconnect/tests/browser/browser_deadObjectOnUnload.html"; const url = "http://mochi.test:8888/browser/js/xpconnect/tests/browser/browser_deadObjectOnUnload.html";
let newTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url); let newTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let browser = gBrowser.selectedBrowser; let browser = gBrowser.selectedBrowser;
let contentDocDead = yield ContentTask.spawn(browser,{}, function*(browser){ let innerWindowId = browser.innerWindowID;
let contentDocDead = yield ContentTask.spawn(browser,{innerWindowId}, function*(args){
let doc = content.document; let doc = content.document;
let promise = ContentTaskUtils.waitForEvent(this, "DOMContentLoaded", true); let {TestUtils} = Components.utils.import("resource://testing-common/TestUtils.jsm", {});
let promise = TestUtils.topicObserved("inner-window-destroyed", (subject, data) => {
let id = subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data;
return id == args.innerWindowId;
});
content.location = "about:home"; content.location = "about:home";
yield promise; yield promise;
return Components.utils.isDeadWrapper(doc); return Components.utils.isDeadWrapper(doc);

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

@ -122,6 +122,7 @@
#include "RegionBuilder.h" #include "RegionBuilder.h"
#include "SVGSVGElement.h" #include "SVGSVGElement.h"
#include "DisplayItemClip.h" #include "DisplayItemClip.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#ifdef MOZ_XUL #ifdef MOZ_XUL
#include "nsXULPopupManager.h" #include "nsXULPopupManager.h"
@ -8508,6 +8509,8 @@ nsLayoutUtils::DoLogTestDataForPaint(LayerManager* aManager,
{ {
if (ClientLayerManager* mgr = aManager->AsClientLayerManager()) { if (ClientLayerManager* mgr = aManager->AsClientLayerManager()) {
mgr->LogTestDataForCurrentPaint(aScrollId, aKey, aValue); mgr->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
} else if (WebRenderLayerManager* wrlm = aManager->AsWebRenderLayerManager()) {
wrlm->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
} }
} }

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

@ -12,11 +12,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
XPCOMUtils.defineLazyModuleGetter(this, "PageActions", XPCOMUtils.defineLazyModuleGetter(this, "PageActions",
"resource://gre/modules/PageActions.jsm"); "resource://gre/modules/PageActions.jsm");
Cu.import("resource://gre/modules/ExtensionUtils.jsm"); Cu.import("resource://gre/modules/ExtensionParent.jsm");
var { var {
IconDetails, IconDetails,
} = ExtensionUtils; } = ExtensionParent;
// WeakMap[Extension -> PageAction] // WeakMap[Extension -> PageAction]
var pageActionMap = new WeakMap(); var pageActionMap = new WeakMap();

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

@ -5,13 +5,11 @@
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource://gre/modules/ExtensionUtils.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/Services.jsm');
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let { PlatformInfo } = ExtensionUtils; if (AppConstants.platform == "android" && !Services.prefs.getBoolPref("network.mdns.use_js_fallback")) {
if (PlatformInfo.os == "android" && !Services.prefs.getBoolPref("network.mdns.use_js_fallback")) {
Cu.import("resource://gre/modules/MulticastDNSAndroid.jsm"); Cu.import("resource://gre/modules/MulticastDNSAndroid.jsm");
} else { } else {
Cu.import("resource://gre/modules/MulticastDNS.jsm"); Cu.import("resource://gre/modules/MulticastDNS.jsm");

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

@ -1,3 +1,2 @@
[display-none.html] [display-none.html]
type: testharness type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318

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

@ -1,4 +1,2 @@
[iframe-no-root.html] [iframe-no-root.html]
type: testharness type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318

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

@ -1,3 +1,2 @@
[multiple-thresholds.html] [multiple-thresholds.html]
type: testharness type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318

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

@ -1,3 +1,2 @@
[root-margin.html] [root-margin.html]
type: testharness type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318

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

@ -1,3 +1,2 @@
[same-document-no-root.html] [same-document-no-root.html]
type: testharness type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318

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

@ -1,3 +1,2 @@
[same-document-zero-size-target.html] [same-document-zero-size-target.html]
type: testharness type: testharness
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318

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

@ -1,4 +1,3 @@
[shadow-content.html] [shadow-content.html]
type: testharness type: testharness
prefs: [dom.webcomponents.enabled:true] prefs: [dom.webcomponents.enabled:true]
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1359318

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

@ -7,6 +7,7 @@ module.exports = {
"Ci": true, "Ci": true,
"Cr": true, "Cr": true,
"Cu": true, "Cu": true,
"StructuredCloneHolder": false,
"TextDecoder": false, "TextDecoder": false,
"TextEncoder": false, "TextEncoder": false,
@ -20,6 +21,7 @@ module.exports = {
"AppConstants": true, "AppConstants": true,
"Extension": true, "Extension": true,
"ExtensionAPI": true, "ExtensionAPI": true,
"ExtensionCommon": true,
"ExtensionManagement": true, "ExtensionManagement": true,
"ExtensionUtils": true, "ExtensionUtils": true,
"extensions": true, "extensions": true,

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

@ -97,13 +97,12 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
var { var {
GlobalManager, GlobalManager,
ParentAPIManager, ParentAPIManager,
StartupCache,
apiManager: Management, apiManager: Management,
} = ExtensionParent; } = ExtensionParent;
const { const {
classifyPermission,
EventEmitter, EventEmitter,
StartupCache,
getUniqueId, getUniqueId,
} = ExtensionUtils; } = ExtensionUtils;
@ -145,6 +144,29 @@ function validateThemeManifest(manifestProperties) {
return invalidProps; return invalidProps;
} }
/**
* Classify an individual permission from a webextension manifest
* as a host/origin permission, an api permission, or a regular permission.
*
* @param {string} perm The permission string to classify
*
* @returns {object}
* An object with exactly one of the following properties:
* "origin" to indicate this is a host/origin permission.
* "api" to indicate this is an api permission
* (as used for webextensions experiments).
* "permission" to indicate this is a regular permission.
*/
function classifyPermission(perm) {
let match = /^(\w+)(?:\.(\w+)(?:\.\w+)*)?$/.exec(perm);
if (!match) {
return {origin: perm};
} else if (match[1] == "experiments" && match[2]) {
return {api: match[2]};
}
return {permission: perm};
}
const LOGGER_ID_BASE = "addons.webextension."; const LOGGER_ID_BASE = "addons.webextension.";
const UUID_MAP_PREF = "extensions.webextensions.uuids"; const UUID_MAP_PREF = "extensions.webextensions.uuids";
const LEAVE_STORAGE_PREF = "extensions.webextensions.keepStorageOnUninstall"; const LEAVE_STORAGE_PREF = "extensions.webextensions.keepStorageOnUninstall";

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

@ -40,22 +40,41 @@ const {
DefaultMap, DefaultMap,
EventEmitter, EventEmitter,
LimitedSet, LimitedSet,
SpreadArgs,
defineLazyGetter, defineLazyGetter,
getMessageManager, getMessageManager,
getUniqueId, getUniqueId,
injectAPI,
} = ExtensionUtils; } = ExtensionUtils;
const { const {
LocalAPIImplementation, LocalAPIImplementation,
LocaleData, LocaleData,
NoCloneSpreadArgs,
SchemaAPIInterface, SchemaAPIInterface,
SingletonEventManager, SingletonEventManager,
} = ExtensionCommon; } = ExtensionCommon;
const isContentProcess = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT; const isContentProcess = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
// Copy an API object from |source| into the scope |dest|.
function injectAPI(source, dest) {
for (let prop in source) {
// Skip names prefixed with '_'.
if (prop[0] == "_") {
continue;
}
let desc = Object.getOwnPropertyDescriptor(source, prop);
if (typeof(desc.value) == "function") {
Cu.exportFunction(desc.value, dest, {defineAs: prop});
} else if (typeof(desc.value) == "object") {
let obj = Cu.createObjectIn(dest, {defineAs: prop});
injectAPI(desc.value, obj);
} else {
Object.defineProperty(dest, prop, desc);
}
}
}
/** /**
* Abstraction for a Port object in the extension API. * Abstraction for a Port object in the extension API.
* *
@ -115,15 +134,16 @@ class Port {
}, },
onDisconnect: new SingletonEventManager(this.context, "Port.onDisconnect", fire => { onDisconnect: new SingletonEventManager(this.context, "Port.onDisconnect", fire => {
return this.registerOnDisconnect(error => { return this.registerOnDisconnect(holder => {
let error = holder.deserialize(this.context.cloneScope);
portError = error && this.context.normalizeError(error); portError = error && this.context.normalizeError(error);
fire.asyncWithoutClone(portObj); fire.asyncWithoutClone(portObj);
}); });
}).api(), }).api(),
onMessage: new SingletonEventManager(this.context, "Port.onMessage", fire => { onMessage: new SingletonEventManager(this.context, "Port.onMessage", fire => {
return this.registerOnMessage(msg => { return this.registerOnMessage(holder => {
msg = Cu.cloneInto(msg, this.context.cloneScope); let msg = holder.deserialize(this.context.cloneScope);
fire.asyncWithoutClone(msg, portObj); fire.asyncWithoutClone(msg, portObj);
}); });
}).api(), }).api(),
@ -202,7 +222,9 @@ class Port {
responseType: MessageChannel.RESPONSE_NONE, responseType: MessageChannel.RESPONSE_NONE,
}; };
return this.context.sendMessage(this.senderMM, message, data, options); let holder = new StructuredCloneHolder(data);
return this.context.sendMessage(this.senderMM, message, holder, options);
} }
handleDisconnection() { handleDisconnection() {
@ -307,7 +329,9 @@ class Messenger {
} }
sendMessage(messageManager, msg, recipient, responseCallback) { sendMessage(messageManager, msg, recipient, responseCallback) {
let promise = this._sendMessage(messageManager, "Extension:Message", msg, recipient) let holder = new StructuredCloneHolder(msg);
let promise = this._sendMessage(messageManager, "Extension:Message", holder, recipient)
.catch(error => { .catch(error => {
if (error.result == MessageChannel.RESULT_NO_HANDLER) { if (error.result == MessageChannel.RESULT_NO_HANDLER) {
return Promise.reject({message: "Could not establish connection. Receiving end does not exist."}); return Promise.reject({message: "Could not establish connection. Receiving end does not exist."});
@ -336,7 +360,7 @@ class Messenger {
filter(sender, recipient)); filter(sender, recipient));
}, },
receiveMessage: ({target, data: message, sender, recipient}) => { receiveMessage: ({target, data: holder, sender, recipient}) => {
if (!this.context.active) { if (!this.context.active) {
return; return;
} }
@ -350,7 +374,7 @@ class Messenger {
}; };
}); });
message = Cu.cloneInto(message, this.context.cloneScope); let message = holder.deserialize(this.context.cloneScope);
sender = Cu.cloneInto(sender, this.context.cloneScope); sender = Cu.cloneInto(sender, this.context.cloneScope);
sendResponse = Cu.exportFunction(sendResponse, this.context.cloneScope); sendResponse = Cu.exportFunction(sendResponse, this.context.cloneScope);
@ -393,7 +417,7 @@ class Messenger {
} else if (error.result === MessageChannel.RESULT_DISCONNECTED) { } else if (error.result === MessageChannel.RESULT_DISCONNECTED) {
error = null; error = null;
} }
port.disconnectByOtherEnd(error); port.disconnectByOtherEnd(new StructuredCloneHolder(error));
}); });
return port.api(); return port.api();
@ -734,7 +758,9 @@ class ChildAPIManager {
let listener = map.ids.get(data.listenerId); let listener = map.ids.get(data.listenerId);
if (listener) { if (listener) {
return this.context.runSafe(listener, ...data.args); let args = data.args.deserialize(this.context.cloneScope);
return this.context.runSafeWithoutClone(listener, ...args);
} }
if (!map.removedIds.has(data.listenerId)) { if (!map.removedIds.has(data.listenerId)) {
Services.console.logStringMessage( Services.console.logStringMessage(
@ -747,7 +773,9 @@ class ChildAPIManager {
if ("error" in data) { if ("error" in data) {
deferred.reject(data.error); deferred.reject(data.error);
} else { } else {
deferred.resolve(new SpreadArgs(data.result)); let result = data.result.deserialize(this.context.cloneScope);
deferred.resolve(new NoCloneSpreadArgs(result));
} }
this.callPromises.delete(data.callId); this.callPromises.delete(data.callId);
break; break;

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

@ -29,6 +29,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
XPCOMUtils.defineLazyModuleGetter(this, "Schemas", XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
"resource://gre/modules/Schemas.jsm"); "resource://gre/modules/Schemas.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
"@mozilla.org/content/style-sheet-service;1",
"nsIStyleSheetService");
Cu.import("resource://gre/modules/ExtensionUtils.jsm"); Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var { var {
@ -36,7 +40,6 @@ var {
DefaultWeakMap, DefaultWeakMap,
EventEmitter, EventEmitter,
ExtensionError, ExtensionError,
SpreadArgs,
defineLazyGetter, defineLazyGetter,
getConsole, getConsole,
getInnerWindowID, getInnerWindowID,
@ -48,6 +51,39 @@ var {
XPCOMUtils.defineLazyGetter(this, "console", getConsole); XPCOMUtils.defineLazyGetter(this, "console", getConsole);
var ExtensionCommon;
/**
* A sentinel class to indicate that an array of values should be
* treated as an array when used as a promise resolution value, but as a
* spread expression (...args) when passed to a callback.
*/
class SpreadArgs extends Array {
constructor(args) {
super();
this.push(...args);
}
}
/**
* Like SpreadArgs, but also indicates that the array values already
* belong to the target compartment, and should not be cloned before
* being passed.
*
* The `unwrappedValues` property contains an Array object which belongs
* to the target compartment, and contains the same unwrapped values
* passed the NoCloneSpreadArgs constructor.
*/
class NoCloneSpreadArgs {
constructor(args) {
this.unwrappedValues = args;
}
[Symbol.iterator]() {
return this.unwrappedValues[Symbol.iterator]();
}
}
class BaseContext { class BaseContext {
constructor(envType, extension) { constructor(envType, extension) {
this.envType = envType; this.envType = envType;
@ -311,6 +347,8 @@ class BaseContext {
dump(`Promise resolved after context unloaded\n`); dump(`Promise resolved after context unloaded\n`);
} else if (!this.active) { } else if (!this.active) {
dump(`Promise resolved while context is inactive\n`); dump(`Promise resolved while context is inactive\n`);
} else if (args instanceof NoCloneSpreadArgs) {
this.runSafeWithoutClone(callback, ...args.unwrappedValues);
} else if (args instanceof SpreadArgs) { } else if (args instanceof SpreadArgs) {
runSafe(callback, ...args); runSafe(callback, ...args);
} else { } else {
@ -336,6 +374,9 @@ class BaseContext {
dump(`Promise resolved after context unloaded\n`); dump(`Promise resolved after context unloaded\n`);
} else if (!this.active) { } else if (!this.active) {
dump(`Promise resolved while context is inactive\n`); dump(`Promise resolved while context is inactive\n`);
} else if (value instanceof NoCloneSpreadArgs) {
let values = value.unwrappedValues;
this.runSafeWithoutClone(resolve, values.length == 1 ? values[0] : values);
} else if (value instanceof SpreadArgs) { } else if (value instanceof SpreadArgs) {
runSafe(resolve, value.length == 1 ? value[0] : value); runSafe(resolve, value.length == 1 ? value[0] : value);
} else { } else {
@ -1067,7 +1108,7 @@ class SchemaAPIManager extends EventEmitter {
sandboxName: `Namespace of ext-*.js scripts for ${this.processType}`, sandboxName: `Namespace of ext-*.js scripts for ${this.processType}`,
}); });
Object.assign(global, {global, Cc, Ci, Cu, Cr, XPCOMUtils, ChromeWorker, MatchPattern, MatchPatternSet, extensions: this}); Object.assign(global, {global, Cc, Ci, Cu, Cr, XPCOMUtils, ChromeWorker, ExtensionCommon, MatchPattern, MatchPatternSet, extensions: this});
Cu.import("resource://gre/modules/AppConstants.jsm", global); Cu.import("resource://gre/modules/AppConstants.jsm", global);
Cu.import("resource://gre/modules/ExtensionAPI.jsm", global); Cu.import("resource://gre/modules/ExtensionAPI.jsm", global);
@ -1443,13 +1484,44 @@ SingletonEventManager.prototype = {
}, },
}; };
// Simple API for event listeners where events never fire.
function ignoreEvent(context, name) {
return {
addListener: function(callback) {
let id = context.extension.id;
let frame = Components.stack.caller;
let msg = `In add-on ${id}, attempting to use listener "${name}", which is unimplemented.`;
let scriptError = Cc["@mozilla.org/scripterror;1"]
.createInstance(Ci.nsIScriptError);
scriptError.init(msg, frame.filename, null, frame.lineNumber,
frame.columnNumber, Ci.nsIScriptError.warningFlag,
"content javascript");
let consoleService = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
consoleService.logMessage(scriptError);
},
removeListener: function(callback) {},
hasListener: function(callback) {},
};
}
const ExtensionCommon = {
const stylesheetMap = new DefaultMap(url => {
let uri = Services.io.newURI(url);
return styleSheetService.preloadSheet(uri, styleSheetService.AGENT_SHEET);
});
ExtensionCommon = {
BaseContext, BaseContext,
CanOfAPIs, CanOfAPIs,
LocalAPIImplementation, LocalAPIImplementation,
LocaleData, LocaleData,
NoCloneSpreadArgs,
SchemaAPIInterface, SchemaAPIInterface,
SchemaAPIManager, SchemaAPIManager,
SingletonEventManager, SingletonEventManager,
SpreadArgs,
ignoreEvent,
stylesheetMap,
}; };

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

@ -24,6 +24,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm"); "resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils", XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
"resource:///modules/E10SUtils.jsm"); "resource:///modules/E10SUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IndexedDB",
"resource://gre/modules/IndexedDB.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel", XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
"resource://gre/modules/MessageChannel.jsm"); "resource://gre/modules/MessageChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NativeApp", XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
@ -46,12 +48,13 @@ var {
BaseContext, BaseContext,
CanOfAPIs, CanOfAPIs,
SchemaAPIManager, SchemaAPIManager,
SpreadArgs,
} = ExtensionCommon; } = ExtensionCommon;
var { var {
DefaultWeakMap, DefaultWeakMap,
ExtensionError,
MessageManagerProxy, MessageManagerProxy,
SpreadArgs,
defineLazyGetter, defineLazyGetter,
promiseDocumentLoaded, promiseDocumentLoaded,
promiseEvent, promiseEvent,
@ -619,7 +622,9 @@ ParentAPIManager = {
result.then(result => { result.then(result => {
result = result instanceof SpreadArgs ? [...result] : [result]; result = result instanceof SpreadArgs ? [...result] : [result];
reply({result}); let holder = new StructuredCloneHolder(result);
reply({result: holder});
}, error => { }, error => {
error = context.normalizeError(error); error = context.normalizeError(error);
reply({error: {message: error.message, fileName: error.fileName}}); reply({error: {message: error.message, fileName: error.fileName}});
@ -651,7 +656,7 @@ ParentAPIManager = {
childId, childId,
listenerId: data.listenerId, listenerId: data.listenerId,
path: data.path, path: data.path,
args: listenerArgs, args: new StructuredCloneHolder(listenerArgs),
}, },
{ {
recipient: {childId}, recipient: {childId},
@ -1070,11 +1075,305 @@ function extensionNameFromURI(uri) {
return GlobalManager.getExtension(id).name; return GlobalManager.getExtension(id).name;
} }
const ExtensionParent = { const INTEGER = /^[1-9]\d*$/;
// Manages icon details for toolbar buttons in the |pageAction| and
// |browserAction| APIs.
let IconDetails = {
// WeakMap<Extension -> Map<url-string -> object>>
iconCache: new DefaultWeakMap(() => new Map()),
// Normalizes the various acceptable input formats into an object
// with icon size as key and icon URL as value.
//
// If a context is specified (function is called from an extension):
// Throws an error if an invalid icon size was provided or the
// extension is not allowed to load the specified resources.
//
// If no context is specified, instead of throwing an error, this
// function simply logs a warning message.
normalize(details, extension, context = null) {
if (!details.imageData && typeof details.path === "string") {
let icons = this.iconCache.get(extension);
let baseURI = context ? context.uri : extension.baseURI;
let url = baseURI.resolve(details.path);
let icon = icons.get(url);
if (!icon) {
icon = this._normalize(details, extension, context);
icons.set(url, icon);
}
return icon;
}
return this._normalize(details, extension, context);
},
_normalize(details, extension, context = null) {
let result = {};
try {
if (details.imageData) {
let imageData = details.imageData;
if (typeof imageData == "string") {
imageData = {"19": imageData};
}
for (let size of Object.keys(imageData)) {
if (!INTEGER.test(size)) {
throw new ExtensionError(`Invalid icon size ${size}, must be an integer`);
}
result[size] = imageData[size];
}
}
if (details.path) {
let path = details.path;
if (typeof path != "object") {
path = {"19": path};
}
let baseURI = context ? context.uri : extension.baseURI;
for (let size of Object.keys(path)) {
if (!INTEGER.test(size)) {
throw new ExtensionError(`Invalid icon size ${size}, must be an integer`);
}
let url = baseURI.resolve(path[size]);
// The Chrome documentation specifies these parameters as
// relative paths. We currently accept absolute URLs as well,
// which means we need to check that the extension is allowed
// to load them. This will throw an error if it's not allowed.
try {
Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
extension.principal, url,
Services.scriptSecurityManager.DISALLOW_SCRIPT);
} catch (e) {
throw new ExtensionError(`Illegal URL ${url}`);
}
result[size] = url;
}
}
} catch (e) {
// Function is called from extension code, delegate error.
if (context) {
throw e;
}
// If there's no context, it's because we're handling this
// as a manifest directive. Log a warning rather than
// raising an error.
extension.manifestError(`Invalid icon data: ${e}`);
}
return result;
},
// Returns the appropriate icon URL for the given icons object and the
// screen resolution of the given window.
getPreferredIcon(icons, extension = null, size = 16) {
const DEFAULT = "chrome://browser/content/extension.svg";
let bestSize = null;
if (icons[size]) {
bestSize = size;
} else if (icons[2 * size]) {
bestSize = 2 * size;
} else {
let sizes = Object.keys(icons)
.map(key => parseInt(key, 10))
.sort((a, b) => a - b);
bestSize = sizes.find(candidate => candidate > size) || sizes.pop();
}
if (bestSize) {
return {size: bestSize, icon: icons[bestSize]};
}
return {size, icon: DEFAULT};
},
convertImageURLToDataURL(imageURL, contentWindow, browserWindow, size = 18) {
return new Promise((resolve, reject) => {
let image = new contentWindow.Image();
image.onload = function() {
let canvas = contentWindow.document.createElement("canvas");
let ctx = canvas.getContext("2d");
let dSize = size * browserWindow.devicePixelRatio;
// Scales the image while maintaing width to height ratio.
// If the width and height differ, the image is centered using the
// smaller of the two dimensions.
let dWidth, dHeight, dx, dy;
if (this.width > this.height) {
dWidth = dSize;
dHeight = image.height * (dSize / image.width);
dx = 0;
dy = (dSize - dHeight) / 2;
} else {
dWidth = image.width * (dSize / image.height);
dHeight = dSize;
dx = (dSize - dWidth) / 2;
dy = 0;
}
canvas.width = dSize;
canvas.height = dSize;
ctx.drawImage(this, 0, 0, this.width, this.height, dx, dy, dWidth, dHeight);
resolve(canvas.toDataURL("image/png"));
};
image.onerror = reject;
image.src = imageURL;
});
},
// These URLs should already be properly escaped, but make doubly sure CSS
// string escape characters are escaped here, since they could lead to a
// sandbox break.
escapeUrl(url) {
return url.replace(/[\\\s"]/g, encodeURIComponent);
},
};
let StartupCache = {
DB_NAME: "ExtensionStartupCache",
SCHEMA_VERSION: 2,
STORE_NAMES: Object.freeze(["locales", "manifests", "schemas"]),
dbPromise: null,
initDB(db) {
for (let name of StartupCache.STORE_NAMES) {
try {
db.deleteObjectStore(name);
} catch (e) {
// Don't worry if the store doesn't already exist.
}
db.createObjectStore(name, {keyPath: "key"});
}
},
clearAddonData(id) {
let range = IDBKeyRange.bound([id], [id, "\uFFFF"]);
return Promise.all([
this.locales.delete(range),
this.manifests.delete(range),
]).catch(e => {
// Ignore the error. It happens when we try to flush the add-on
// data after the AddonManager has flushed the entire startup cache.
this.dbPromise = this.reallyOpen(true).catch(e => {});
});
},
async reallyOpen(invalidate = false) {
if (this.dbPromise) {
let db = await this.dbPromise;
db.close();
}
if (invalidate) {
IndexedDB.deleteDatabase(this.DB_NAME, {storage: "persistent"});
}
return IndexedDB.open(this.DB_NAME,
{storage: "persistent", version: this.SCHEMA_VERSION},
db => this.initDB(db));
},
async open() {
if (!this.dbPromise) {
this.dbPromise = this.reallyOpen();
}
return this.dbPromise;
},
observe(subject, topic, data) {
if (topic === "startupcache-invalidate") {
this.dbPromise = this.reallyOpen(true).catch(e => {});
}
},
};
Services.obs.addObserver(StartupCache, "startupcache-invalidate");
class CacheStore {
constructor(storeName) {
this.storeName = storeName;
}
async get(key, createFunc) {
let db;
let result;
try {
db = await StartupCache.open();
result = await db.objectStore(this.storeName)
.get(key);
} catch (e) {
Cu.reportError(e);
return createFunc(key);
}
if (result === undefined) {
let value = await createFunc(key);
result = {key, value};
try {
db.objectStore(this.storeName, "readwrite")
.put(result);
} catch (e) {
Cu.reportError(e);
}
}
return result && result.value;
}
async getAll() {
let result = new Map();
try {
let db = await StartupCache.open();
let results = await db.objectStore(this.storeName)
.getAll();
for (let {key, value} of results) {
result.set(key, value);
}
} catch (e) {
Cu.reportError(e);
}
return result;
}
async delete(key) {
let db = await StartupCache.open();
return db.objectStore(this.storeName, "readwrite").delete(key);
}
}
for (let name of StartupCache.STORE_NAMES) {
StartupCache[name] = new CacheStore(name);
}
var ExtensionParent = {
extensionNameFromURI, extensionNameFromURI,
GlobalManager, GlobalManager,
HiddenExtensionPage, HiddenExtensionPage,
IconDetails,
ParentAPIManager, ParentAPIManager,
StartupCache,
WebExtensionPolicy, WebExtensionPolicy,
apiManager, apiManager,
get baseManifestProperties() { get baseManifestProperties() {
@ -1095,3 +1394,39 @@ const ExtensionParent = {
watchExtensionProxyContextLoad, watchExtensionProxyContextLoad,
DebugUtils, DebugUtils,
}; };
XPCOMUtils.defineLazyGetter(ExtensionParent, "PlatformInfo", () => {
return Object.freeze({
os: (function() {
let os = AppConstants.platform;
if (os == "macosx") {
os = "mac";
}
return os;
})(),
arch: (function() {
let abi = Services.appinfo.XPCOMABI;
let [arch] = abi.split("-");
if (arch == "x86") {
arch = "x86-32";
} else if (arch == "x86_64") {
arch = "x86-64";
}
return arch;
})(),
});
});
/**
* Retreives the browser_style stylesheets needed for extension popups and sidebars.
* @returns {Array<string>} an array of stylesheets needed for the current platform.
*/
XPCOMUtils.defineLazyGetter(ExtensionParent, "extensionStylesheets", () => {
let stylesheets = ["chrome://browser/content/extension.css"];
if (AppConstants.platform === "macosx") {
stylesheets.push("chrome://browser/content/extension-mac.css");
}
return stylesheets;
});

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

@ -11,29 +11,13 @@ const Cc = Components.classes;
const Cu = Components.utils; const Cu = Components.utils;
const Cr = Components.results; const Cr = Components.results;
const INTEGER = /^[1-9]\d*$/;
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI", XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI",
"resource://gre/modules/Console.jsm"); "resource://gre/modules/Console.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IndexedDB",
"resource://gre/modules/IndexedDB.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel", XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
"resource://gre/modules/MessageChannel.jsm"); "resource://gre/modules/MessageChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
"resource://gre/modules/Preferences.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
"resource://gre/modules/Schemas.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
"@mozilla.org/content/style-sheet-service;1",
"nsIStyleSheetService");
function getConsole() { function getConsole() {
return new ConsoleAPI({ return new ConsoleAPI({
@ -51,134 +35,6 @@ function getUniqueId() {
return `${nextId++}-${uniqueProcessID}`; return `${nextId++}-${uniqueProcessID}`;
} }
let StartupCache = {
DB_NAME: "ExtensionStartupCache",
SCHEMA_VERSION: 2,
STORE_NAMES: Object.freeze(["locales", "manifests", "schemas"]),
dbPromise: null,
initDB(db) {
for (let name of StartupCache.STORE_NAMES) {
try {
db.deleteObjectStore(name);
} catch (e) {
// Don't worry if the store doesn't already exist.
}
db.createObjectStore(name, {keyPath: "key"});
}
},
clearAddonData(id) {
let range = IDBKeyRange.bound([id], [id, "\uFFFF"]);
return Promise.all([
this.locales.delete(range),
this.manifests.delete(range),
]).catch(e => {
// Ignore the error. It happens when we try to flush the add-on
// data after the AddonManager has flushed the entire startup cache.
this.dbPromise = this.reallyOpen(true).catch(e => {});
});
},
async reallyOpen(invalidate = false) {
if (this.dbPromise) {
let db = await this.dbPromise;
db.close();
}
if (invalidate) {
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT) {
IndexedDB.deleteDatabase(this.DB_NAME, {storage: "persistent"});
}
}
return IndexedDB.open(this.DB_NAME,
{storage: "persistent", version: this.SCHEMA_VERSION},
db => this.initDB(db));
},
async open() {
if (!this.dbPromise) {
this.dbPromise = this.reallyOpen();
}
return this.dbPromise;
},
observe(subject, topic, data) {
if (topic === "startupcache-invalidate") {
this.dbPromise = this.reallyOpen(true).catch(e => {});
}
},
};
Services.obs.addObserver(StartupCache, "startupcache-invalidate");
class CacheStore {
constructor(storeName) {
this.storeName = storeName;
}
async get(key, createFunc) {
let db;
let result;
try {
db = await StartupCache.open();
result = await db.objectStore(this.storeName)
.get(key);
} catch (e) {
Cu.reportError(e);
return createFunc(key);
}
if (result === undefined) {
let value = await createFunc(key);
result = {key, value};
try {
db.objectStore(this.storeName, "readwrite")
.put(result);
} catch (e) {
Cu.reportError(e);
}
}
return result && result.value;
}
async getAll() {
let result = new Map();
try {
let db = await StartupCache.open();
let results = await db.objectStore(this.storeName)
.getAll();
for (let {key, value} of results) {
result.set(key, value);
}
} catch (e) {
Cu.reportError(e);
}
return result;
}
async delete(key) {
let db = await StartupCache.open();
return db.objectStore(this.storeName, "readwrite").delete(key);
}
}
for (let name of StartupCache.STORE_NAMES) {
StartupCache[name] = new CacheStore(name);
}
/** /**
* An Error subclass for which complete error messages are always passed * An Error subclass for which complete error messages are always passed
@ -251,21 +107,6 @@ function instanceOf(value, type) {
return {}.toString.call(value) == `[object ${type}]`; return {}.toString.call(value) == `[object ${type}]`;
} }
// Extend the object |obj| with the property descriptors of each object in
// |args|.
function extend(obj, ...args) {
for (let arg of args) {
let props = [...Object.getOwnPropertyNames(arg),
...Object.getOwnPropertySymbols(arg)];
for (let prop of props) {
let descriptor = Object.getOwnPropertyDescriptor(arg, prop);
Object.defineProperty(obj, prop, descriptor);
}
}
return obj;
}
/** /**
* Similar to a WeakMap, but creates a new key with the given * Similar to a WeakMap, but creates a new key with the given
* constructor if one is not present. * constructor if one is not present.
@ -308,176 +149,6 @@ function getInnerWindowID(window) {
return getWinUtils(window).currentInnerWindowID; return getWinUtils(window).currentInnerWindowID;
} }
class SpreadArgs extends Array {
constructor(args) {
super();
this.push(...args);
}
}
// Manages icon details for toolbar buttons in the |pageAction| and
// |browserAction| APIs.
let IconDetails = {
// WeakMap<Extension -> Map<url-string -> object>>
iconCache: new DefaultWeakMap(() => new Map()),
// Normalizes the various acceptable input formats into an object
// with icon size as key and icon URL as value.
//
// If a context is specified (function is called from an extension):
// Throws an error if an invalid icon size was provided or the
// extension is not allowed to load the specified resources.
//
// If no context is specified, instead of throwing an error, this
// function simply logs a warning message.
normalize(details, extension, context = null) {
if (!details.imageData && typeof details.path === "string") {
let icons = this.iconCache.get(extension);
let baseURI = context ? context.uri : extension.baseURI;
let url = baseURI.resolve(details.path);
let icon = icons.get(url);
if (!icon) {
icon = this._normalize(details, extension, context);
icons.set(url, icon);
}
return icon;
}
return this._normalize(details, extension, context);
},
_normalize(details, extension, context = null) {
let result = {};
try {
if (details.imageData) {
let imageData = details.imageData;
if (typeof imageData == "string") {
imageData = {"19": imageData};
}
for (let size of Object.keys(imageData)) {
if (!INTEGER.test(size)) {
throw new ExtensionError(`Invalid icon size ${size}, must be an integer`);
}
result[size] = imageData[size];
}
}
if (details.path) {
let path = details.path;
if (typeof path != "object") {
path = {"19": path};
}
let baseURI = context ? context.uri : extension.baseURI;
for (let size of Object.keys(path)) {
if (!INTEGER.test(size)) {
throw new ExtensionError(`Invalid icon size ${size}, must be an integer`);
}
let url = baseURI.resolve(path[size]);
// The Chrome documentation specifies these parameters as
// relative paths. We currently accept absolute URLs as well,
// which means we need to check that the extension is allowed
// to load them. This will throw an error if it's not allowed.
try {
Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(
extension.principal, url,
Services.scriptSecurityManager.DISALLOW_SCRIPT);
} catch (e) {
throw new ExtensionError(`Illegal URL ${url}`);
}
result[size] = url;
}
}
} catch (e) {
// Function is called from extension code, delegate error.
if (context) {
throw e;
}
// If there's no context, it's because we're handling this
// as a manifest directive. Log a warning rather than
// raising an error.
extension.manifestError(`Invalid icon data: ${e}`);
}
return result;
},
// Returns the appropriate icon URL for the given icons object and the
// screen resolution of the given window.
getPreferredIcon(icons, extension = null, size = 16) {
const DEFAULT = "chrome://browser/content/extension.svg";
let bestSize = null;
if (icons[size]) {
bestSize = size;
} else if (icons[2 * size]) {
bestSize = 2 * size;
} else {
let sizes = Object.keys(icons)
.map(key => parseInt(key, 10))
.sort((a, b) => a - b);
bestSize = sizes.find(candidate => candidate > size) || sizes.pop();
}
if (bestSize) {
return {size: bestSize, icon: icons[bestSize]};
}
return {size, icon: DEFAULT};
},
convertImageURLToDataURL(imageURL, contentWindow, browserWindow, size = 18) {
return new Promise((resolve, reject) => {
let image = new contentWindow.Image();
image.onload = function() {
let canvas = contentWindow.document.createElement("canvas");
let ctx = canvas.getContext("2d");
let dSize = size * browserWindow.devicePixelRatio;
// Scales the image while maintaing width to height ratio.
// If the width and height differ, the image is centered using the
// smaller of the two dimensions.
let dWidth, dHeight, dx, dy;
if (this.width > this.height) {
dWidth = dSize;
dHeight = image.height * (dSize / image.width);
dx = 0;
dy = (dSize - dHeight) / 2;
} else {
dWidth = image.width * (dSize / image.height);
dHeight = dSize;
dx = (dSize - dWidth) / 2;
dy = 0;
}
canvas.width = dSize;
canvas.height = dSize;
ctx.drawImage(this, 0, 0, this.width, this.height, dx, dy, dWidth, dHeight);
resolve(canvas.toDataURL("image/png"));
};
image.onerror = reject;
image.src = imageURL;
});
},
// These URLs should already be properly escaped, but make doubly sure CSS
// string escape characters are escaped here, since they could lead to a
// sandbox break.
escapeUrl(url) {
return url.replace(/[\\\s"]/g, encodeURIComponent);
},
};
const LISTENERS = Symbol("listeners"); const LISTENERS = Symbol("listeners");
const ONCE_MAP = Symbol("onceMap"); const ONCE_MAP = Symbol("onceMap");
@ -571,47 +242,6 @@ class EventEmitter {
} }
} }
// Simple API for event listeners where events never fire.
function ignoreEvent(context, name) {
return {
addListener: function(callback) {
let id = context.extension.id;
let frame = Components.stack.caller;
let msg = `In add-on ${id}, attempting to use listener "${name}", which is unimplemented.`;
let scriptError = Cc["@mozilla.org/scripterror;1"]
.createInstance(Ci.nsIScriptError);
scriptError.init(msg, frame.filename, null, frame.lineNumber,
frame.columnNumber, Ci.nsIScriptError.warningFlag,
"content javascript");
let consoleService = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
consoleService.logMessage(scriptError);
},
removeListener: function(callback) {},
hasListener: function(callback) {},
};
}
// Copy an API object from |source| into the scope |dest|.
function injectAPI(source, dest) {
for (let prop in source) {
// Skip names prefixed with '_'.
if (prop[0] == "_") {
continue;
}
let desc = Object.getOwnPropertyDescriptor(source, prop);
if (typeof(desc.value) == "function") {
Cu.exportFunction(desc.value, dest, {defineAs: prop});
} else if (typeof(desc.value) == "object") {
let obj = Cu.createObjectIn(dest, {defineAs: prop});
injectAPI(desc.value, obj);
} else {
Object.defineProperty(dest, prop, desc);
}
}
}
/** /**
* A set with a limited number of slots, which flushes older entries as * A set with a limited number of slots, which flushes older entries as
* newer ones are added. * newer ones are added.
@ -744,28 +374,6 @@ function flushJarCache(jarPath) {
Services.obs.notifyObservers(null, "flush-cache-entry", jarPath); Services.obs.notifyObservers(null, "flush-cache-entry", jarPath);
} }
function PlatformInfo() {
return Object.freeze({
os: (function() {
let os = AppConstants.platform;
if (os == "macosx") {
os = "mac";
}
return os;
})(),
arch: (function() {
let abi = Services.appinfo.XPCOMABI;
let [arch] = abi.split("-");
if (arch == "x86") {
arch = "x86-32";
} else if (arch == "x86_64") {
arch = "x86-64";
}
return arch;
})(),
});
}
/** /**
* Convert any of several different representations of a date/time to a Date object. * Convert any of several different representations of a date/time to a Date object.
* Accepts several formats: * Accepts several formats:
@ -784,25 +392,6 @@ function normalizeTime(date) {
? parseInt(date, 10) : date); ? parseInt(date, 10) : date);
} }
const stylesheetMap = new DefaultMap(url => {
let uri = Services.io.newURI(url);
return styleSheetService.preloadSheet(uri, styleSheetService.AGENT_SHEET);
});
/**
* Retreives the browser_style stylesheets needed for extension popups and sidebars.
* @returns {Array<string>} an array of stylesheets needed for the current platform.
*/
function extensionStylesheets() {
let stylesheets = ["chrome://browser/content/extension.css"];
if (AppConstants.platform === "macosx") {
stylesheets.push("chrome://browser/content/extension-mac.css");
}
return stylesheets;
}
/** /**
* Defines a lazy getter for the given property on the given object. The * Defines a lazy getter for the given property on the given object. The
* first time the property is accessed, the return value of the getter * first time the property is accessed, the return value of the getter
@ -844,26 +433,6 @@ function defineLazyGetter(object, prop, getter) {
}); });
} }
function findPathInObject(obj, path, printErrors = true) {
let parent;
for (let elt of path.split(".")) {
if (!obj || !(elt in obj)) {
if (printErrors) {
Cu.reportError(`WebExtension API ${path} not found (it may be unimplemented by Firefox).`);
}
return null;
}
parent = obj;
obj = obj[elt];
}
if (typeof obj === "function") {
return obj.bind(parent);
}
return obj;
}
/** /**
* Acts as a proxy for a message manager or message manager owner, and * Acts as a proxy for a message manager or message manager owner, and
* tracks docShell swaps so that messages are always sent to the same * tracks docShell swaps so that messages are always sent to the same
@ -1041,34 +610,8 @@ class MessageManagerProxy {
} }
} }
/**
* Classify an individual permission from a webextension manifest
* as a host/origin permission, an api permission, or a regular permission.
*
* @param {string} perm The permission string to classify
*
* @returns {object}
* An object with exactly one of the following properties:
* "origin" to indicate this is a host/origin permission.
* "api" to indicate this is an api permission
* (as used for webextensions experiments).
* "permission" to indicate this is a regular permission.
*/
function classifyPermission(perm) {
let match = /^(\w+)(?:\.(\w+)(?:\.\w+)*)?$/.exec(perm);
if (!match) {
return {origin: perm};
} else if (match[1] == "experiments" && match[2]) {
return {api: match[2]};
}
return {permission: perm};
}
this.ExtensionUtils = { this.ExtensionUtils = {
classifyPermission,
defineLazyGetter, defineLazyGetter,
extend,
findPathInObject,
flushJarCache, flushJarCache,
getConsole, getConsole,
getInnerWindowID, getInnerWindowID,
@ -1076,8 +619,6 @@ this.ExtensionUtils = {
getUniqueId, getUniqueId,
filterStack, filterStack,
getWinUtils, getWinUtils,
ignoreEvent,
injectAPI,
instanceOf, instanceOf,
normalizeTime, normalizeTime,
promiseDocumentLoaded, promiseDocumentLoaded,
@ -1088,17 +629,10 @@ this.ExtensionUtils = {
runSafeSync, runSafeSync,
runSafeSyncWithoutClone, runSafeSyncWithoutClone,
runSafeWithoutClone, runSafeWithoutClone,
stylesheetMap,
DefaultMap, DefaultMap,
DefaultWeakMap, DefaultWeakMap,
EventEmitter, EventEmitter,
ExtensionError, ExtensionError,
IconDetails,
LimitedSet, LimitedSet,
MessageManagerProxy, MessageManagerProxy,
SpreadArgs,
StartupCache,
}; };
XPCOMUtils.defineLazyGetter(this.ExtensionUtils, "extensionStylesheets", extensionStylesheets);
XPCOMUtils.defineLazyGetter(this.ExtensionUtils, "PlatformInfo", PlatformInfo);

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

@ -59,6 +59,8 @@ const PREF_MAX_WRITE = "webextensions.native-messaging.max-output-message-bytes"
const REGPATH = "Software\\Mozilla\\NativeMessagingHosts"; const REGPATH = "Software\\Mozilla\\NativeMessagingHosts";
const global = this;
this.HostManifestManager = { this.HostManifestManager = {
_initializePromise: null, _initializePromise: null,
_lookup: null, _lookup: null,
@ -236,7 +238,7 @@ this.NativeApp = class extends EventEmitter {
app.on("message", (what, msg) => port.postMessage(msg)); app.on("message", (what, msg) => port.postMessage(msg));
/* eslint-enable mozilla/balanced-listeners */ /* eslint-enable mozilla/balanced-listeners */
port.registerOnMessage(msg => app.send(msg)); port.registerOnMessage(holder => app.send(holder));
port.registerOnDisconnect(msg => app.close()); port.registerOnDisconnect(msg => app.close());
} }
@ -334,10 +336,11 @@ this.NativeApp = class extends EventEmitter {
})(); })();
} }
send(msg) { send(holder) {
if (this._isDisconnected) { if (this._isDisconnected) {
throw new this.context.cloneScope.Error("Attempt to postMessage on disconnected port"); throw new this.context.cloneScope.Error("Attempt to postMessage on disconnected port");
} }
let msg = holder.deserialize(global);
if (Cu.getClassName(msg, true) != "ArrayBuffer") { if (Cu.getClassName(msg, true) != "ArrayBuffer") {
// This error cannot be triggered by extensions; it indicates an error in // This error cannot be triggered by extensions; it indicates an error in
// our implementation. // our implementation.
@ -412,14 +415,14 @@ this.NativeApp = class extends EventEmitter {
this._cleanup(); this._cleanup();
} }
sendMessage(msg) { sendMessage(holder) {
let responsePromise = new Promise((resolve, reject) => { let responsePromise = new Promise((resolve, reject) => {
this.once("message", (what, msg) => { resolve(msg); }); this.once("message", (what, msg) => { resolve(msg); });
this.once("disconnect", (what, err) => { reject(err); }); this.once("disconnect", (what, err) => { reject(err); });
}); });
let result = this.startupPromise.then(() => { let result = this.startupPromise.then(() => {
this.send(msg); this.send(holder);
return responsePromise; return responsePromise;
}); });

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

@ -21,16 +21,19 @@ Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var { var {
DefaultMap, DefaultMap,
DefaultWeakMap, DefaultWeakMap,
StartupCache,
instanceOf, instanceOf,
} = ExtensionUtils; } = ExtensionUtils;
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
"resource://gre/modules/ExtensionParent.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm"); "resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "contentPolicyService", XPCOMUtils.defineLazyServiceGetter(this, "contentPolicyService",
"@mozilla.org/addons/content-policy;1", "@mozilla.org/addons/content-policy;1",
"nsIAddonContentPolicy"); "nsIAddonContentPolicy");
XPCOMUtils.defineLazyGetter(this, "StartupCache", () => ExtensionParent.StartupCache);
this.EXPORTED_SYMBOLS = ["Schemas"]; this.EXPORTED_SYMBOLS = ["Schemas"];
const {DEBUG} = AppConstants; const {DEBUG} = AppConstants;

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

@ -9,6 +9,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "clearTimeout", XPCOMUtils.defineLazyModuleGetter(this, "clearTimeout",
"resource://gre/modules/Timer.jsm"); "resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionCommon",
"resource://gre/modules/ExtensionCommon.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm"); "resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "require", XPCOMUtils.defineLazyModuleGetter(this, "require",
@ -19,7 +21,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
Cu.import("resource://gre/modules/ExtensionUtils.jsm"); Cu.import("resource://gre/modules/ExtensionUtils.jsm");
const { const {
getWinUtils, getWinUtils,
stylesheetMap,
} = ExtensionUtils; } = ExtensionUtils;
/* eslint-env mozilla/frame-script */ /* eslint-env mozilla/frame-script */
@ -124,7 +125,7 @@ const BrowserListener = {
let winUtils = getWinUtils(content); let winUtils = getWinUtils(content);
for (let url of this.stylesheets) { for (let url of this.stylesheets) {
winUtils.addSheet(stylesheetMap.get(url), winUtils.AGENT_SHEET); winUtils.addSheet(ExtensionCommon.stylesheetMap.get(url), winUtils.AGENT_SHEET);
} }
}, },

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

@ -1,5 +1,7 @@
"use strict"; "use strict";
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads", XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm"); "resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths", XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
@ -14,11 +16,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
"resource://gre/modules/EventEmitter.jsm"); "resource://gre/modules/EventEmitter.jsm");
var { var {
ignoreEvent,
normalizeTime, normalizeTime,
PlatformInfo,
} = ExtensionUtils; } = ExtensionUtils;
var {
ignoreEvent,
} = ExtensionCommon;
const DOWNLOAD_ITEM_FIELDS = ["id", "url", "referrer", "filename", "incognito", const DOWNLOAD_ITEM_FIELDS = ["id", "url", "referrer", "filename", "incognito",
"danger", "mime", "startTime", "endTime", "danger", "mime", "startTime", "endTime",
"estimatedEndTime", "state", "estimatedEndTime", "state",
@ -392,7 +396,7 @@ this.downloads = class extends ExtensionAPI {
downloads: { downloads: {
download(options) { download(options) {
let {filename} = options; let {filename} = options;
if (filename && PlatformInfo.os === "win") { if (filename && AppConstants.platform === "win") {
// cross platform javascript code uses "/" // cross platform javascript code uses "/"
filename = filename.replace(/\//g, "\\"); filename = filename.replace(/\//g, "\\");
} }

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

@ -5,7 +5,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
var { var {
ignoreEvent, ignoreEvent,
} = ExtensionUtils; } = ExtensionCommon;
// WeakMap[Extension -> Map[id -> Notification]] // WeakMap[Extension -> Map[id -> Notification]]
let notificationsMap = new WeakMap(); let notificationsMap = new WeakMap();

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

@ -6,6 +6,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
"resource://gre/modules/AddonManager.jsm"); "resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Extension", XPCOMUtils.defineLazyModuleGetter(this, "Extension",
"resource://gre/modules/Extension.jsm"); "resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
"resource://gre/modules/ExtensionParent.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm"); "resource://gre/modules/NetUtil.jsm");
@ -100,7 +102,7 @@ this.runtime = class extends ExtensionAPI {
}, },
getPlatformInfo: function() { getPlatformInfo: function() {
return Promise.resolve(ExtensionUtils.PlatformInfo); return Promise.resolve(ExtensionParent.PlatformInfo);
}, },
openOptionsPage: function() { openOptionsPage: function() {

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

@ -18,15 +18,9 @@ add_task(async function test_sendMessage_error() {
// because there is no onMessage listener. // because there is no onMessage listener.
[[null, null, null], "Could not establish connection. Receiving end does not exist."], [[null, null, null], "Could not establish connection. Receiving end does not exist."],
// Structural cloning doesn't work with DOM but we fall back // Structured cloning doesn't work with DOM objects
// JSON serialization, so we don't expect another error. [[null, location, null], "The object could not be cloned."],
[[null, location, null], "Could not establish connection. Receiving end does not exist."], [[null, [circ, location], null], "The object could not be cloned."],
// Structured cloning supports cyclic self-references.
[[null, [circ, location], null], "cyclic object value"],
// JSON serialization does not support cyclic references.
[[null, circ, null], "Could not establish connection. Receiving end does not exist."],
// (the last two tests shows whether sendMessage is implemented as structured cloning).
]; ];
// Repeat all tests with the undefined value instead of null. // Repeat all tests with the undefined value instead of null.

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

@ -287,7 +287,7 @@ while True:
}); });
let buffer = NativeApp.encodeMessage(mockContext, MSG); let buffer = NativeApp.encodeMessage(mockContext, MSG);
app.send(buffer); app.send(new StructuredCloneHolder(buffer));
await recvPromise; await recvPromise;
app._cleanup(); app._cleanup();

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

@ -74,8 +74,8 @@ const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml
var gViewDefault = "addons://discover/"; var gViewDefault = "addons://discover/";
XPCOMUtils.defineLazyGetter(this, "extensionStylesheets", () => { XPCOMUtils.defineLazyGetter(this, "extensionStylesheets", () => {
const {ExtensionUtils} = Cu.import("resource://gre/modules/ExtensionUtils.jsm", {}); const {ExtensionParent} = Cu.import("resource://gre/modules/ExtensionParent.jsm", {});
return ExtensionUtils.extensionStylesheets; return ExtensionParent.extensionStylesheets;
}); });
var gStrings = {}; var gStrings = {};

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

@ -41,7 +41,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Locale",
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm"); "resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "IconDetails", () => { XPCOMUtils.defineLazyGetter(this, "IconDetails", () => {
return Cu.import("resource://gre/modules/ExtensionUtils.jsm", {}).ExtensionUtils.IconDetails; return Cu.import("resource://gre/modules/ExtensionParent.jsm", {}).ExtensionParent.IconDetails;
}); });
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm"); "resource://gre/modules/LightweightThemeManager.jsm");