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",
"resource://gre/modules/ExtensionParent.jsm");
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
extensionStylesheets,
promiseEvent,
} = ExtensionUtils;
@ -61,7 +61,7 @@ function getBrowser(sidebar) {
"chrome://extensions/content/ext-browser-content.js", false);
browser.messageManager.sendAsyncMessage("Extension:InitBrowser", {
stylesheets: extensionStylesheets,
stylesheets: ExtensionParent.extensionStylesheets,
});
}
return browser;

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

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

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

@ -19,9 +19,14 @@ Cu.import("resource://gre/modules/EventEmitter.jsm");
var {
DefaultWeakMap,
IconDetails,
} = ExtensionUtils;
Cu.import("resource://gre/modules/ExtensionParent.jsm");
var {
IconDetails,
} = ExtensionParent;
const POPUP_PRELOAD_TIMEOUT_MS = 200;
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: */
"use strict";
var {
PlatformInfo,
} = ExtensionUtils;
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
"resource://gre/modules/ExtensionParent.jsm");
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();
// For Windows, chrome.runtime expects 'win' while chrome.commands
// expects 'windows'. We can special case this for now.
let {PlatformInfo} = ExtensionParent;
let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
for (let [name, command] of Object.entries(manifest.commands)) {
let suggested_key = command.suggested_key || {};

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

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

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

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

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

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

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

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

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

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

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

@ -1,5 +1,5 @@
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);
}
this._factory = null;
}
},
};
var PdfJs = {
@ -344,6 +344,6 @@ var PdfJs = {
delete this._pdfStreamConverterFactory;
this._registered = false;
}
},
};

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

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

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

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

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

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

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

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

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

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

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

@ -119,7 +119,7 @@ var FontInspector = (function FontInspectorClosure() {
download.href = url[1];
} else if (fontObj.data) {
url = URL.createObjectURL(new Blob([fontObj.data], {
type: fontObj.mimeType
type: fontObj.mimeType,
}));
download.href = url;
}
@ -154,7 +154,7 @@ var FontInspector = (function FontInspectorClosure() {
resetSelection();
}
}, 2000);
}
},
};
})();
@ -243,7 +243,7 @@ var StepperManager = (function StepperManagerClosure() {
saveBreakPoints: function saveBreakPoints(pageIndex, bps) {
breakPoints[pageIndex] = bps;
sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints));
}
},
};
})();
@ -433,7 +433,7 @@ var Stepper = (function StepperClosure() {
row.style.backgroundColor = null;
}
}
}
},
};
return Stepper;
})();
@ -497,7 +497,7 @@ var Stats = (function Stats() {
cleanup() {
stats = [];
clear(this.panel);
}
},
};
})();
@ -615,6 +615,6 @@ window.PDFBug = (function PDFBugClosure() {
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) -->
<base href="resource://pdf.js/web/">
<script src="l10n.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>
</head>

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

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

@ -8,9 +8,6 @@ Library('icuuc')
FINAL_LIBRARY = 'icu'
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']

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

@ -330,6 +330,7 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
nsIFrame* targetFrame = target->GetPrimaryFrame();
nsRect targetRect;
Maybe<nsRect> intersectionRect;
bool isSameDoc = root && root->GetComposedDoc() == target->GetComposedDoc();
if (rootFrame && targetFrame) {
// 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
// Document as the intersection root, e.g. if root is an element of
// the main document and target an element from an embedded iframe.
if (target->GetComposedDoc() != root->GetComposedDoc()) {
if (!isSameDoc) {
continue;
}
// Skip further processing of this target if is not a descendant of the
@ -410,12 +411,12 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
intersectionRectRelativeToRoot,
rootIntersectionRect
);
if (intersectionRect.isSome()) {
intersectionRect = Some(nsLayoutUtils::TransformFrameRectToAncestor(
nsLayoutUtils::GetContainingBlockForClientRect(rootFrame),
intersectionRect.value(),
targetFrame->PresContext()->PresShell()->GetRootScrollFrame()
));
if (intersectionRect.isSome() && !isSameDoc) {
nsRect rect = intersectionRect.value();
nsPresContext* presContext = targetFrame->PresContext();
nsLayoutUtils::TransformRect(rootFrame,
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/dom/BlobBinding.h"
#include "mozilla/dom/CryptoKey.h"
#include "mozilla/dom/StructuredCloneBlob.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/File.h"
@ -357,6 +358,10 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
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) {
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
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
{
URLSearchParams* usp = nullptr;

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

@ -62,6 +62,8 @@ enum StructuredCloneTags {
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!
// Tags that are supported by IDB must not ever change. See the static assert
// in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback.

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

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

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

@ -3893,6 +3893,10 @@ nsDOMWindowUtils::GetContentAPZTestData(JSContext* aContext,
if (!clm->GetAPZTestData().ToJS(aOutContentTestData, aContext)) {
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) {
return NS_OK;
}
APZTestData compositorSideData;
if (ClientLayerManager* clm = lm->AsClientLayerManager()) {
APZTestData 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;
}
}
if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) {
return NS_ERROR_FAILURE;
}
}
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
[test_range.js]
head = head_xml.js
[test_structuredcloneholder.js]
[test_thirdpartyutil.js]
[test_treewalker.js]
head = head_xml.js

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

@ -798,6 +798,11 @@ DOMInterfaces = {
'implicitJSContext': [ 'close' ],
},
'StructuredCloneHolder': {
'nativeType': 'mozilla::dom::StructuredCloneBlob',
'wrapperCache': False,
},
'StyleSheet': {
'nativeType': 'mozilla::StyleSheet',
'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',
'StorageManager.webidl',
'StorageType.webidl',
'StructuredCloneHolder.webidl',
'StyleSheet.webidl',
'StyleSheetList.webidl',
'SubtleCrypto.webidl',

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

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

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

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

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

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

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

@ -105,7 +105,7 @@ public:
virtual CompositorAnimationStorage*
GetAnimationStorage(const uint64_t& aId) 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;
virtual void SetConfirmedTargetAPZC(const uint64_t& aLayersId,
const uint64_t& aInputBlockId,

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -32,6 +32,7 @@ WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
, mNeedsComposite(false)
, mIsFirstPaint(false)
, mTarget(nullptr)
, mPaintSequenceNumber(0)
{
MOZ_COUNT_CTOR(WebRenderLayerManager);
}
@ -124,6 +125,13 @@ WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
bool
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;
}
@ -209,6 +217,7 @@ WebRenderLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback
scrollData.SetIsFirstPaint();
mIsFirstPaint = false;
}
scrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
if (mRoot) {
PopulateScrollData(scrollData, mRoot.get());
}

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

@ -8,6 +8,7 @@
#include "Layers.h"
#include "mozilla/MozPromise.h"
#include "mozilla/layers/APZTestData.h"
#include "mozilla/layers/TransactionIdAllocator.h"
#include "mozilla/webrender/WebRenderTypes.h"
@ -126,6 +127,16 @@ public:
void SetTransactionIncomplete() { mTransactionIncomplete = true; }
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:
/**
* 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
// back to mTarget.
RefPtr<gfxContext> mTarget;
// See equivalent field in ClientLayerManager
uint32_t mPaintSequenceNumber;
// See equivalent field in ClientLayerManager
APZTestData mApzTestData;
};
} // namespace layers

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

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

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

@ -121,6 +121,8 @@ public:
void SetIsFirstPaint();
bool IsFirstPaint() const;
void SetPaintSequenceNumber(uint32_t aPaintSequenceNumber);
uint32_t GetPaintSequenceNumber() const;
friend struct IPC::ParamTraits<WebRenderScrollData>;
@ -146,6 +148,7 @@ private:
nsTArray<WebRenderLayerScrollData> mLayerScrollData;
bool mIsFirstPaint;
uint32_t mPaintSequenceNumber;
};
} // namespace layers
@ -219,6 +222,7 @@ struct ParamTraits<mozilla::layers::WebRenderScrollData>
WriteParam(aMsg, aParam.mScrollMetadatas);
WriteParam(aMsg, aParam.mLayerScrollData);
WriteParam(aMsg, aParam.mIsFirstPaint);
WriteParam(aMsg, aParam.mPaintSequenceNumber);
}
static bool
@ -226,7 +230,8 @@ struct ParamTraits<mozilla::layers::WebRenderScrollData>
{
return ReadParam(aMsg, aIter, &aResult->mScrollMetadatas)
&& 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
[PWebRenderBridge::SetAsyncZoom]
description = test only
[PWebRenderBridge::GetAPZTestData]
description = test only
[PHal::GetCurrentBatteryInformation]
description =
[PHal::GetCurrentNetworkInformation]

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

@ -1,4 +1,3 @@
// |jit-test| allow-oom
if (getBuildConfiguration().debug === true)
quit(0);
function f(){};
@ -9,4 +8,4 @@ try {
} catch (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) {
if (getElementsHeader()->numShiftedElements() > 0)
unshiftElements();
moveShiftedElements();
// When an array's length becomes non-writable, writes to indexes
// 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);
if (MOZ_UNLIKELY(header->numShiftedElements() + count > ObjectElements::MaxShiftedElements)) {
unshiftElements();
moveShiftedElements();
header = getElementsHeader();
}

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

@ -115,7 +115,7 @@ ObjectElements::FreezeElements(JSContext* cx, HandleNativeObject obj)
return true;
if (obj->getElementsHeader()->numShiftedElements() > 0)
obj->unshiftElements();
obj->moveShiftedElements();
ObjectElements* header = obj->getElementsHeader();
@ -707,7 +707,7 @@ NativeObject::maybeDensifySparseElements(JSContext* cx, HandleNativeObject obj)
}
void
NativeObject::unshiftElements()
NativeObject::moveShiftedElements()
{
ObjectElements* header = getElementsHeader();
uint32_t numShifted = header->numShiftedElements();
@ -723,7 +723,7 @@ NativeObject::unshiftElements()
elements_ = newHeader->elements();
// To move the elements, temporarily update initializedLength to include
// both shifted and unshifted elements.
// the shifted elements.
newHeader->initializedLength += numShifted;
// Move the elements. Initialize to |undefined| to ensure pre-barriers
@ -739,14 +739,14 @@ NativeObject::unshiftElements()
}
void
NativeObject::maybeUnshiftElements()
NativeObject::maybeMoveShiftedElements()
{
ObjectElements* header = getElementsHeader();
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)
unshiftElements();
moveShiftedElements();
}
// 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())
MOZ_CRASH();
// If there are shifted elements, consider unshifting them first. If we
// don't unshift here, the code below will include the shifted elements in
// the resize.
// If there are shifted elements, consider moving them first. If we don't
// move them here, the code below will include the shifted elements in the
// resize.
uint32_t numShifted = getElementsHeader()->numShiftedElements();
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)
return true;
numShifted = getElementsHeader()->numShiftedElements();
// Ensure |reqCapacity + numShifted| below won't overflow by forcing an
// unshift in that case.
// If |reqCapacity + numShifted| overflows, we just move all shifted
// elements to avoid the problem.
CheckedInt<uint32_t> checkedReqCapacity(reqCapacity);
checkedReqCapacity += numShifted;
if (MOZ_UNLIKELY(!checkedReqCapacity.isValid())) {
unshiftElements();
moveShiftedElements();
numShifted = 0;
}
}
@ -932,10 +941,10 @@ NativeObject::shrinkElements(JSContext* cx, uint32_t reqCapacity)
if (!hasDynamicElements())
return;
// If we have shifted elements, consider unshifting them.
// If we have shifted elements, consider moving them.
uint32_t numShifted = getElementsHeader()->numShiftedElements();
if (numShifted > 0) {
maybeUnshiftElements();
maybeMoveShiftedElements();
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
* 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
* are frozen, have copy-on-write elements, or on arrays with non-writable
* length).
@ -205,7 +205,7 @@ class ObjectElements
};
// 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 MaxShiftedElements = (1 << NumShiftedElementsBits) - 1;
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.
inline bool tryShiftDenseElements(uint32_t count);
// Unshift all shifted elements so that numShiftedElements is 0.
void unshiftElements();
// Move the elements header and all shifted elements to the start of the
// allocated elements space, so that numShiftedElements is 0 afterwards.
void moveShiftedElements();
// If this object has many shifted elements, unshift them.
void maybeUnshiftElements();
// If this object has many shifted elements call moveShiftedElements.
void maybeMoveShiftedElements();
static bool goodElementsAllocationAmount(JSContext* cx, uint32_t reqAllocated,
uint32_t length, uint32_t* goodAmount);

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

@ -20,6 +20,22 @@
#include <prio.h>
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 {
using mozilla::dom::AutoJSAPI;

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

@ -39,6 +39,9 @@
#include "nsXULAppAPI.h"
#include "WrapperFactory.h"
#include "AutoMemMap.h"
#include "ScriptPreloader-inl.h"
#include "mozilla/AddonPathService.h"
#include "mozilla/scache/StartupCache.h"
#include "mozilla/scache/StartupCacheUtils.h"
@ -51,6 +54,7 @@
using namespace mozilla;
using namespace mozilla::scache;
using namespace mozilla::loader;
using namespace xpc;
using namespace JS;
@ -506,25 +510,6 @@ mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
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*
mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
nsIFile* aComponentFile,
@ -671,54 +656,13 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
.setSourceIsLazy(!!cache);
if (realFile) {
int64_t fileSize;
rv = aComponentFile->GetFileSize(&fileSize);
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;
}
AutoMemMap map;
MOZ_TRY(map.init(aComponentFile));
// Note: exceptions will get handled further down;
// don't early return for them here.
Compile(cx, options, buf, fileSize32, &script);
PR_MemUnmap(buf, fileSize32);
auto buf = map.get<char>();
Compile(cx, options, buf.get(), map.size(), &script);
} else {
rv = aInfo.EnsureScriptChannel();
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";
let newTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
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 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";
yield promise;
return Components.utils.isDeadWrapper(doc);

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

@ -122,6 +122,7 @@
#include "RegionBuilder.h"
#include "SVGSVGElement.h"
#include "DisplayItemClip.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
@ -8508,6 +8509,8 @@ nsLayoutUtils::DoLogTestDataForPaint(LayerManager* aManager,
{
if (ClientLayerManager* mgr = aManager->AsClientLayerManager()) {
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",
"resource://gre/modules/PageActions.jsm");
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
Cu.import("resource://gre/modules/ExtensionParent.jsm");
var {
IconDetails,
} = ExtensionUtils;
} = ExtensionParent;
// WeakMap[Extension -> PageAction]
var pageActionMap = new WeakMap();

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

@ -5,13 +5,11 @@
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/XPCOMUtils.jsm");
let { PlatformInfo } = ExtensionUtils;
if (PlatformInfo.os == "android" && !Services.prefs.getBoolPref("network.mdns.use_js_fallback")) {
if (AppConstants.platform == "android" && !Services.prefs.getBoolPref("network.mdns.use_js_fallback")) {
Cu.import("resource://gre/modules/MulticastDNSAndroid.jsm");
} else {
Cu.import("resource://gre/modules/MulticastDNS.jsm");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -97,13 +97,12 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
var {
GlobalManager,
ParentAPIManager,
StartupCache,
apiManager: Management,
} = ExtensionParent;
const {
classifyPermission,
EventEmitter,
StartupCache,
getUniqueId,
} = ExtensionUtils;
@ -145,6 +144,29 @@ function validateThemeManifest(manifestProperties) {
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 UUID_MAP_PREF = "extensions.webextensions.uuids";
const LEAVE_STORAGE_PREF = "extensions.webextensions.keepStorageOnUninstall";

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

@ -40,22 +40,41 @@ const {
DefaultMap,
EventEmitter,
LimitedSet,
SpreadArgs,
defineLazyGetter,
getMessageManager,
getUniqueId,
injectAPI,
} = ExtensionUtils;
const {
LocalAPIImplementation,
LocaleData,
NoCloneSpreadArgs,
SchemaAPIInterface,
SingletonEventManager,
} = ExtensionCommon;
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.
*
@ -115,15 +134,16 @@ class Port {
},
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);
fire.asyncWithoutClone(portObj);
});
}).api(),
onMessage: new SingletonEventManager(this.context, "Port.onMessage", fire => {
return this.registerOnMessage(msg => {
msg = Cu.cloneInto(msg, this.context.cloneScope);
return this.registerOnMessage(holder => {
let msg = holder.deserialize(this.context.cloneScope);
fire.asyncWithoutClone(msg, portObj);
});
}).api(),
@ -202,7 +222,9 @@ class Port {
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() {
@ -307,7 +329,9 @@ class Messenger {
}
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 => {
if (error.result == MessageChannel.RESULT_NO_HANDLER) {
return Promise.reject({message: "Could not establish connection. Receiving end does not exist."});
@ -336,7 +360,7 @@ class Messenger {
filter(sender, recipient));
},
receiveMessage: ({target, data: message, sender, recipient}) => {
receiveMessage: ({target, data: holder, sender, recipient}) => {
if (!this.context.active) {
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);
sendResponse = Cu.exportFunction(sendResponse, this.context.cloneScope);
@ -393,7 +417,7 @@ class Messenger {
} else if (error.result === MessageChannel.RESULT_DISCONNECTED) {
error = null;
}
port.disconnectByOtherEnd(error);
port.disconnectByOtherEnd(new StructuredCloneHolder(error));
});
return port.api();
@ -734,7 +758,9 @@ class ChildAPIManager {
let listener = map.ids.get(data.listenerId);
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)) {
Services.console.logStringMessage(
@ -747,7 +773,9 @@ class ChildAPIManager {
if ("error" in data) {
deferred.reject(data.error);
} 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);
break;

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

@ -29,6 +29,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
"resource://gre/modules/Schemas.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
"@mozilla.org/content/style-sheet-service;1",
"nsIStyleSheetService");
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
@ -36,7 +40,6 @@ var {
DefaultWeakMap,
EventEmitter,
ExtensionError,
SpreadArgs,
defineLazyGetter,
getConsole,
getInnerWindowID,
@ -48,6 +51,39 @@ var {
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 {
constructor(envType, extension) {
this.envType = envType;
@ -311,6 +347,8 @@ class BaseContext {
dump(`Promise resolved after context unloaded\n`);
} else if (!this.active) {
dump(`Promise resolved while context is inactive\n`);
} else if (args instanceof NoCloneSpreadArgs) {
this.runSafeWithoutClone(callback, ...args.unwrappedValues);
} else if (args instanceof SpreadArgs) {
runSafe(callback, ...args);
} else {
@ -336,6 +374,9 @@ class BaseContext {
dump(`Promise resolved after context unloaded\n`);
} else if (!this.active) {
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) {
runSafe(resolve, value.length == 1 ? value[0] : value);
} else {
@ -1067,7 +1108,7 @@ class SchemaAPIManager extends EventEmitter {
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/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,
CanOfAPIs,
LocalAPIImplementation,
LocaleData,
NoCloneSpreadArgs,
SchemaAPIInterface,
SchemaAPIManager,
SingletonEventManager,
SpreadArgs,
ignoreEvent,
stylesheetMap,
};

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

@ -24,6 +24,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
"resource:///modules/E10SUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IndexedDB",
"resource://gre/modules/IndexedDB.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
"resource://gre/modules/MessageChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
@ -46,12 +48,13 @@ var {
BaseContext,
CanOfAPIs,
SchemaAPIManager,
SpreadArgs,
} = ExtensionCommon;
var {
DefaultWeakMap,
ExtensionError,
MessageManagerProxy,
SpreadArgs,
defineLazyGetter,
promiseDocumentLoaded,
promiseEvent,
@ -619,7 +622,9 @@ ParentAPIManager = {
result.then(result => {
result = result instanceof SpreadArgs ? [...result] : [result];
reply({result});
let holder = new StructuredCloneHolder(result);
reply({result: holder});
}, error => {
error = context.normalizeError(error);
reply({error: {message: error.message, fileName: error.fileName}});
@ -651,7 +656,7 @@ ParentAPIManager = {
childId,
listenerId: data.listenerId,
path: data.path,
args: listenerArgs,
args: new StructuredCloneHolder(listenerArgs),
},
{
recipient: {childId},
@ -1070,11 +1075,305 @@ function extensionNameFromURI(uri) {
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,
GlobalManager,
HiddenExtensionPage,
IconDetails,
ParentAPIManager,
StartupCache,
WebExtensionPolicy,
apiManager,
get baseManifestProperties() {
@ -1095,3 +1394,39 @@ const ExtensionParent = {
watchExtensionProxyContextLoad,
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 Cr = Components.results;
const INTEGER = /^[1-9]\d*$/;
Cu.import("resource://gre/modules/Services.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",
"resource://gre/modules/Console.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IndexedDB",
"resource://gre/modules/IndexedDB.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
"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() {
return new ConsoleAPI({
@ -51,134 +35,6 @@ function getUniqueId() {
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
@ -251,21 +107,6 @@ function instanceOf(value, 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
* constructor if one is not present.
@ -308,176 +149,6 @@ function getInnerWindowID(window) {
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 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
* newer ones are added.
@ -744,28 +374,6 @@ function flushJarCache(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.
* Accepts several formats:
@ -784,25 +392,6 @@ function normalizeTime(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
* 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
* 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 = {
classifyPermission,
defineLazyGetter,
extend,
findPathInObject,
flushJarCache,
getConsole,
getInnerWindowID,
@ -1076,8 +619,6 @@ this.ExtensionUtils = {
getUniqueId,
filterStack,
getWinUtils,
ignoreEvent,
injectAPI,
instanceOf,
normalizeTime,
promiseDocumentLoaded,
@ -1088,17 +629,10 @@ this.ExtensionUtils = {
runSafeSync,
runSafeSyncWithoutClone,
runSafeWithoutClone,
stylesheetMap,
DefaultMap,
DefaultWeakMap,
EventEmitter,
ExtensionError,
IconDetails,
LimitedSet,
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 global = this;
this.HostManifestManager = {
_initializePromise: null,
_lookup: null,
@ -236,7 +238,7 @@ this.NativeApp = class extends EventEmitter {
app.on("message", (what, msg) => port.postMessage(msg));
/* eslint-enable mozilla/balanced-listeners */
port.registerOnMessage(msg => app.send(msg));
port.registerOnMessage(holder => app.send(holder));
port.registerOnDisconnect(msg => app.close());
}
@ -334,10 +336,11 @@ this.NativeApp = class extends EventEmitter {
})();
}
send(msg) {
send(holder) {
if (this._isDisconnected) {
throw new this.context.cloneScope.Error("Attempt to postMessage on disconnected port");
}
let msg = holder.deserialize(global);
if (Cu.getClassName(msg, true) != "ArrayBuffer") {
// This error cannot be triggered by extensions; it indicates an error in
// our implementation.
@ -412,14 +415,14 @@ this.NativeApp = class extends EventEmitter {
this._cleanup();
}
sendMessage(msg) {
sendMessage(holder) {
let responsePromise = new Promise((resolve, reject) => {
this.once("message", (what, msg) => { resolve(msg); });
this.once("disconnect", (what, err) => { reject(err); });
});
let result = this.startupPromise.then(() => {
this.send(msg);
this.send(holder);
return responsePromise;
});

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

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

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

@ -9,6 +9,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "clearTimeout",
"resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionCommon",
"resource://gre/modules/ExtensionCommon.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "require",
@ -19,7 +21,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
const {
getWinUtils,
stylesheetMap,
} = ExtensionUtils;
/* eslint-env mozilla/frame-script */
@ -124,7 +125,7 @@ const BrowserListener = {
let winUtils = getWinUtils(content);
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";
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
@ -14,11 +16,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
"resource://gre/modules/EventEmitter.jsm");
var {
ignoreEvent,
normalizeTime,
PlatformInfo,
} = ExtensionUtils;
var {
ignoreEvent,
} = ExtensionCommon;
const DOWNLOAD_ITEM_FIELDS = ["id", "url", "referrer", "filename", "incognito",
"danger", "mime", "startTime", "endTime",
"estimatedEndTime", "state",
@ -392,7 +396,7 @@ this.downloads = class extends ExtensionAPI {
downloads: {
download(options) {
let {filename} = options;
if (filename && PlatformInfo.os === "win") {
if (filename && AppConstants.platform === "win") {
// cross platform javascript code uses "/"
filename = filename.replace(/\//g, "\\");
}

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

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

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

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

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

@ -18,15 +18,9 @@ add_task(async function test_sendMessage_error() {
// because there is no onMessage listener.
[[null, null, null], "Could not establish connection. Receiving end does not exist."],
// Structural cloning doesn't work with DOM but we fall back
// JSON serialization, so we don't expect another error.
[[null, location, null], "Could not establish connection. Receiving end does not exist."],
// 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).
// Structured cloning doesn't work with DOM objects
[[null, location, null], "The object could not be cloned."],
[[null, [circ, location], null], "The object could not be cloned."],
];
// Repeat all tests with the undefined value instead of null.

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

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

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

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

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

@ -41,7 +41,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Locale",
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
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",
"resource://gre/modules/LightweightThemeManager.jsm");