зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
87a0b11003
|
@ -837,7 +837,7 @@ const proto = {
|
|||
|
||||
// Catch any errors if the source actor cannot be found
|
||||
try {
|
||||
source = this.hooks.sources().getSourceActorByURL(stack.source);
|
||||
source = this.hooks.sources().getSourceActorsByURL(stack.source)[0];
|
||||
} catch (e) {
|
||||
// ignored
|
||||
}
|
||||
|
|
|
@ -70,31 +70,13 @@ function getSourceURL(source, window) {
|
|||
exports.getSourceURL = getSourceURL;
|
||||
|
||||
/**
|
||||
* A SourceActor provides information about the source of a script. There
|
||||
* are two kinds of source actors: ones that represent real source objects,
|
||||
* and ones that represent non-existant "original" sources when the real
|
||||
* sources are HTML documents. We separate these because there isn't a
|
||||
* 1:1 mapping of HTML to sources; one source may represent a subsection
|
||||
* of an HTML source, so we need to create N + 1 separate
|
||||
* actors.
|
||||
*
|
||||
* There are 2 different scenarios for sources that you should
|
||||
* understand:
|
||||
*
|
||||
* - A single source that is not inlined in HTML
|
||||
* (separate JS file, eval'ed code, etc)
|
||||
* - An HTML page with multiple inline scripts, which are distinct
|
||||
* sources, but should be represented as a single source
|
||||
*
|
||||
* The complexity of `SourceActor` and `ThreadSources` are to handle
|
||||
* all of thise cases and hopefully internalize the complexities.
|
||||
* A SourceActor provides information about the source of a script. Source
|
||||
* actors are 1:1 with Debugger.Source objects.
|
||||
*
|
||||
* @param Debugger.Source source
|
||||
* The source object we are representing.
|
||||
* @param ThreadActor thread
|
||||
* The current thread actor.
|
||||
* @param String originalUrl
|
||||
* Optional. For HTML documents urls, the original url this is representing.
|
||||
* @param Boolean isInlineSource
|
||||
* Optional. True if this is an inline source from a HTML or XUL page.
|
||||
* @param String contentType
|
||||
|
@ -103,10 +85,9 @@ exports.getSourceURL = getSourceURL;
|
|||
const SourceActor = ActorClassWithSpec(sourceSpec, {
|
||||
typeName: "source",
|
||||
|
||||
initialize: function({ source, thread, originalUrl,
|
||||
isInlineSource, contentType }) {
|
||||
initialize: function({ source, thread, isInlineSource, contentType }) {
|
||||
this._threadActor = thread;
|
||||
this._url = originalUrl;
|
||||
this._url = null;
|
||||
this._source = source;
|
||||
this._contentType = contentType;
|
||||
this._isInlineSource = isInlineSource;
|
||||
|
@ -137,10 +118,7 @@ const SourceActor = ActorClassWithSpec(sourceSpec, {
|
|||
return this.threadActor.breakpointActorMap;
|
||||
},
|
||||
get url() {
|
||||
if (this._url) {
|
||||
return this._url;
|
||||
}
|
||||
if (this.source) {
|
||||
if (!this._url) {
|
||||
this._url = getSourceURL(this.source, this.threadActor._parent.window);
|
||||
}
|
||||
return this._url;
|
||||
|
@ -155,10 +133,9 @@ const SourceActor = ActorClassWithSpec(sourceSpec, {
|
|||
|
||||
form: function() {
|
||||
const source = this.source;
|
||||
// This might not have a source because we treat HTML pages with
|
||||
// inline scripts as a special SourceActor that doesn't have either.
|
||||
|
||||
let introductionUrl = null;
|
||||
if (source && source.introductionScript) {
|
||||
if (source.introductionScript) {
|
||||
introductionUrl = source.introductionScript.source.url;
|
||||
}
|
||||
|
||||
|
@ -185,15 +162,7 @@ const SourceActor = ActorClassWithSpec(sourceSpec, {
|
|||
"Debuggee source and URL are set automatically"
|
||||
);
|
||||
|
||||
// For most cases, we have a real source to query for. The
|
||||
// only time we don't is for HTML pages. In that case we want
|
||||
// to query for scripts in an HTML page based on its URL, as
|
||||
// there could be several sources within an HTML page.
|
||||
if (this.source) {
|
||||
query.source = this.source;
|
||||
} else {
|
||||
query.url = this.url;
|
||||
}
|
||||
query.source = this.source;
|
||||
return this.dbg.findScripts(query);
|
||||
},
|
||||
|
||||
|
@ -213,7 +182,7 @@ const SourceActor = ActorClassWithSpec(sourceSpec, {
|
|||
content: t,
|
||||
contentType: this._contentType,
|
||||
});
|
||||
const isWasm = this.source && this.source.introductionType === "wasm";
|
||||
const isWasm = this.source.introductionType === "wasm";
|
||||
|
||||
if (isWasm) {
|
||||
const wasm = this.source.binary;
|
||||
|
|
|
@ -317,12 +317,16 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
const actor = this.breakpointActorMap.getOrCreateBreakpointActor(location);
|
||||
actor.setOptions(options);
|
||||
|
||||
const sourceActor = location.sourceUrl
|
||||
? this.sources.getSourceActorByURL(location.sourceUrl)
|
||||
: this.sources.getSourceActorById(location.sourceId);
|
||||
|
||||
if (sourceActor) {
|
||||
sourceActor.applyBreakpoint(actor);
|
||||
if (location.sourceUrl) {
|
||||
// There can be multiple source actors for a URL if there are multiple
|
||||
// inline sources on an HTML page.
|
||||
const sourceActors = this.sources.getSourceActorsByURL(location.sourceUrl);
|
||||
sourceActors.map(sourceActor => sourceActor.applyBreakpoint(actor));
|
||||
} else {
|
||||
const sourceActor = this.sources.getSourceActorById(location.sourceId);
|
||||
if (sourceActor) {
|
||||
sourceActor.applyBreakpoint(actor);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@ function TabSources(threadActor, allowSourceFn = () => true) {
|
|||
|
||||
// Debugger.Source -> SourceActor
|
||||
this._sourceActors = new Map();
|
||||
// url -> SourceActor
|
||||
this._htmlDocumentSourceActors = Object.create(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +61,6 @@ TabSources.prototype = {
|
|||
*/
|
||||
reset: function() {
|
||||
this._sourceActors = new Map();
|
||||
this._htmlDocumentSourceActors = Object.create(null);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -88,33 +85,15 @@ TabSources.prototype = {
|
|||
return null;
|
||||
}
|
||||
|
||||
// It's a hack, but inline HTML scripts each have real sources,
|
||||
// but we want to represent all of them as one source as the
|
||||
// HTML page. The actor representing this fake HTML source is
|
||||
// stored in this array, which always has a URL, so check it
|
||||
// first.
|
||||
if (isInlineSource && source.url in this._htmlDocumentSourceActors) {
|
||||
return this._htmlDocumentSourceActors[source.url];
|
||||
}
|
||||
|
||||
let originalUrl = null;
|
||||
if (isInlineSource) {
|
||||
// If it's an inline source, the fake HTML source hasn't been
|
||||
// created yet (would have returned above), so flip this source
|
||||
// into a sourcemapped state by giving it an `originalUrl` which
|
||||
// is the HTML url.
|
||||
originalUrl = source.url;
|
||||
source = null;
|
||||
} else if (this._sourceActors.has(source)) {
|
||||
if (this._sourceActors.has(source)) {
|
||||
return this._sourceActors.get(source);
|
||||
}
|
||||
|
||||
const actor = new SourceActor({
|
||||
thread: this._thread,
|
||||
source: source,
|
||||
originalUrl: originalUrl,
|
||||
isInlineSource: isInlineSource,
|
||||
contentType: contentType,
|
||||
source,
|
||||
isInlineSource,
|
||||
contentType,
|
||||
});
|
||||
|
||||
this._thread.threadLifetimePool.addActor(actor);
|
||||
|
@ -126,21 +105,13 @@ TabSources.prototype = {
|
|||
this.neverAutoBlackBoxSources.add(actor.url);
|
||||
}
|
||||
|
||||
if (source) {
|
||||
this._sourceActors.set(source, actor);
|
||||
} else {
|
||||
this._htmlDocumentSourceActors[originalUrl] = actor;
|
||||
}
|
||||
this._sourceActors.set(source, actor);
|
||||
|
||||
this.emit("newSource", actor);
|
||||
return actor;
|
||||
},
|
||||
|
||||
_getSourceActor: function(source) {
|
||||
if (source.url in this._htmlDocumentSourceActors) {
|
||||
return this._htmlDocumentSourceActors[source.url];
|
||||
}
|
||||
|
||||
if (this._sourceActors.has(source)) {
|
||||
return this._sourceActors.get(source);
|
||||
}
|
||||
|
@ -163,19 +134,16 @@ TabSources.prototype = {
|
|||
return sourceActor;
|
||||
},
|
||||
|
||||
getSourceActorByURL: function(url) {
|
||||
getSourceActorsByURL: function(url) {
|
||||
const rv = [];
|
||||
if (url) {
|
||||
for (const [source, actor] of this._sourceActors) {
|
||||
if (source.url === url) {
|
||||
return actor;
|
||||
rv.push(actor);
|
||||
}
|
||||
}
|
||||
|
||||
if (url in this._htmlDocumentSourceActors) {
|
||||
return this._htmlDocumentSourceActors[url];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return rv;
|
||||
},
|
||||
|
||||
getSourceActorById(actorId) {
|
||||
|
@ -401,13 +369,7 @@ TabSources.prototype = {
|
|||
},
|
||||
|
||||
iter: function() {
|
||||
const actors = Object.keys(this._htmlDocumentSourceActors).map(k => {
|
||||
return this._htmlDocumentSourceActors[k];
|
||||
});
|
||||
for (const actor of this._sourceActors.values()) {
|
||||
actors.push(actor);
|
||||
}
|
||||
return actors;
|
||||
return [...this._sourceActors.values()];
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -101,6 +101,8 @@
|
|||
#include "mozilla/dom/ParentSHistory.h"
|
||||
#include "mozilla/dom/ChildSHistory.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/RemoteFrameChild.h"
|
||||
|
||||
#include "mozilla/dom/HTMLBodyElement.h"
|
||||
|
||||
|
@ -349,13 +351,19 @@ nsresult nsFrameLoader::ReallyStartLoadingInternal() {
|
|||
AUTO_PROFILER_LABEL("nsFrameLoader::ReallyStartLoadingInternal", OTHER);
|
||||
|
||||
if (IsRemoteFrame()) {
|
||||
if (!mRemoteBrowser && !TryRemoteBrowser()) {
|
||||
if (!mRemoteBrowser && !mRemoteFrameChild && !TryRemoteBrowser()) {
|
||||
NS_WARNING("Couldn't create child process for iframe.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// FIXME get error codes from child
|
||||
mRemoteBrowser->LoadURL(mURIToLoad);
|
||||
if (mRemoteFrameChild) {
|
||||
nsAutoCString spec;
|
||||
mURIToLoad->GetSpec(spec);
|
||||
Unused << mRemoteFrameChild->SendLoadURL(spec);
|
||||
} else {
|
||||
// FIXME get error codes from child
|
||||
mRemoteBrowser->LoadURL(mURIToLoad);
|
||||
}
|
||||
|
||||
if (!mRemoteBrowserShown) {
|
||||
// This can fail if it's too early to show the frame, we will retry later.
|
||||
|
@ -790,7 +798,7 @@ bool nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
|
|||
NS_ASSERTION(IsRemoteFrame(),
|
||||
"ShowRemote only makes sense on remote frames.");
|
||||
|
||||
if (!mRemoteBrowser && !TryRemoteBrowser()) {
|
||||
if (!mRemoteBrowser && !mRemoteFrameChild && !TryRemoteBrowser()) {
|
||||
NS_ERROR("Couldn't create child process.");
|
||||
return false;
|
||||
}
|
||||
|
@ -809,12 +817,25 @@ bool nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
|
|||
return false;
|
||||
}
|
||||
|
||||
RenderFrame* rf = GetCurrentRenderFrame();
|
||||
if (!rf) {
|
||||
return false;
|
||||
if (mRemoteFrameChild) {
|
||||
nsCOMPtr<nsISupports> container =
|
||||
mOwnerContent->OwnerDoc()->GetContainer();
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
|
||||
nsCOMPtr<nsIWidget> mainWidget;
|
||||
baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
|
||||
nsSizeMode sizeMode =
|
||||
mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal;
|
||||
|
||||
Unused << mRemoteFrameChild->SendShow(
|
||||
size, ParentWindowIsActive(mOwnerContent->OwnerDoc()), sizeMode);
|
||||
mRemoteBrowserShown = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!rf->AttachLayerManager()) {
|
||||
RenderFrame* rf =
|
||||
mRemoteBrowser ? mRemoteBrowser->GetRenderFrame() : nullptr;
|
||||
|
||||
if (!rf || !rf->AttachLayerManager()) {
|
||||
// This is just not going to work.
|
||||
return false;
|
||||
}
|
||||
|
@ -832,7 +853,11 @@ bool nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
|
|||
|
||||
// Don't show remote iframe if we are waiting for the completion of reflow.
|
||||
if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
if (mRemoteBrowser) {
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
} else if (mRemoteFrameChild) {
|
||||
mRemoteFrameChild->UpdateDimensions(dimensions, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -921,6 +946,11 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// FIXME: Consider supporting FrameLoader swapping for remote sub frames.
|
||||
if (mRemoteFrameChild) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (!mRemoteBrowser || !aOther->mRemoteBrowser) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -1648,6 +1678,11 @@ void nsFrameLoader::DestroyDocShell() {
|
|||
mRemoteBrowser->Destroy();
|
||||
}
|
||||
|
||||
if (mRemoteFrameChild) {
|
||||
Unused << mRemoteFrameChild->Send__delete__(mRemoteFrameChild);
|
||||
mRemoteFrameChild = nullptr;
|
||||
}
|
||||
|
||||
// Fire the "unload" event if we're in-process.
|
||||
if (mChildMessageManager) {
|
||||
mChildMessageManager->FireUnloadEvent();
|
||||
|
@ -1689,6 +1724,11 @@ void nsFrameLoader::DestroyComplete() {
|
|||
mRemoteBrowser = nullptr;
|
||||
}
|
||||
|
||||
if (mRemoteFrameChild) {
|
||||
Unused << mRemoteFrameChild->Send__delete__(mRemoteFrameChild);
|
||||
mRemoteFrameChild = nullptr;
|
||||
}
|
||||
|
||||
if (mMessageManager) {
|
||||
mMessageManager->Disconnect();
|
||||
}
|
||||
|
@ -1718,10 +1758,6 @@ void nsFrameLoader::SetOwnerContent(Element* aContent) {
|
|||
UpdateReflectorGlobal(jsapi.cx(), wrapper, rv);
|
||||
Unused << NS_WARN_IF(rv.Failed());
|
||||
}
|
||||
|
||||
if (RenderFrame* rfp = GetCurrentRenderFrame()) {
|
||||
rfp->OwnerContentChanged(aContent);
|
||||
}
|
||||
}
|
||||
|
||||
bool nsFrameLoader::OwnerIsMozBrowserFrame() {
|
||||
|
@ -1764,6 +1800,13 @@ bool nsFrameLoader::ShouldUseRemoteProcess() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Check if the force fission test attribute is enabled.
|
||||
if (XRE_IsContentProcess() &&
|
||||
Preferences::GetBool("browser.fission.oopif.attribute", false) &&
|
||||
mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::fission)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess() &&
|
||||
!(PR_GetEnv("MOZ_NESTED_OOP_TABS") ||
|
||||
Preferences::GetBool("dom.ipc.tabs.nested.enabled", false))) {
|
||||
|
@ -1785,14 +1828,6 @@ bool nsFrameLoader::ShouldUseRemoteProcess() {
|
|||
nsGkAtoms::_true, eCaseMatters);
|
||||
}
|
||||
|
||||
bool nsFrameLoader::IsRemoteFrame() {
|
||||
if (mRemoteFrame) {
|
||||
MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static already_AddRefed<BrowsingContext> CreateBrowsingContext(
|
||||
BrowsingContext* aParentContext, BrowsingContext* aOpenerContext,
|
||||
const nsAString& aName, bool aIsContent) {
|
||||
|
@ -2259,7 +2294,7 @@ nsresult nsFrameLoader::GetWindowDimensions(nsIntRect& aRect) {
|
|||
|
||||
nsresult nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame* aIFrame) {
|
||||
if (IsRemoteFrame()) {
|
||||
if (mRemoteBrowser) {
|
||||
if (mRemoteBrowser || mRemoteFrameChild) {
|
||||
ScreenIntSize size = aIFrame->GetSubdocumentSize();
|
||||
// If we were not able to show remote frame before, we should probably
|
||||
// retry now to send correct showInfo.
|
||||
|
@ -2269,7 +2304,11 @@ nsresult nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame* aIFrame) {
|
|||
nsIntRect dimensions;
|
||||
NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
|
||||
mLazySize = size;
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
if (mRemoteBrowser) {
|
||||
mRemoteBrowser->UpdateDimensions(dimensions, size);
|
||||
} else if (mRemoteFrameChild) {
|
||||
mRemoteFrameChild->UpdateDimensions(dimensions, size);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2371,7 +2410,7 @@ static Tuple<ContentParent*, TabParent*> GetContentParent(Element* aBrowser) {
|
|||
}
|
||||
|
||||
bool nsFrameLoader::TryRemoteBrowser() {
|
||||
NS_ASSERTION(!mRemoteBrowser,
|
||||
NS_ASSERTION(!mRemoteBrowser && !mRemoteFrameChild,
|
||||
"TryRemoteBrowser called with a remote browser already?");
|
||||
|
||||
if (!mOwnerContent) {
|
||||
|
@ -2417,7 +2456,9 @@ bool nsFrameLoader::TryRemoteBrowser() {
|
|||
// iframes for JS plugins also get to skip these checks. We control the URL
|
||||
// that gets loaded, but the load is triggered from the document containing
|
||||
// the plugin.
|
||||
if (!OwnerIsMozBrowserFrame() && !IsForJSPlugin()) {
|
||||
// out of process iframes also get to skip this check.
|
||||
if (!OwnerIsMozBrowserFrame() && !IsForJSPlugin() &&
|
||||
!XRE_IsContentProcess()) {
|
||||
if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
|
||||
// Allow about:addon an exception to this rule so it can load remote
|
||||
// extension options pages.
|
||||
|
@ -2487,6 +2528,14 @@ bool nsFrameLoader::TryRemoteBrowser() {
|
|||
}
|
||||
|
||||
nsCOMPtr<Element> ownerElement = mOwnerContent;
|
||||
|
||||
// If we're in a content process, create a RemoteFrameChild actor.
|
||||
if (XRE_IsContentProcess()) {
|
||||
mRemoteFrameChild = RemoteFrameChild::Create(
|
||||
this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
return !!mRemoteFrameChild;
|
||||
}
|
||||
|
||||
mRemoteBrowser =
|
||||
ContentParent::CreateBrowser(context, ownerElement, openerContentParent,
|
||||
sameTabGroupAs, nextTabParentId);
|
||||
|
@ -2546,15 +2595,27 @@ bool nsFrameLoader::TryRemoteBrowser() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool nsFrameLoader::IsRemoteFrame() {
|
||||
if (mRemoteFrame) {
|
||||
MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::dom::PBrowserParent* nsFrameLoader::GetRemoteBrowser() const {
|
||||
return mRemoteBrowser;
|
||||
}
|
||||
|
||||
RenderFrame* nsFrameLoader::GetCurrentRenderFrame() const {
|
||||
mozilla::layers::LayersId nsFrameLoader::GetLayersId() const {
|
||||
MOZ_ASSERT(mRemoteFrame);
|
||||
if (mRemoteBrowser) {
|
||||
return mRemoteBrowser->GetRenderFrame();
|
||||
return mRemoteBrowser->GetRenderFrame()->GetLayersId();
|
||||
}
|
||||
return nullptr;
|
||||
if (mRemoteFrameChild) {
|
||||
return mRemoteFrameChild->GetLayersId();
|
||||
}
|
||||
return mozilla::layers::LayersId{};
|
||||
}
|
||||
|
||||
void nsFrameLoader::ActivateRemoteFrame(ErrorResult& aRv) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ParentSHistory.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "Units.h"
|
||||
#include "nsIFrame.h"
|
||||
|
@ -58,6 +59,7 @@ class ProcessMessageManager;
|
|||
class Promise;
|
||||
class TabParent;
|
||||
class MutableTabContext;
|
||||
class RemoteFrameChild;
|
||||
|
||||
namespace ipc {
|
||||
class StructuredCloneData;
|
||||
|
@ -270,23 +272,26 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
return mOwnerContent ? mOwnerContent->OwnerDoc() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this frame is a remote frame.
|
||||
*
|
||||
* This is true for either a top-level remote browser in the parent process,
|
||||
* or a remote subframe in the child process.
|
||||
*/
|
||||
bool IsRemoteFrame();
|
||||
|
||||
/**
|
||||
* Returns the IPDL actor used if this is a top-level remote browser, or null
|
||||
* otherwise.
|
||||
*/
|
||||
PBrowserParent* GetRemoteBrowser() const;
|
||||
|
||||
/**
|
||||
* The "current" render frame is the one on which the most recent
|
||||
* remote layer-tree transaction was executed. If no content has
|
||||
* been drawn yet, or the remote browser doesn't have any drawn
|
||||
* content for whatever reason, return nullptr. The returned render
|
||||
* frame has an associated shadow layer tree.
|
||||
* Returns the layers ID that this remote frame is using to render.
|
||||
*
|
||||
* Note that the returned render frame might not be a frame
|
||||
* constructed for this->GetURL(). This can happen, e.g., if the
|
||||
* <browser> was just navigated to a new URL, but hasn't painted the
|
||||
* new page yet. A render frame for the previous page may be
|
||||
* returned. (In-process <browser> behaves similarly, and this
|
||||
* behavior seems desirable.)
|
||||
* This must only be called if this is a remote frame.
|
||||
*/
|
||||
RenderFrame* GetCurrentRenderFrame() const;
|
||||
mozilla::layers::LayersId GetLayersId() const;
|
||||
|
||||
mozilla::dom::ChromeMessageSender* GetFrameMessageManager() {
|
||||
return mMessageManager;
|
||||
|
@ -358,11 +363,6 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
|
||||
bool ShouldUseRemoteProcess();
|
||||
|
||||
/**
|
||||
* Return true if the frame is a remote frame. Return false otherwise
|
||||
*/
|
||||
bool IsRemoteFrame();
|
||||
|
||||
bool IsForJSPlugin() { return mJSPluginID != nsFakePluginTag::NOT_JSPLUGIN; }
|
||||
|
||||
/**
|
||||
|
@ -456,6 +456,9 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
TabParent* mRemoteBrowser;
|
||||
uint64_t mChildID;
|
||||
|
||||
// This is used when this refers to a remote sub frame
|
||||
RefPtr<mozilla::dom::RemoteFrameChild> mRemoteFrameChild;
|
||||
|
||||
int32_t mJSPluginID;
|
||||
|
||||
// Holds the last known size of the frame.
|
||||
|
|
|
@ -1403,6 +1403,12 @@ static bool XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
|||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(attrSpec.isAccessor(),
|
||||
"Bad JSPropertySpec declaration: not an accessor property");
|
||||
MOZ_ASSERT(
|
||||
!attrSpec.isSelfHosted(),
|
||||
"Bad JSPropertySpec declaration: unsupported self-hosted accessor");
|
||||
|
||||
cacheOnHolder = true;
|
||||
|
||||
// Because of centralization, we need to make sure we fault in the JitInfos as
|
||||
|
|
|
@ -19,6 +19,7 @@ include protocol PFileDescriptorSet;
|
|||
include protocol PIPCBlobInputStream;
|
||||
include protocol PPaymentRequest;
|
||||
include protocol PWindowGlobal;
|
||||
include protocol PRemoteFrame;
|
||||
|
||||
include DOMTypes;
|
||||
include IPCBlob;
|
||||
|
@ -142,6 +143,7 @@ nested(upto inside_cpow) sync protocol PBrowser
|
|||
manages PPluginWidget;
|
||||
manages PPaymentRequest;
|
||||
manages PWindowGlobal;
|
||||
manages PRemoteFrame;
|
||||
|
||||
both:
|
||||
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
|
||||
|
@ -174,6 +176,11 @@ parent:
|
|||
*/
|
||||
async PWindowGlobal(WindowGlobalInit init);
|
||||
|
||||
/**
|
||||
* Construct a new Remote iframe actor.
|
||||
*/
|
||||
async PRemoteFrame(nsString aPresentationURL, nsString aRemoteType);
|
||||
|
||||
/**
|
||||
* Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
|
||||
* widget's shareable window on the chrome side. Only used on Windows.
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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 protocol PBrowser;
|
||||
|
||||
include DOMTypes;
|
||||
|
||||
using ScreenIntSize from "Units.h";
|
||||
using nsSizeMode from "nsIWidgetListener.h";
|
||||
using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h";
|
||||
using mozilla::layers::LayersId from "mozilla/layers/LayersTypes.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* PRemoteFrame corresponds to a remote iframe.
|
||||
*/
|
||||
async protocol PRemoteFrame {
|
||||
manager PBrowser;
|
||||
|
||||
child:
|
||||
async SetLayersId(LayersId layersId);
|
||||
|
||||
parent:
|
||||
// Destroy the remote web browser due to the nsFrameLoader going away.
|
||||
async __delete__();
|
||||
|
||||
// DocShell messaging.
|
||||
async LoadURL(nsCString aSpec);
|
||||
|
||||
// Out of process rendering.
|
||||
async Show(ScreenIntSize size, bool parentIsActive, nsSizeMode sizeMode);
|
||||
async UpdateDimensions(DimensionInfo dimensions) compressall;
|
||||
async RenderLayers(bool aEnabled, bool aForceRepaint, LayersObserverEpoch aEpoch);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- 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/RemoteFrameChild.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
RemoteFrameChild::RemoteFrameChild(nsFrameLoader* aFrameLoader)
|
||||
: mLayersId{0}, mIPCOpen(true), mFrameLoader(aFrameLoader) {}
|
||||
|
||||
RemoteFrameChild::~RemoteFrameChild() {}
|
||||
|
||||
already_AddRefed<RemoteFrameChild> RemoteFrameChild::Create(
|
||||
nsFrameLoader* aFrameLoader, const TabContext& aContext,
|
||||
const nsString& aRemoteType) {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
// Determine our embedder's TabChild actor.
|
||||
RefPtr<Element> owner = aFrameLoader->GetOwnerContent();
|
||||
MOZ_DIAGNOSTIC_ASSERT(owner);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(owner->GetOwnerGlobal());
|
||||
MOZ_DIAGNOSTIC_ASSERT(docShell);
|
||||
|
||||
RefPtr<TabChild> tabChild = TabChild::GetFrom(docShell);
|
||||
MOZ_DIAGNOSTIC_ASSERT(tabChild);
|
||||
|
||||
RefPtr<RemoteFrameChild> remoteFrame = new RemoteFrameChild(aFrameLoader);
|
||||
// Reference is freed in TabChild::DeallocPRemoteFrameChild.
|
||||
tabChild->SendPRemoteFrameConstructor(
|
||||
do_AddRef(remoteFrame).take(),
|
||||
PromiseFlatString(aContext.PresentationURL()), aRemoteType);
|
||||
remoteFrame->mIPCOpen = true;
|
||||
|
||||
return remoteFrame.forget();
|
||||
}
|
||||
|
||||
void RemoteFrameChild::UpdateDimensions(const nsIntRect& aRect,
|
||||
const mozilla::ScreenIntSize& aSize) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIPCOpen);
|
||||
|
||||
RefPtr<Element> owner = mFrameLoader->GetOwnerContent();
|
||||
nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForContent(owner);
|
||||
if (!widget) {
|
||||
widget = nsContentUtils::WidgetForDocument(owner->OwnerDoc());
|
||||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(widget);
|
||||
|
||||
CSSToLayoutDeviceScale widgetScale = widget->GetDefaultScale();
|
||||
|
||||
LayoutDeviceIntRect devicePixelRect = ViewAs<LayoutDevicePixel>(
|
||||
aRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
|
||||
LayoutDeviceIntSize devicePixelSize = ViewAs<LayoutDevicePixel>(
|
||||
aSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
|
||||
|
||||
// XXX What are clientOffset and chromeOffset used for? Are they meaningful
|
||||
// for nested iframes with transforms?
|
||||
LayoutDeviceIntPoint clientOffset;
|
||||
LayoutDeviceIntPoint chromeOffset;
|
||||
|
||||
CSSRect unscaledRect = devicePixelRect / widgetScale;
|
||||
CSSSize unscaledSize = devicePixelSize / widgetScale;
|
||||
hal::ScreenOrientation orientation = hal::eScreenOrientation_Default;
|
||||
DimensionInfo di(unscaledRect, unscaledSize, orientation, clientOffset,
|
||||
chromeOffset);
|
||||
|
||||
Unused << SendUpdateDimensions(di);
|
||||
}
|
||||
|
||||
IPCResult RemoteFrameChild::RecvSetLayersId(
|
||||
const mozilla::layers::LayersId& aLayersId) {
|
||||
MOZ_ASSERT(!mLayersId.IsValid() && aLayersId.IsValid());
|
||||
mLayersId = aLayersId;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void RemoteFrameChild::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
mIPCOpen = false;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_RemoteFrameChild_h
|
||||
#define mozilla_dom_RemoteFrameChild_h
|
||||
|
||||
#include "mozilla/dom/PRemoteFrameChild.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* Child side for a remote frame.
|
||||
*/
|
||||
class RemoteFrameChild : public PRemoteFrameChild {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(RemoteFrameChild);
|
||||
|
||||
TabChild* Manager() {
|
||||
MOZ_ASSERT(mIPCOpen);
|
||||
return static_cast<TabChild*>(PRemoteFrameChild::Manager());
|
||||
}
|
||||
|
||||
mozilla::layers::LayersId GetLayersId() { return mLayersId; }
|
||||
|
||||
static already_AddRefed<RemoteFrameChild> Create(nsFrameLoader* aFrameLoader,
|
||||
const TabContext& aContext,
|
||||
const nsString& aRemoteType);
|
||||
|
||||
void UpdateDimensions(const nsIntRect& aRect,
|
||||
const mozilla::ScreenIntSize& aSize);
|
||||
|
||||
protected:
|
||||
friend class PRemoteFrameChild;
|
||||
|
||||
mozilla::ipc::IPCResult RecvSetLayersId(
|
||||
const mozilla::layers::LayersId& aLayersId);
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
explicit RemoteFrameChild(nsFrameLoader* aFrameLoader);
|
||||
~RemoteFrameChild();
|
||||
|
||||
mozilla::layers::LayersId mLayersId;
|
||||
bool mIPCOpen;
|
||||
RefPtr<nsFrameLoader> mFrameLoader;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_RemoteFrameParent_h)
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- 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/RemoteFrameParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentProcessManager.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layout;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
RemoteFrameParent::RemoteFrameParent() : mIPCOpen(false) {}
|
||||
|
||||
RemoteFrameParent::~RemoteFrameParent() {}
|
||||
|
||||
nsresult RemoteFrameParent::Init(const nsString& aPresentationURL,
|
||||
const nsString& aRemoteType) {
|
||||
mIPCOpen = true;
|
||||
|
||||
// FIXME: This should actually use a non-bogus TabContext, probably inherited
|
||||
// from our Manager().
|
||||
OriginAttributes attrs;
|
||||
attrs.mInIsolatedMozBrowser = false;
|
||||
attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
|
||||
attrs.SyncAttributesWithPrivateBrowsing(false);
|
||||
MutableTabContext tabContext;
|
||||
tabContext.SetTabContext(false, 0, UIStateChangeType_Set,
|
||||
UIStateChangeType_Set, attrs, aPresentationURL);
|
||||
|
||||
ProcessPriority initialPriority = PROCESS_PRIORITY_FOREGROUND;
|
||||
|
||||
// Get our ConstructorSender object.
|
||||
RefPtr<nsIContentParent> constructorSender =
|
||||
ContentParent::GetNewOrUsedBrowserProcess(
|
||||
nullptr, aRemoteType, initialPriority, nullptr, false);
|
||||
if (NS_WARN_IF(!constructorSender)) {
|
||||
MOZ_ASSERT(false, "Unable to allocate content process!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
TabId tabId(nsContentUtils::GenerateTabId());
|
||||
cpm->RegisterRemoteFrame(tabId, ContentParentId(0), TabId(0),
|
||||
tabContext.AsIPCTabContext(),
|
||||
constructorSender->ChildID());
|
||||
|
||||
// Construct the TabParent object for our subframe.
|
||||
uint32_t chromeFlags = 0;
|
||||
RefPtr<TabParent> tabParent(
|
||||
new TabParent(constructorSender, tabId, tabContext, chromeFlags));
|
||||
|
||||
PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
|
||||
// DeallocPBrowserParent() releases this ref.
|
||||
tabParent.forget().take(), tabId, TabId(0), tabContext.AsIPCTabContext(),
|
||||
chromeFlags, constructorSender->ChildID(),
|
||||
constructorSender->IsForBrowser());
|
||||
if (NS_WARN_IF(!browser)) {
|
||||
MOZ_ASSERT(false, "Browser Constructor Failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Set our TabParent object to the newly created browser.
|
||||
mTabParent = TabParent::GetFrom(browser);
|
||||
mTabParent->SetOwnerElement(Manager()->GetOwnerElement());
|
||||
mTabParent->InitRendering();
|
||||
|
||||
RenderFrame* rf = mTabParent->GetRenderFrame();
|
||||
if (NS_WARN_IF(!rf)) {
|
||||
MOZ_ASSERT(false, "No RenderFrame");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Send the newly created layers ID back into content.
|
||||
Unused << SendSetLayersId(rf->GetLayersId());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IPCResult RemoteFrameParent::RecvShow(const ScreenIntSize& aSize,
|
||||
const bool& aParentIsActive,
|
||||
const nsSizeMode& aSizeMode) {
|
||||
RenderFrame* rf = mTabParent->GetRenderFrame();
|
||||
if (!rf->AttachLayerManager()) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
Unused << mTabParent->SendShow(aSize, mTabParent->GetShowInfo(),
|
||||
aParentIsActive, aSizeMode);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult RemoteFrameParent::RecvLoadURL(const nsCString& aUrl) {
|
||||
Unused << mTabParent->SendLoadURL(aUrl, mTabParent->GetShowInfo());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult RemoteFrameParent::RecvUpdateDimensions(
|
||||
const DimensionInfo& aDimensions) {
|
||||
Unused << mTabParent->SendUpdateDimensions(aDimensions);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult RemoteFrameParent::RecvRenderLayers(
|
||||
const bool& aEnabled, const bool& aForceRepaint,
|
||||
const layers::LayersObserverEpoch& aEpoch) {
|
||||
Unused << mTabParent->SendRenderLayers(aEnabled, aForceRepaint, aEpoch);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void RemoteFrameParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
mIPCOpen = false;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_RemoteFrameParent_h
|
||||
#define mozilla_dom_RemoteFrameParent_h
|
||||
|
||||
#include "mozilla/dom/PRemoteFrameParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class RemoteFrameParent : public PRemoteFrameParent {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(RemoteFrameParent);
|
||||
|
||||
RemoteFrameParent();
|
||||
|
||||
// Initialize this actor after performing startup.
|
||||
nsresult Init(const nsString& aPresentationURL, const nsString& aRemoteType);
|
||||
|
||||
TabParent* GetTabParent() { return mTabParent; }
|
||||
|
||||
// Get our manager actor.
|
||||
TabParent* Manager() {
|
||||
MOZ_ASSERT(mIPCOpen);
|
||||
return static_cast<TabParent*>(PRemoteFrameParent::Manager());
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class PRemoteFrameParent;
|
||||
|
||||
mozilla::ipc::IPCResult RecvShow(const ScreenIntSize& aSize,
|
||||
const bool& aParentIsActive,
|
||||
const nsSizeMode& aSizeMode);
|
||||
mozilla::ipc::IPCResult RecvLoadURL(const nsCString& aUrl);
|
||||
mozilla::ipc::IPCResult RecvUpdateDimensions(
|
||||
const DimensionInfo& aDimensions);
|
||||
mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled,
|
||||
const bool& aForceRepaint,
|
||||
const LayersObserverEpoch& aEpoch);
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
~RemoteFrameParent();
|
||||
|
||||
RefPtr<TabParent> mTabParent;
|
||||
bool mIPCOpen;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_RemoteFrameParent_h)
|
|
@ -30,6 +30,7 @@
|
|||
#include "mozilla/dom/PaymentRequestChild.h"
|
||||
#include "mozilla/dom/PBrowser.h"
|
||||
#include "mozilla/dom/WindowProxyHolder.h"
|
||||
#include "mozilla/dom/RemoteFrameChild.h"
|
||||
#include "mozilla/gfx/CrossProcessPaint.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
|
@ -3179,6 +3180,18 @@ bool TabChild::DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) {
|
|||
return true;
|
||||
}
|
||||
|
||||
PRemoteFrameChild* TabChild::AllocPRemoteFrameChild(const nsString&,
|
||||
const nsString&) {
|
||||
MOZ_CRASH("We should never be manually allocating PRemoteFrameChild actors");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TabChild::DeallocPRemoteFrameChild(PRemoteFrameChild* aActor) {
|
||||
// This reference was added in RemoteFrameChild::Create.
|
||||
static_cast<RemoteFrameChild*>(aActor)->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
ScreenIntSize TabChild::GetInnerSize() {
|
||||
LayoutDeviceIntSize innerSize =
|
||||
RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
|
||||
|
|
|
@ -670,6 +670,11 @@ class TabChild final : public TabChildBase,
|
|||
|
||||
virtual bool DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) override;
|
||||
|
||||
virtual PRemoteFrameChild* AllocPRemoteFrameChild(
|
||||
const nsString& aName, const nsString& aRemoteType) override;
|
||||
|
||||
virtual bool DeallocPRemoteFrameChild(PRemoteFrameChild* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvDestroy() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/dom/indexedDB/ActorsParent.h"
|
||||
#include "mozilla/dom/IPCBlobUtils.h"
|
||||
#include "mozilla/dom/PaymentRequestParent.h"
|
||||
#include "mozilla/dom/RemoteFrameParent.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
|
@ -303,6 +304,10 @@ void TabParent::SetOwnerElement(Element* aElement) {
|
|||
Unused << SendSetWidgetNativeData(widgetNativeData);
|
||||
}
|
||||
}
|
||||
|
||||
if (mRenderFrame.IsInitialized()) {
|
||||
mRenderFrame.OwnerContentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP TabParent::GetOwnerElement(Element** aElement) {
|
||||
|
@ -616,16 +621,8 @@ void TabParent::LoadURL(nsIURI* aURI) {
|
|||
}
|
||||
|
||||
void TabParent::InitRendering() {
|
||||
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
|
||||
MOZ_ASSERT(!mRenderFrame.IsInitialized());
|
||||
MOZ_ASSERT(frameLoader);
|
||||
|
||||
if (!frameLoader) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRenderFrame.Initialize(frameLoader);
|
||||
mRenderFrame.Initialize(this);
|
||||
MOZ_ASSERT(mRenderFrame.IsInitialized());
|
||||
|
||||
layers::LayersId layersId = mRenderFrame.GetLayersId();
|
||||
|
@ -1015,6 +1012,25 @@ bool TabParent::DeallocPWindowGlobalParent(PWindowGlobalParent* aActor) {
|
|||
return true;
|
||||
}
|
||||
|
||||
IPCResult TabParent::RecvPRemoteFrameConstructor(PRemoteFrameParent* aActor,
|
||||
const nsString& aName,
|
||||
const nsString& aRemoteType) {
|
||||
static_cast<RemoteFrameParent*>(aActor)->Init(aName, aRemoteType);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PRemoteFrameParent* TabParent::AllocPRemoteFrameParent(
|
||||
const nsString& aName, const nsString& aRemoteType) {
|
||||
// Reference freed in DeallocPRemoteFrameParent.
|
||||
return do_AddRef(new RemoteFrameParent()).take();
|
||||
}
|
||||
|
||||
bool TabParent::DeallocPRemoteFrameParent(PRemoteFrameParent* aActor) {
|
||||
// Free reference from AllocPRemoteFrameParent.
|
||||
static_cast<RemoteFrameParent*>(aActor)->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
|
||||
int32_t aButton, int32_t aClickCount,
|
||||
int32_t aModifiers,
|
||||
|
|
|
@ -316,6 +316,15 @@ class TabParent final : public PBrowserParent,
|
|||
virtual mozilla::ipc::IPCResult RecvPWindowGlobalConstructor(
|
||||
PWindowGlobalParent* aActor, const WindowGlobalInit& aInit) override;
|
||||
|
||||
PRemoteFrameParent* AllocPRemoteFrameParent(const nsString& aPresentationURL,
|
||||
const nsString& aRemoteType);
|
||||
|
||||
bool DeallocPRemoteFrameParent(PRemoteFrameParent* aActor);
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvPRemoteFrameConstructor(
|
||||
PRemoteFrameParent* aActor, const nsString& aPresentationURL,
|
||||
const nsString& aRemoteType) override;
|
||||
|
||||
void LoadURL(nsIURI* aURI);
|
||||
|
||||
void InitRendering();
|
||||
|
@ -549,6 +558,8 @@ class TabParent final : public PBrowserParent,
|
|||
|
||||
void NavigateByKey(bool aForward, bool aForDocumentNavigation);
|
||||
|
||||
ShowInfo GetShowInfo();
|
||||
|
||||
protected:
|
||||
bool ReceiveMessage(
|
||||
const nsString& aMessage, bool aSync, ipc::StructuredCloneData* aData,
|
||||
|
@ -717,8 +728,6 @@ class TabParent final : public PBrowserParent,
|
|||
int32_t mActiveSupressDisplayportCount;
|
||||
#endif
|
||||
|
||||
ShowInfo GetShowInfo();
|
||||
|
||||
private:
|
||||
// This is used when APZ needs to find the TabParent associated with a layer
|
||||
// to dispatch events.
|
||||
|
|
|
@ -47,6 +47,8 @@ EXPORTS.mozilla.dom += [
|
|||
'nsIContentChild.h',
|
||||
'nsIContentParent.h',
|
||||
'PermissionMessageUtils.h',
|
||||
'RemoteFrameChild.h',
|
||||
'RemoteFrameParent.h',
|
||||
'TabChild.h',
|
||||
'TabContext.h',
|
||||
'TabMessageUtils.h',
|
||||
|
@ -86,6 +88,8 @@ UNIFIED_SOURCES += [
|
|||
'PermissionMessageUtils.cpp',
|
||||
'PreallocatedProcessManager.cpp',
|
||||
'ProcessPriorityManager.cpp',
|
||||
'RemoteFrameChild.cpp',
|
||||
'RemoteFrameParent.cpp',
|
||||
'SharedMap.cpp',
|
||||
'SharedStringMap.cpp',
|
||||
'StructuredCloneData.cpp',
|
||||
|
@ -120,6 +124,7 @@ IPDL_SOURCES += [
|
|||
'PPluginWidget.ipdl',
|
||||
'PProcessHangMonitor.ipdl',
|
||||
'PrefsTypes.ipdlh',
|
||||
'PRemoteFrame.ipdl',
|
||||
'PTabContext.ipdlh',
|
||||
'PURLClassifier.ipdl',
|
||||
'PURLClassifierInfo.ipdlh',
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/PIPCBlobInputStreamParent.h"
|
||||
#include "mozilla/ipc/IPCStreamAlloc.h"
|
||||
#include "mozilla/ipc/IPCStreamDestination.h"
|
||||
#include "mozilla/ipc/IPCStreamSource.h"
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include "nsPrintfCString.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
// XXX need another bug to move this to a common header.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<h1>This is a dummy file!</h1>
|
|
@ -23,3 +23,7 @@ support-files =
|
|||
!/dom/canvas/test/captureStream_common.js
|
||||
[test_Preallocated.html]
|
||||
skip-if = !e10s
|
||||
[test_force_oop_iframe.html]
|
||||
skip-if = !e10s || webrender # oop-iframes trigger a debug assertion in webrender picture caching
|
||||
support-files =
|
||||
file_dummy.html
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/AddTask.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/ChromeTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
/* eslint-env mozilla/frame-script */
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["browser.fission.oopif.attribute", true]]});
|
||||
|
||||
// This iframe should be loaded out of process. Unfortunately as of the time
|
||||
// of this test's creation, many different events which we could use to detect
|
||||
// this load have not been implemented yet.
|
||||
let contentCreated = ChromeTask.spawn(null, async function() {
|
||||
let wgp = await new Promise(resolve => {
|
||||
function observer(parent) {
|
||||
info("WGP with origin: " + parent.documentPrincipal.origin);
|
||||
if (parent.documentPrincipal.origin !== "http://mochi.test:8888") {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(observer, "window-global-created");
|
||||
resolve(parent);
|
||||
}
|
||||
Services.obs.addObserver(observer, "window-global-created");
|
||||
});
|
||||
|
||||
is(wgp.isInProcess, false, "not in-process");
|
||||
ok(wgp.rootFrameLoader, "Has frameloader");
|
||||
ok(wgp.documentPrincipal, "Has document principal");
|
||||
});
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("fission", "true");
|
||||
iframe.setAttribute("src", "file_dummy.html");
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
// Check that this isn't loaded in-process, or using a nested tabParent object.
|
||||
let frameLoader = SpecialPowers.wrap(iframe).frameLoader;
|
||||
is(frameLoader.docShell, null);
|
||||
is(frameLoader.tabParent, null);
|
||||
|
||||
await contentCreated;
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -4,7 +4,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using mozilla::TimeStamp from "mozilla/TimeStamp.h";
|
||||
using mozilla::gfx::OpenVRControllerType from "gfxVR.h";
|
||||
using mozilla::gfx::OpenVRControllerType from "VRMessageUtils.h";
|
||||
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
||||
|
||||
include GraphicsMessages;
|
||||
|
|
|
@ -1373,7 +1373,10 @@ function TypedArraySubarray(begin, end) {
|
|||
}
|
||||
|
||||
// Steps 4-6.
|
||||
var buffer = TypedArrayBuffer(obj);
|
||||
var buffer = ViewedArrayBufferIfReified(obj);
|
||||
if (buffer === null) {
|
||||
buffer = TypedArrayBuffer(obj);
|
||||
}
|
||||
var srcLength = TypedArrayLength(obj);
|
||||
|
||||
// Step 14 (Reordered because otherwise it'd be observable that we reset
|
||||
|
|
|
@ -128,6 +128,7 @@ static inline const MDefinition* GetObject(const MDefinition* ins) {
|
|||
case MDefinition::Opcode::MaybeCopyElementsForWrite:
|
||||
case MDefinition::Opcode::MaybeToDoubleElement:
|
||||
case MDefinition::Opcode::TypedArrayLength:
|
||||
case MDefinition::Opcode::TypedArrayByteOffset:
|
||||
case MDefinition::Opcode::SetTypedObjectOffset:
|
||||
case MDefinition::Opcode::SetDisjointTypedElements:
|
||||
case MDefinition::Opcode::ArrayPopShift:
|
||||
|
|
|
@ -7449,12 +7449,81 @@ void CodeGenerator::visitTypedArrayLength(LTypedArrayLength* lir) {
|
|||
masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitTypedArrayByteOffset(LTypedArrayByteOffset* lir) {
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register out = ToRegister(lir->output());
|
||||
masm.unboxInt32(Address(obj, TypedArrayObject::byteOffsetOffset()), out);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitTypedArrayElements(LTypedArrayElements* lir) {
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register out = ToRegister(lir->output());
|
||||
masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), out);
|
||||
}
|
||||
|
||||
static constexpr bool ValidateShiftRange(Scalar::Type from, Scalar::Type to) {
|
||||
for (Scalar::Type type = from; type < to; type = Scalar::Type(type + 1)) {
|
||||
if (TypedArrayShift(type) != TypedArrayShift(from)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CodeGenerator::visitTypedArrayElementShift(LTypedArrayElementShift* lir) {
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register out = ToRegister(lir->output());
|
||||
|
||||
static_assert(Scalar::Int8 == 0, "Int8 is the first typed array class");
|
||||
static_assert((Scalar::Uint8Clamped - Scalar::Int8) ==
|
||||
Scalar::MaxTypedArrayViewType - 1,
|
||||
"Uint8Clamped is the last typed array class");
|
||||
|
||||
Label zero, one, two, done;
|
||||
|
||||
masm.loadObjClassUnsafe(obj, out);
|
||||
|
||||
static_assert(ValidateShiftRange(Scalar::Int8, Scalar::Int16),
|
||||
"shift amount is zero in [Int8, Int16)");
|
||||
masm.branchPtr(Assembler::Below, out,
|
||||
ImmPtr(TypedArrayObject::classForType(Scalar::Int16)), &zero);
|
||||
|
||||
static_assert(ValidateShiftRange(Scalar::Int16, Scalar::Int32),
|
||||
"shift amount is one in [Int16, Int32)");
|
||||
masm.branchPtr(Assembler::Below, out,
|
||||
ImmPtr(TypedArrayObject::classForType(Scalar::Int32)), &one);
|
||||
|
||||
static_assert(ValidateShiftRange(Scalar::Int32, Scalar::Float64),
|
||||
"shift amount is two in [Int32, Float64)");
|
||||
masm.branchPtr(Assembler::Below, out,
|
||||
ImmPtr(TypedArrayObject::classForType(Scalar::Float64)), &two);
|
||||
|
||||
static_assert(ValidateShiftRange(Scalar::Float64, Scalar::Uint8Clamped),
|
||||
"shift amount is three in [Float64, Uint8Clamped)");
|
||||
static_assert(
|
||||
ValidateShiftRange(Scalar::Uint8Clamped, Scalar::MaxTypedArrayViewType),
|
||||
"shift amount is zero in [Uint8Clamped, MaxTypedArrayViewType)");
|
||||
masm.branchPtr(Assembler::AboveOrEqual, out,
|
||||
ImmPtr(TypedArrayObject::classForType(Scalar::Uint8Clamped)),
|
||||
&zero);
|
||||
|
||||
masm.move32(Imm32(3), out);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&two);
|
||||
masm.move32(Imm32(2), out);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&one);
|
||||
masm.move32(Imm32(1), out);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&zero);
|
||||
masm.move32(Imm32(0), out);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitSetDisjointTypedElements(
|
||||
LSetDisjointTypedElements* lir) {
|
||||
Register target = ToRegister(lir->target());
|
||||
|
|
|
@ -149,6 +149,8 @@
|
|||
_(IntrinsicIsPossiblyWrappedTypedArray) \
|
||||
_(IntrinsicTypedArrayLength) \
|
||||
_(IntrinsicPossiblyWrappedTypedArrayLength) \
|
||||
_(IntrinsicTypedArrayByteOffset) \
|
||||
_(IntrinsicTypedArrayElementShift) \
|
||||
_(IntrinsicSetDisjointTypedElements) \
|
||||
\
|
||||
_(IntrinsicObjectIsTypedObject) \
|
||||
|
|
|
@ -9076,6 +9076,45 @@ MInstruction* IonBuilder::addArrayBufferByteLength(MDefinition* obj) {
|
|||
return ins;
|
||||
}
|
||||
|
||||
TypedArrayObject* IonBuilder::tryTypedArrayEmbedConstantElements(
|
||||
MDefinition* obj) {
|
||||
JSObject* object = nullptr;
|
||||
if (MConstant* objConst = obj->maybeConstantValue()) {
|
||||
if (objConst->type() == MIRType::Object) {
|
||||
object = &objConst->toObject();
|
||||
}
|
||||
} else if (TemporaryTypeSet* types = obj->resultTypeSet()) {
|
||||
object = types->maybeSingleton();
|
||||
}
|
||||
if (!object || !object->isSingleton()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypedArrayObject* tarr = &object->as<TypedArrayObject>();
|
||||
|
||||
// TypedArrays are only singletons when created with a (Shared)ArrayBuffer
|
||||
// and a length greater or equal to |SINGLETON_BYTE_LENGTH|.
|
||||
MOZ_ASSERT(tarr->hasBuffer());
|
||||
MOZ_ASSERT(tarr->byteLength() >= TypedArrayObject::SINGLETON_BYTE_LENGTH ||
|
||||
tarr->hasDetachedBuffer());
|
||||
|
||||
// TypedArrays using an ArrayBuffer don't have nursery-allocated data, see
|
||||
// |ArrayBufferViewObject::init(...)|.
|
||||
MOZ_ASSERT(!tarr->runtimeFromMainThread()->gc.nursery().isInside(
|
||||
tarr->dataPointerEither()));
|
||||
|
||||
// The 'data' pointer of TypedArrayObject can change in rare circumstances
|
||||
// (ArrayBufferObject::setNewData).
|
||||
TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarr);
|
||||
if (tarrKey->unknownProperties()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!tarr->isSharedMemory()) {
|
||||
tarrKey->watchStateChangeForTypedArrayData(constraints());
|
||||
}
|
||||
return tarr;
|
||||
}
|
||||
|
||||
void IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
|
||||
BoundsChecking checking,
|
||||
MDefinition** index,
|
||||
|
@ -9083,49 +9122,25 @@ void IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
|
|||
MInstruction** elements) {
|
||||
MOZ_ASSERT((index != nullptr) == (elements != nullptr));
|
||||
|
||||
JSObject* tarr = nullptr;
|
||||
|
||||
if (MConstant* objConst = obj->maybeConstantValue()) {
|
||||
if (objConst->type() == MIRType::Object) {
|
||||
tarr = &objConst->toObject();
|
||||
}
|
||||
} else if (TemporaryTypeSet* types = obj->resultTypeSet()) {
|
||||
tarr = types->maybeSingleton();
|
||||
}
|
||||
|
||||
if (tarr) {
|
||||
SharedMem<void*> data = tarr->as<TypedArrayObject>().dataPointerEither();
|
||||
if (TypedArrayObject* tarr = tryTypedArrayEmbedConstantElements(obj)) {
|
||||
// Bug 979449 - Optimistically embed the elements and use TI to
|
||||
// invalidate if we move them.
|
||||
bool isTenured =
|
||||
!tarr->runtimeFromMainThread()->gc.nursery().isInside(data);
|
||||
if (isTenured && tarr->isSingleton()) {
|
||||
// The 'data' pointer of TypedArrayObject can change in rare circumstances
|
||||
// (ArrayBufferObject::changeContents).
|
||||
TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarr);
|
||||
if (!tarrKey->unknownProperties()) {
|
||||
if (tarr->is<TypedArrayObject>()) {
|
||||
tarrKey->watchStateChangeForTypedArrayData(constraints());
|
||||
}
|
||||
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
|
||||
int32_t len =
|
||||
AssertedCast<int32_t>(tarr->as<TypedArrayObject>().length());
|
||||
*length = MConstant::New(alloc(), Int32Value(len));
|
||||
current->add(*length);
|
||||
int32_t len = AssertedCast<int32_t>(tarr->length());
|
||||
*length = MConstant::New(alloc(), Int32Value(len));
|
||||
current->add(*length);
|
||||
|
||||
if (index) {
|
||||
if (checking == DoBoundsCheck) {
|
||||
*index = addBoundsCheck(*index, *length);
|
||||
}
|
||||
|
||||
*elements = MConstantElements::New(alloc(), data);
|
||||
current->add(*elements);
|
||||
}
|
||||
return;
|
||||
if (index) {
|
||||
if (checking == DoBoundsCheck) {
|
||||
*index = addBoundsCheck(*index, *length);
|
||||
}
|
||||
|
||||
*elements = MConstantElements::New(alloc(), tarr->dataPointerEither());
|
||||
current->add(*elements);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
*length = MTypedArrayLength::New(alloc(), obj);
|
||||
|
@ -9141,6 +9156,21 @@ void IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
|
|||
}
|
||||
}
|
||||
|
||||
MInstruction* IonBuilder::addTypedArrayByteOffset(MDefinition* obj) {
|
||||
MInstruction* byteOffset;
|
||||
if (TypedArrayObject* tarr = tryTypedArrayEmbedConstantElements(obj)) {
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
|
||||
int32_t offset = AssertedCast<int32_t>(tarr->byteOffset());
|
||||
byteOffset = MConstant::New(alloc(), Int32Value(offset));
|
||||
} else {
|
||||
byteOffset = MTypedArrayByteOffset::New(alloc(), obj);
|
||||
}
|
||||
|
||||
current->add(byteOffset);
|
||||
return byteOffset;
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok> IonBuilder::jsop_getelem_typed(MDefinition* obj,
|
||||
MDefinition* index,
|
||||
Scalar::Type arrayType) {
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#include "jit/OptimizationTracking.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class TypedArrayObject;
|
||||
|
||||
namespace jit {
|
||||
|
||||
class CodeGenerator;
|
||||
|
@ -493,6 +496,8 @@ class IonBuilder : public MIRGenerator,
|
|||
|
||||
MInstruction* addArrayBufferByteLength(MDefinition* obj);
|
||||
|
||||
TypedArrayObject* tryTypedArrayEmbedConstantElements(MDefinition* obj);
|
||||
|
||||
// Add instructions to compute a typed array's length and data. Also
|
||||
// optionally convert |*index| into a bounds-checked definition, if
|
||||
// requested.
|
||||
|
@ -511,6 +516,10 @@ class IonBuilder : public MIRGenerator,
|
|||
return length;
|
||||
}
|
||||
|
||||
// Add an instruction to compute a typed array's byte offset to the current
|
||||
// block.
|
||||
MInstruction* addTypedArrayByteOffset(MDefinition* obj);
|
||||
|
||||
AbortReasonOr<Ok> improveThisTypesForCall();
|
||||
|
||||
MDefinition* getCallee();
|
||||
|
@ -778,6 +787,8 @@ class IonBuilder : public MIRGenerator,
|
|||
InliningResult inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo);
|
||||
InliningResult inlineTypedArrayLength(CallInfo& callInfo);
|
||||
InliningResult inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo);
|
||||
InliningResult inlineTypedArrayByteOffset(CallInfo& callInfo);
|
||||
InliningResult inlineTypedArrayElementShift(CallInfo& callInfo);
|
||||
InliningResult inlineSetDisjointTypedElements(CallInfo& callInfo);
|
||||
|
||||
// TypedObject intrinsics and natives.
|
||||
|
|
|
@ -2836,12 +2836,25 @@ void LIRGenerator::visitTypedArrayLength(MTypedArrayLength* ins) {
|
|||
ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitTypedArrayByteOffset(MTypedArrayByteOffset* ins) {
|
||||
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
|
||||
define(new (alloc()) LTypedArrayByteOffset(useRegisterAtStart(ins->object())),
|
||||
ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitTypedArrayElements(MTypedArrayElements* ins) {
|
||||
MOZ_ASSERT(ins->type() == MIRType::Elements);
|
||||
define(new (alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())),
|
||||
ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitTypedArrayElementShift(MTypedArrayElementShift* ins) {
|
||||
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
|
||||
define(new (alloc())
|
||||
LTypedArrayElementShift(useRegisterAtStart(ins->object())),
|
||||
ins);
|
||||
}
|
||||
|
||||
void LIRGenerator::visitSetDisjointTypedElements(
|
||||
MSetDisjointTypedElements* ins) {
|
||||
MOZ_ASSERT(ins->type() == MIRType::None);
|
||||
|
|
|
@ -371,6 +371,10 @@ IonBuilder::InliningResult IonBuilder::inlineNativeCall(CallInfo& callInfo,
|
|||
return inlinePossiblyWrappedTypedArrayLength(callInfo);
|
||||
case InlinableNative::IntrinsicTypedArrayLength:
|
||||
return inlineTypedArrayLength(callInfo);
|
||||
case InlinableNative::IntrinsicTypedArrayByteOffset:
|
||||
return inlineTypedArrayByteOffset(callInfo);
|
||||
case InlinableNative::IntrinsicTypedArrayElementShift:
|
||||
return inlineTypedArrayElementShift(callInfo);
|
||||
case InlinableNative::IntrinsicSetDisjointTypedElements:
|
||||
return inlineSetDisjointTypedElements(callInfo);
|
||||
|
||||
|
@ -421,8 +425,8 @@ IonBuilder::InliningResult IonBuilder::inlineNativeGetter(CallInfo& callInfo,
|
|||
|
||||
// Try to optimize typed array lengths.
|
||||
if (TypedArrayObject::isOriginalLengthGetter(native)) {
|
||||
Scalar::Type type = thisTypes->getTypedArrayType(constraints());
|
||||
if (type == Scalar::MaxTypedArrayViewType) {
|
||||
if (thisTypes->forAllClasses(constraints(), IsTypedArrayClass) !=
|
||||
TemporaryTypeSet::ForAllResult::ALL_TRUE) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
|
@ -431,6 +435,18 @@ IonBuilder::InliningResult IonBuilder::inlineNativeGetter(CallInfo& callInfo,
|
|||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
// Try to optimize typed array byteOffsets.
|
||||
if (TypedArrayObject::isOriginalByteOffsetGetter(native)) {
|
||||
if (thisTypes->forAllClasses(constraints(), IsTypedArrayClass) !=
|
||||
TemporaryTypeSet::ForAllResult::ALL_TRUE) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MInstruction* byteOffset = addTypedArrayByteOffset(thisArg);
|
||||
current->push(byteOffset);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
// Try to optimize RegExp getters.
|
||||
RegExpFlag mask = NoFlags;
|
||||
if (RegExpObject::isOriginalFlagGetter(native, &mask)) {
|
||||
|
@ -3195,6 +3211,51 @@ IonBuilder::InliningResult IonBuilder::inlineTypedArrayLength(
|
|||
return inlinePossiblyWrappedTypedArrayLength(callInfo);
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult IonBuilder::inlineTypedArrayByteOffset(
|
||||
CallInfo& callInfo) {
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
if (callInfo.getArg(0)->type() != MIRType::Object) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
if (getInlineReturnType() != MIRType::Int32) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MInstruction* byteOffset = addTypedArrayByteOffset(callInfo.getArg(0));
|
||||
current->push(byteOffset);
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult IonBuilder::inlineTypedArrayElementShift(
|
||||
CallInfo& callInfo) {
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
if (callInfo.getArg(0)->type() != MIRType::Object) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
if (getInlineReturnType() != MIRType::Int32) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) {
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
auto* ins = MTypedArrayElementShift::New(alloc(), callInfo.getArg(0));
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult IonBuilder::inlineSetDisjointTypedElements(
|
||||
CallInfo& callInfo) {
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
|
|
|
@ -459,33 +459,6 @@ static bool MaybeCallable(CompilerConstraintList* constraints,
|
|||
return types->maybeCallable(constraints);
|
||||
}
|
||||
|
||||
/* static */ const char* AliasSet::Name(size_t flag) {
|
||||
switch (flag) {
|
||||
case 0:
|
||||
return "ObjectFields";
|
||||
case 1:
|
||||
return "Element";
|
||||
case 2:
|
||||
return "UnboxedElement";
|
||||
case 3:
|
||||
return "DynamicSlot";
|
||||
case 4:
|
||||
return "FixedSlot";
|
||||
case 5:
|
||||
return "DOMProperty";
|
||||
case 6:
|
||||
return "FrameArgument";
|
||||
case 7:
|
||||
return "WasmGlobalVar";
|
||||
case 8:
|
||||
return "WasmHeap";
|
||||
case 9:
|
||||
return "TypedArrayLength";
|
||||
default:
|
||||
MOZ_CRASH("Unknown flag");
|
||||
}
|
||||
}
|
||||
|
||||
void MTest::cacheOperandMightEmulateUndefined(
|
||||
CompilerConstraintList* constraints) {
|
||||
MOZ_ASSERT(operandMightEmulateUndefined());
|
||||
|
|
|
@ -332,21 +332,21 @@ class AliasSet {
|
|||
public:
|
||||
enum Flag {
|
||||
None_ = 0,
|
||||
ObjectFields = 1 << 0, // shape, class, slots, length etc.
|
||||
Element = 1 << 1, // A Value member of obj->elements or
|
||||
// a typed object.
|
||||
UnboxedElement = 1 << 2, // An unboxed scalar or reference member of
|
||||
// typed object or unboxed object.
|
||||
DynamicSlot = 1 << 3, // A Value member of obj->slots.
|
||||
FixedSlot = 1 << 4, // A Value member of obj->fixedSlots().
|
||||
DOMProperty = 1 << 5, // A DOM property
|
||||
FrameArgument = 1 << 6, // An argument kept on the stack frame
|
||||
WasmGlobalVar = 1 << 7, // An asm.js/wasm private global var
|
||||
WasmHeap = 1 << 8, // An asm.js/wasm heap load
|
||||
WasmHeapMeta = 1 << 9, // The asm.js/wasm heap base pointer and
|
||||
// bounds check limit, in Tls.
|
||||
TypedArrayLength = 1 << 10, // A typed array's length
|
||||
WasmGlobalCell = 1 << 11, // A wasm global cell
|
||||
ObjectFields = 1 << 0, // shape, class, slots, length etc.
|
||||
Element = 1 << 1, // A Value member of obj->elements or
|
||||
// a typed object.
|
||||
UnboxedElement = 1 << 2, // An unboxed scalar or reference member of
|
||||
// typed object or unboxed object.
|
||||
DynamicSlot = 1 << 3, // A Value member of obj->slots.
|
||||
FixedSlot = 1 << 4, // A Value member of obj->fixedSlots().
|
||||
DOMProperty = 1 << 5, // A DOM property
|
||||
FrameArgument = 1 << 6, // An argument kept on the stack frame
|
||||
WasmGlobalVar = 1 << 7, // An asm.js/wasm private global var
|
||||
WasmHeap = 1 << 8, // An asm.js/wasm heap load
|
||||
WasmHeapMeta = 1 << 9, // The asm.js/wasm heap base pointer and
|
||||
// bounds check limit, in Tls.
|
||||
TypedArrayLengthOrOffset = 1 << 10, // A typed array's length or byteOffset
|
||||
WasmGlobalCell = 1 << 11, // A wasm global cell
|
||||
Last = WasmGlobalCell,
|
||||
Any = Last | (Last - 1),
|
||||
|
||||
|
@ -362,8 +362,6 @@ class AliasSet {
|
|||
explicit AliasSet(uint32_t flags) : flags_(flags) {}
|
||||
|
||||
public:
|
||||
static const char* Name(size_t flag);
|
||||
|
||||
inline bool isNone() const { return flags_ == None_; }
|
||||
uint32_t flags() const { return flags_ & Any; }
|
||||
inline bool isStore() const { return !!(flags_ & Store_); }
|
||||
|
@ -7142,7 +7140,31 @@ class MTypedArrayLength : public MUnaryInstruction,
|
|||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::Load(AliasSet::TypedArrayLength);
|
||||
return AliasSet::Load(AliasSet::TypedArrayLengthOrOffset);
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator& alloc) override;
|
||||
};
|
||||
|
||||
// Read the byteOffset of a typed array.
|
||||
class MTypedArrayByteOffset : public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data {
|
||||
explicit MTypedArrayByteOffset(MDefinition* obj)
|
||||
: MUnaryInstruction(classOpcode, obj) {
|
||||
setResultType(MIRType::Int32);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(TypedArrayByteOffset)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, object))
|
||||
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::Load(AliasSet::TypedArrayLengthOrOffset);
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator& alloc) override;
|
||||
|
@ -7172,6 +7194,28 @@ class MTypedArrayElements : public MUnaryInstruction,
|
|||
ALLOW_CLONE(MTypedArrayElements)
|
||||
};
|
||||
|
||||
// Return the element shift of a typed array, i.e. the shift value so that
|
||||
// |1 << shift| is equal to the element size.
|
||||
class MTypedArrayElementShift : public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data {
|
||||
explicit MTypedArrayElementShift(MDefinition* obj)
|
||||
: MUnaryInstruction(classOpcode, obj) {
|
||||
setResultType(MIRType::Int32);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(TypedArrayElementShift)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, object))
|
||||
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator& alloc) override;
|
||||
};
|
||||
|
||||
class MSetDisjointTypedElements : public MTernaryInstruction,
|
||||
public NoTypePolicy::Data {
|
||||
explicit MSetDisjointTypedElements(MDefinition* target,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "jit/RangeAnalysis.h"
|
||||
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/IonAnalysis.h"
|
||||
|
@ -1755,6 +1756,24 @@ void MTypedArrayLength::computeRange(TempAllocator& alloc) {
|
|||
setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX));
|
||||
}
|
||||
|
||||
void MTypedArrayByteOffset::computeRange(TempAllocator& alloc) {
|
||||
setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX));
|
||||
}
|
||||
|
||||
void MTypedArrayElementShift::computeRange(TempAllocator& alloc) {
|
||||
using mozilla::tl::FloorLog2;
|
||||
|
||||
constexpr auto MaxTypedArrayShift = FloorLog2<sizeof(double)>::value;
|
||||
|
||||
#define ASSERT_MAX_SHIFT(T, N) \
|
||||
static_assert(FloorLog2<sizeof(T)>::value <= MaxTypedArrayShift, \
|
||||
"unexpected typed array type exceeding 64-bits storage");
|
||||
JS_FOR_EACH_TYPED_ARRAY(ASSERT_MAX_SHIFT)
|
||||
#undef ASSERT_MAX_SHIFT
|
||||
|
||||
setRange(Range::NewUInt32Range(alloc, 0, MaxTypedArrayShift));
|
||||
}
|
||||
|
||||
void MStringLength::computeRange(TempAllocator& alloc) {
|
||||
static_assert(JSString::MAX_LENGTH <= UINT32_MAX,
|
||||
"NewUInt32Range requires a uint32 value");
|
||||
|
|
|
@ -3833,6 +3833,19 @@ class LTypedArrayLength : public LInstructionHelper<1, 1, 0> {
|
|||
const LAllocation* object() { return getOperand(0); }
|
||||
};
|
||||
|
||||
// Read the byteOffset of a typed array.
|
||||
class LTypedArrayByteOffset : public LInstructionHelper<1, 1, 0> {
|
||||
public:
|
||||
LIR_HEADER(TypedArrayByteOffset)
|
||||
|
||||
explicit LTypedArrayByteOffset(const LAllocation& obj)
|
||||
: LInstructionHelper(classOpcode) {
|
||||
setOperand(0, obj);
|
||||
}
|
||||
|
||||
const LAllocation* object() { return getOperand(0); }
|
||||
};
|
||||
|
||||
// Load a typed array's elements vector.
|
||||
class LTypedArrayElements : public LInstructionHelper<1, 1, 0> {
|
||||
public:
|
||||
|
@ -3845,6 +3858,19 @@ class LTypedArrayElements : public LInstructionHelper<1, 1, 0> {
|
|||
const LAllocation* object() { return getOperand(0); }
|
||||
};
|
||||
|
||||
// Return the element shift of a typed array.
|
||||
class LTypedArrayElementShift : public LInstructionHelper<1, 1, 0> {
|
||||
public:
|
||||
LIR_HEADER(TypedArrayElementShift)
|
||||
|
||||
explicit LTypedArrayElementShift(const LAllocation& obj)
|
||||
: LInstructionHelper(classOpcode) {
|
||||
setOperand(0, obj);
|
||||
}
|
||||
|
||||
const LAllocation* object() { return getOperand(0); }
|
||||
};
|
||||
|
||||
// Assign
|
||||
//
|
||||
// target[targetOffset..targetOffset + source.length] =
|
||||
|
|
|
@ -1143,10 +1143,10 @@ static bool intrinsic_TypedArrayLength(JSContext* cx, unsigned argc,
|
|||
Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
MOZ_ASSERT(TypedArrayObject::is(args[0]));
|
||||
|
||||
JSObject* obj = &args[0].toObject();
|
||||
MOZ_ASSERT(obj->is<TypedArrayObject>());
|
||||
args.rval().setInt32(obj->as<TypedArrayObject>().length());
|
||||
args.rval().set(TypedArrayObject::lengthValue(
|
||||
&args[0].toObject().as<TypedArrayObject>()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2603,8 +2603,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
IntrinsicIsTypedArrayConstructor),
|
||||
|
||||
JS_FN("TypedArrayBuffer", intrinsic_TypedArrayBuffer, 1, 0),
|
||||
JS_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1, 0),
|
||||
JS_FN("TypedArrayElementShift", intrinsic_TypedArrayElementShift, 1, 0),
|
||||
JS_INLINABLE_FN("TypedArrayByteOffset", intrinsic_TypedArrayByteOffset, 1,
|
||||
0, IntrinsicTypedArrayByteOffset),
|
||||
JS_INLINABLE_FN("TypedArrayElementShift", intrinsic_TypedArrayElementShift,
|
||||
1, 0, IntrinsicTypedArrayElementShift),
|
||||
|
||||
JS_INLINABLE_FN("TypedArrayLength", intrinsic_TypedArrayLength, 1, 0,
|
||||
IntrinsicTypedArrayLength),
|
||||
|
|
|
@ -1979,15 +1979,16 @@ namespace {
|
|||
class ConstraintDataFreezeObjectForTypedArrayData {
|
||||
NativeObject* obj;
|
||||
|
||||
uintptr_t viewData;
|
||||
void* viewData;
|
||||
uint32_t length;
|
||||
|
||||
public:
|
||||
explicit ConstraintDataFreezeObjectForTypedArrayData(TypedArrayObject& tarray)
|
||||
: obj(&tarray),
|
||||
viewData(tarray.dataPointerEither().unwrapValue()),
|
||||
viewData(tarray.dataPointerUnshared()),
|
||||
length(tarray.length()) {
|
||||
MOZ_ASSERT(tarray.isSingleton());
|
||||
MOZ_ASSERT(!tarray.isSharedMemory());
|
||||
}
|
||||
|
||||
const char* kind() { return "freezeObjectForTypedArrayData"; }
|
||||
|
@ -1998,8 +1999,7 @@ class ConstraintDataFreezeObjectForTypedArrayData {
|
|||
ObjectGroup* group) {
|
||||
MOZ_ASSERT(obj->group() == group);
|
||||
TypedArrayObject& tarr = obj->as<TypedArrayObject>();
|
||||
return tarr.dataPointerEither().unwrapValue() != viewData ||
|
||||
tarr.length() != length;
|
||||
return tarr.dataPointerUnshared() != viewData || tarr.length() != length;
|
||||
}
|
||||
|
||||
bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx,
|
||||
|
|
|
@ -1452,6 +1452,12 @@ static bool TypedArray_lengthGetter(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return TypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx, argc, vp);
|
||||
}
|
||||
|
||||
static bool TypedArray_byteOffsetGetter(JSContext* cx, unsigned argc,
|
||||
Value* vp) {
|
||||
return TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>(cx, argc,
|
||||
vp);
|
||||
}
|
||||
|
||||
bool BufferGetterImpl(JSContext* cx, const CallArgs& args) {
|
||||
MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
|
||||
Rooted<TypedArrayObject*> tarray(
|
||||
|
@ -1506,8 +1512,7 @@ static bool TypedArray_toStringTagGetter(JSContext* cx, unsigned argc,
|
|||
JS_PSG("buffer", TypedArray_bufferGetter, 0),
|
||||
JS_PSG("byteLength",
|
||||
TypedArrayObject::Getter<TypedArrayObject::byteLengthValue>, 0),
|
||||
JS_PSG("byteOffset",
|
||||
TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>, 0),
|
||||
JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
|
||||
JS_SYM_GET(toStringTag, TypedArray_toStringTagGetter, 0),
|
||||
JS_PS_END};
|
||||
|
||||
|
@ -2031,6 +2036,10 @@ const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
|
|||
return native == TypedArray_lengthGetter;
|
||||
}
|
||||
|
||||
/* static */ bool TypedArrayObject::isOriginalByteOffsetGetter(Native native) {
|
||||
return native == TypedArray_byteOffsetGetter;
|
||||
}
|
||||
|
||||
bool js::IsTypedArrayConstructor(const JSObject* obj) {
|
||||
#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
|
||||
if (IsNativeFunction(obj, N##Array::class_constructor)) { \
|
||||
|
|
|
@ -43,6 +43,9 @@ class TypedArrayObject : public ArrayBufferViewObject {
|
|||
static constexpr int lengthOffset() {
|
||||
return NativeObject::getFixedSlotOffset(LENGTH_SLOT);
|
||||
}
|
||||
static constexpr int byteOffsetOffset() {
|
||||
return NativeObject::getFixedSlotOffset(BYTEOFFSET_SLOT);
|
||||
}
|
||||
static constexpr int dataOffset() {
|
||||
return NativeObject::getPrivateDataOffset(DATA_SLOT);
|
||||
}
|
||||
|
@ -148,6 +151,8 @@ class TypedArrayObject : public ArrayBufferViewObject {
|
|||
|
||||
static bool isOriginalLengthGetter(Native native);
|
||||
|
||||
static bool isOriginalByteOffsetGetter(Native native);
|
||||
|
||||
static void finalize(FreeOp* fop, JSObject* obj);
|
||||
static size_t objectMoved(JSObject* obj, JSObject* old);
|
||||
|
||||
|
@ -274,7 +279,7 @@ bool DefineTypedArrayElement(JSContext* cx, HandleObject arr, uint64_t index,
|
|||
Handle<PropertyDescriptor> desc,
|
||||
ObjectOpResult& result);
|
||||
|
||||
static inline unsigned TypedArrayShift(Scalar::Type viewType) {
|
||||
static inline constexpr unsigned TypedArrayShift(Scalar::Type viewType) {
|
||||
switch (viewType) {
|
||||
case Scalar::Int8:
|
||||
case Scalar::Uint8:
|
||||
|
@ -290,9 +295,9 @@ static inline unsigned TypedArrayShift(Scalar::Type viewType) {
|
|||
case Scalar::Int64:
|
||||
case Scalar::Float64:
|
||||
return 3;
|
||||
default:;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected array type");
|
||||
}
|
||||
MOZ_CRASH("Unexpected array type");
|
||||
}
|
||||
|
||||
static inline unsigned TypedArrayElemSize(Scalar::Type viewType) {
|
||||
|
|
|
@ -301,10 +301,7 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
if (!IsVisibleForPainting()) return;
|
||||
|
||||
nsFrameLoader* frameLoader = FrameLoader();
|
||||
RenderFrame* rf = nullptr;
|
||||
if (frameLoader) {
|
||||
rf = frameLoader->GetCurrentRenderFrame();
|
||||
}
|
||||
bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame();
|
||||
|
||||
// If we are pointer-events:none then we don't need to HitTest background
|
||||
bool pointerEventsNone =
|
||||
|
@ -312,7 +309,7 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
|
||||
nsDisplayListCollection decorations(aBuilder);
|
||||
DisplayBorderBackgroundOutline(aBuilder, decorations);
|
||||
if (rf) {
|
||||
if (isRemoteFrame) {
|
||||
// Wrap background colors of <iframe>s with remote subdocuments in their
|
||||
// own layer so we generate a ColorLayer. This is helpful for optimizing
|
||||
// compositing; we can skip compositing the ColorLayer when the
|
||||
|
@ -335,7 +332,7 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
return;
|
||||
}
|
||||
|
||||
if (rf) {
|
||||
if (isRemoteFrame) {
|
||||
// We're the subdoc for <browser remote="true"> and it has
|
||||
// painted content. Display its shadow layer tree.
|
||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||
|
@ -998,10 +995,6 @@ nsFrameLoader* nsSubDocumentFrame::FrameLoader() const {
|
|||
return mFrameLoader;
|
||||
}
|
||||
|
||||
mozilla::layout::RenderFrame* nsSubDocumentFrame::GetRenderFrame() const {
|
||||
return FrameLoader() ? FrameLoader()->GetCurrentRenderFrame() : nullptr;
|
||||
}
|
||||
|
||||
// XXX this should be called ObtainDocShell or something like that,
|
||||
// to indicate that it could have side effects
|
||||
nsIDocShell* nsSubDocumentFrame::GetDocShell() {
|
||||
|
|
|
@ -118,7 +118,7 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame,
|
|||
}
|
||||
}
|
||||
|
||||
mozilla::layout::RenderFrame* GetRenderFrame() const;
|
||||
nsFrameLoader* FrameLoader() const;
|
||||
|
||||
protected:
|
||||
friend class AsyncFrameInit;
|
||||
|
@ -126,8 +126,6 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame,
|
|||
// Helper method to look up the HTML marginwidth & marginheight attributes.
|
||||
mozilla::CSSIntSize GetMarginAttributes();
|
||||
|
||||
nsFrameLoader* FrameLoader() const;
|
||||
|
||||
bool IsInline() { return mIsInline; }
|
||||
|
||||
nscoord GetIntrinsicISize();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/dom/RemoteFrameChild.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/LayerTransactionParent.h"
|
||||
|
@ -28,43 +29,36 @@ using namespace mozilla::layers;
|
|||
namespace mozilla {
|
||||
namespace layout {
|
||||
|
||||
static already_AddRefed<LayerManager> GetLayerManager(
|
||||
nsFrameLoader* aFrameLoader) {
|
||||
if (nsIContent* content = aFrameLoader->GetOwnerContent()) {
|
||||
RefPtr<LayerManager> lm = nsContentUtils::LayerManagerForContent(content);
|
||||
if (lm) {
|
||||
static already_AddRefed<LayerManager> GetLayerManager(TabParent* aTabParent) {
|
||||
if (Element* element = aTabParent->GetOwnerElement()) {
|
||||
if (RefPtr<LayerManager> lm =
|
||||
nsContentUtils::LayerManagerForContent(element)) {
|
||||
return lm.forget();
|
||||
}
|
||||
return nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
|
||||
}
|
||||
|
||||
Document* doc = aFrameLoader->GetOwnerDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
return nsContentUtils::LayerManagerForDocument(doc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RenderFrame::RenderFrame()
|
||||
: mLayersId{0},
|
||||
mFrameLoader(nullptr),
|
||||
mTabParent(nullptr),
|
||||
mLayerManager(nullptr),
|
||||
mInitialized(false),
|
||||
mLayersConnected(false) {}
|
||||
|
||||
RenderFrame::~RenderFrame() {}
|
||||
|
||||
bool RenderFrame::Initialize(nsFrameLoader* aFrameLoader) {
|
||||
if (mInitialized || !aFrameLoader) {
|
||||
bool RenderFrame::Initialize(TabParent* aTabParent) {
|
||||
if (mInitialized || !aTabParent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFrameLoader = aFrameLoader;
|
||||
RefPtr<LayerManager> lm = GetLayerManager(mFrameLoader);
|
||||
mTabParent = aTabParent;
|
||||
RefPtr<LayerManager> lm = GetLayerManager(mTabParent);
|
||||
PCompositorBridgeChild* compositor =
|
||||
lm ? lm->GetCompositorBridgeChild() : nullptr;
|
||||
|
||||
TabParent* browser = TabParent::GetFrom(aFrameLoader);
|
||||
mTabProcessId = browser->Manager()->AsContentParent()->OtherPid();
|
||||
mTabProcessId = mTabParent->Manager()->AsContentParent()->OtherPid();
|
||||
|
||||
// Our remote frame will push layers updates to the compositor,
|
||||
// and we'll keep an indirect reference to that tree.
|
||||
|
@ -81,12 +75,12 @@ void RenderFrame::Destroy() {
|
|||
GPUProcessManager::Get()->UnmapLayerTreeId(mLayersId, mTabProcessId);
|
||||
}
|
||||
|
||||
mFrameLoader = nullptr;
|
||||
mTabParent = nullptr;
|
||||
mLayerManager = nullptr;
|
||||
}
|
||||
|
||||
void RenderFrame::EnsureLayersConnected(CompositorOptions* aCompositorOptions) {
|
||||
RefPtr<LayerManager> lm = GetLayerManager(mFrameLoader);
|
||||
RefPtr<LayerManager> lm = GetLayerManager(mTabParent);
|
||||
if (!lm) {
|
||||
return;
|
||||
}
|
||||
|
@ -102,8 +96,8 @@ void RenderFrame::EnsureLayersConnected(CompositorOptions* aCompositorOptions) {
|
|||
|
||||
LayerManager* RenderFrame::AttachLayerManager() {
|
||||
RefPtr<LayerManager> lm;
|
||||
if (mFrameLoader) {
|
||||
lm = GetLayerManager(mFrameLoader);
|
||||
if (mTabParent) {
|
||||
lm = GetLayerManager(mTabParent);
|
||||
}
|
||||
|
||||
// Perhaps the document containing this frame currently has no presentation?
|
||||
|
@ -117,17 +111,11 @@ LayerManager* RenderFrame::AttachLayerManager() {
|
|||
return mLayerManager;
|
||||
}
|
||||
|
||||
void RenderFrame::OwnerContentChanged(nsIContent* aContent) {
|
||||
MOZ_ASSERT(!mFrameLoader || mFrameLoader->GetOwnerContent() == aContent,
|
||||
"Don't build new map if owner is same!");
|
||||
|
||||
Unused << AttachLayerManager();
|
||||
}
|
||||
void RenderFrame::OwnerContentChanged() { Unused << AttachLayerManager(); }
|
||||
|
||||
void RenderFrame::GetTextureFactoryIdentifier(
|
||||
TextureFactoryIdentifier* aTextureFactoryIdentifier) const {
|
||||
RefPtr<LayerManager> lm =
|
||||
mFrameLoader ? GetLayerManager(mFrameLoader) : nullptr;
|
||||
RefPtr<LayerManager> lm = mTabParent ? GetLayerManager(mTabParent) : nullptr;
|
||||
// Perhaps the document containing this frame currently has no presentation?
|
||||
if (lm) {
|
||||
*aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier();
|
||||
|
@ -185,10 +173,14 @@ nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
|
|||
mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent;
|
||||
}
|
||||
|
||||
nsFrameLoader* frameLoader = GetRenderFrame()->GetFrameLoader();
|
||||
if (frameLoader) {
|
||||
TabParent* browser = TabParent::GetFrom(frameLoader);
|
||||
if (browser) {
|
||||
nsFrameLoader* frameLoader = GetFrameLoader();
|
||||
MOZ_ASSERT(frameLoader && frameLoader->IsRemoteFrame());
|
||||
mLayersId = frameLoader->GetLayersId();
|
||||
|
||||
if (nsFrameLoader* frameLoader = GetFrameLoader()) {
|
||||
// TODO: We need to handle acquiring a TabId in the remote sub-frame case
|
||||
// for fission.
|
||||
if (TabParent* browser = TabParent::GetFrom(frameLoader)) {
|
||||
mTabId = browser->GetTabId();
|
||||
}
|
||||
}
|
||||
|
@ -205,13 +197,12 @@ mozilla::LayerState nsDisplayRemote::GetLayerState(
|
|||
|
||||
bool nsDisplayRemote::HasDeletedFrame() const {
|
||||
// RenderFrame might change without invalidating nsSubDocumentFrame.
|
||||
return !GetRenderFrame() || nsDisplayItem::HasDeletedFrame();
|
||||
return !GetFrameLoader() || nsDisplayItem::HasDeletedFrame();
|
||||
}
|
||||
|
||||
already_AddRefed<Layer> nsDisplayRemote::BuildLayer(
|
||||
nsDisplayListBuilder* aBuilder, LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) {
|
||||
MOZ_ASSERT(GetRenderFrame());
|
||||
MOZ_ASSERT(mFrame, "Makes no sense to have a shadow tree without a frame");
|
||||
|
||||
if (IsTempLayerManager(aManager)) {
|
||||
|
@ -227,9 +218,7 @@ already_AddRefed<Layer> nsDisplayRemote::BuildLayer(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
LayersId remoteId = GetRenderFrame()->GetLayersId();
|
||||
|
||||
if (!remoteId.IsValid()) {
|
||||
if (!mLayersId.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -246,7 +235,7 @@ already_AddRefed<Layer> nsDisplayRemote::BuildLayer(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static_cast<RefLayer*>(layer.get())->SetReferentId(remoteId);
|
||||
static_cast<RefLayer*>(layer.get())->SetReferentId(mLayersId);
|
||||
LayoutDeviceIntPoint offset = GetContentRectLayerOffset(Frame(), aBuilder);
|
||||
// We can only have an offset if we're a child of an inactive
|
||||
// container, but our display item is LAYER_ACTIVE_FORCE which
|
||||
|
@ -284,6 +273,10 @@ bool nsDisplayRemote::CreateWebRenderCommands(
|
|||
const StackingContextHelper& aSc,
|
||||
mozilla::layers::RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
if (!mLayersId.IsValid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mOffset = GetContentRectLayerOffset(mFrame, aDisplayListBuilder);
|
||||
|
||||
LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(
|
||||
|
@ -292,8 +285,7 @@ bool nsDisplayRemote::CreateWebRenderCommands(
|
|||
rect += mOffset;
|
||||
|
||||
aBuilder.PushIFrame(mozilla::wr::ToRoundedLayoutRect(rect),
|
||||
!BackfaceIsHidden(),
|
||||
mozilla::wr::AsPipelineId(GetRemoteLayersId()),
|
||||
!BackfaceIsHidden(), mozilla::wr::AsPipelineId(mLayersId),
|
||||
/*ignoreMissingPipelines*/ true);
|
||||
|
||||
return true;
|
||||
|
@ -302,8 +294,12 @@ bool nsDisplayRemote::CreateWebRenderCommands(
|
|||
bool nsDisplayRemote::UpdateScrollData(
|
||||
mozilla::layers::WebRenderScrollData* aData,
|
||||
mozilla::layers::WebRenderLayerScrollData* aLayerData) {
|
||||
if (!mLayersId.IsValid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aLayerData) {
|
||||
aLayerData->SetReferentId(GetRemoteLayersId());
|
||||
aLayerData->SetReferentId(mLayersId);
|
||||
aLayerData->SetTransform(
|
||||
mozilla::gfx::Matrix4x4::Translation(mOffset.x, mOffset.y, 0.0));
|
||||
aLayerData->SetEventRegionsOverride(mEventRegionsOverride);
|
||||
|
@ -311,12 +307,7 @@ bool nsDisplayRemote::UpdateScrollData(
|
|||
return true;
|
||||
}
|
||||
|
||||
LayersId nsDisplayRemote::GetRemoteLayersId() const {
|
||||
MOZ_ASSERT(GetRenderFrame());
|
||||
return GetRenderFrame()->GetLayersId();
|
||||
}
|
||||
|
||||
mozilla::layout::RenderFrame* nsDisplayRemote::GetRenderFrame() const {
|
||||
return mFrame ? static_cast<nsSubDocumentFrame*>(mFrame)->GetRenderFrame()
|
||||
nsFrameLoader* nsDisplayRemote::GetFrameLoader() const {
|
||||
return mFrame ? static_cast<nsSubDocumentFrame*>(mFrame)->FrameLoader()
|
||||
: nullptr;
|
||||
}
|
||||
|
|
|
@ -21,12 +21,20 @@ class nsSubDocumentFrame;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class TabParent;
|
||||
} // namespace dom
|
||||
|
||||
namespace layers {
|
||||
struct TextureFactoryIdentifier;
|
||||
} // namespace layers
|
||||
|
||||
namespace layout {
|
||||
|
||||
/**
|
||||
* RenderFrame connects and manages layer trees for remote frames. It is
|
||||
* directly owned by a TabParent and always lives in the parent process.
|
||||
*/
|
||||
class RenderFrame final {
|
||||
typedef mozilla::layers::CompositorOptions CompositorOptions;
|
||||
typedef mozilla::layers::LayerManager LayerManager;
|
||||
|
@ -37,14 +45,13 @@ class RenderFrame final {
|
|||
RenderFrame();
|
||||
virtual ~RenderFrame();
|
||||
|
||||
bool Initialize(nsFrameLoader* aFrameLoader);
|
||||
bool Initialize(dom::TabParent* aTabParent);
|
||||
void Destroy();
|
||||
|
||||
void EnsureLayersConnected(CompositorOptions* aCompositorOptions);
|
||||
LayerManager* AttachLayerManager();
|
||||
void OwnerContentChanged(nsIContent* aContent);
|
||||
void OwnerContentChanged();
|
||||
|
||||
nsFrameLoader* GetFrameLoader() const { return mFrameLoader; }
|
||||
LayersId GetLayersId() const { return mLayersId; }
|
||||
CompositorOptions GetCompositorOptions() const { return mCompositorOptions; }
|
||||
|
||||
|
@ -55,17 +62,17 @@ class RenderFrame final {
|
|||
bool IsLayersConnected() const { return mLayersConnected; }
|
||||
|
||||
private:
|
||||
// The process id of the remote frame. This is used by the compositor to
|
||||
// do security checks on incoming layer transactions.
|
||||
base::ProcessId mTabProcessId;
|
||||
// When our child frame is pushing transactions directly to the
|
||||
// compositor, this is the ID of its layer tree in the compositor's
|
||||
// context.
|
||||
// The layers id of the remote frame.
|
||||
LayersId mLayersId;
|
||||
// The compositor options for this layers id. This is only meaningful if
|
||||
// the compositor actually knows about this layers id (i.e. when
|
||||
// mLayersConnected is true).
|
||||
CompositorOptions mCompositorOptions;
|
||||
|
||||
RefPtr<nsFrameLoader> mFrameLoader;
|
||||
dom::TabParent* mTabParent;
|
||||
RefPtr<LayerManager> mLayerManager;
|
||||
|
||||
bool mInitialized;
|
||||
|
@ -79,9 +86,8 @@ class RenderFrame final {
|
|||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
* A DisplayRemote exists solely to graft a child process's shadow
|
||||
* layer tree (for a given RenderFrame) into its parent
|
||||
* process's layer tree.
|
||||
* A nsDisplayRemote will graft a remote frame's shadow layer tree (for a given
|
||||
* nsFrameLoader) into its parent frame's layer tree.
|
||||
*/
|
||||
class nsDisplayRemote final : public nsDisplayItem {
|
||||
typedef mozilla::dom::TabId TabId;
|
||||
|
@ -122,10 +128,10 @@ class nsDisplayRemote final : public nsDisplayItem {
|
|||
NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE)
|
||||
|
||||
private:
|
||||
LayersId GetRemoteLayersId() const;
|
||||
RenderFrame* GetRenderFrame() const;
|
||||
nsFrameLoader* GetFrameLoader() const;
|
||||
|
||||
TabId mTabId;
|
||||
LayersId mLayersId;
|
||||
LayoutDeviceIntPoint mOffset;
|
||||
EventRegionsOverride mEventRegionsOverride;
|
||||
};
|
||||
|
|
|
@ -2682,7 +2682,7 @@ pref("csp.overrule_about_uris_without_csp_whitelist", false);
|
|||
pref("csp.skip_about_page_has_csp_assert", false);
|
||||
// assertion flag will be set to false after fixing Bug 1473549
|
||||
pref("security.allow_eval_with_system_principal", false);
|
||||
pref("security.uris_using_eval_with_system_principal", "autocomplete.xml,redux.js,react-redux.js,content-task.js,content-task.js,tree.xml,dialog.xml,preferencesbindings.js,wizard.xml,lodash.js,jszip.js,ajv-4.1.1.js,updates.js,setup,jsol.js,parent_utils.js");
|
||||
pref("security.uris_using_eval_with_system_principal", "autocomplete.xml,redux.js,react-redux.js,content-task.js,content-task.js,tree.xml,dialog.xml,preferencesbindings.js,wizard.xml,lodash.js,jszip.js,ajv-4.1.1.js,updates.js,setup,jsol.js,parent_utils.js,chrometask_chromescript");
|
||||
#endif
|
||||
|
||||
// Default Content Security Policy to apply to signed contents.
|
||||
|
|
|
@ -25,7 +25,8 @@ All notable changes to this program is documented in this file.
|
|||
|
||||
- Added new endpoint `POST /session/{session_id}/window/new`
|
||||
for the [New Window] command to create a new top-level browsing
|
||||
context, which can be either a window or a tab.
|
||||
context, which can be either a window or a tab. The first version
|
||||
of Firefox supporting this command is Firefox 66.0.
|
||||
|
||||
- When using the preference `devtools.console.stdout.content` set to
|
||||
`true` logging of console API calls like `info()`, `warn()`, and
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function ChromeTask_ChromeScript() {
|
||||
"use strict";
|
||||
|
||||
const {Task} = ChromeUtils.import("resource://testing-common/Task.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const AssertCls = ChromeUtils.import("resource://testing-common/Assert.jsm", null).Assert;
|
||||
|
||||
addMessageListener("chrome-task:spawn", function(aData) {
|
||||
let id = aData.id;
|
||||
let source = aData.runnable || "()=>{}";
|
||||
|
||||
function getStack(aStack) {
|
||||
let frames = [];
|
||||
for (let frame = aStack; frame; frame = frame.caller) {
|
||||
frames.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber);
|
||||
}
|
||||
return frames.join("\n");
|
||||
}
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
var Assert = new AssertCls((err, message, stack) => {
|
||||
sendAsyncMessage("chrome-task:test-result", {
|
||||
id,
|
||||
condition: !err,
|
||||
name: err ? err.message : message,
|
||||
stack: getStack(err ? err.stack : stack),
|
||||
});
|
||||
});
|
||||
|
||||
var ok = Assert.ok.bind(Assert);
|
||||
var is = Assert.equal.bind(Assert);
|
||||
var isnot = Assert.notEqual.bind(Assert);
|
||||
|
||||
function todo(expr, name) {
|
||||
sendAsyncMessage("chrome-task:test-todo", {id, expr, name});
|
||||
}
|
||||
|
||||
function todo_is(a, b, name) {
|
||||
sendAsyncMessage("chrome-task:test-todo_is", {id, a, b, name});
|
||||
}
|
||||
|
||||
function info(name) {
|
||||
sendAsyncMessage("chrome-task:test-info", {id, name});
|
||||
}
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
try {
|
||||
let runnablestr = `
|
||||
(() => {
|
||||
return (${source});
|
||||
})();`;
|
||||
|
||||
// eslint-disable-next-line no-eval
|
||||
let runnable = eval(runnablestr);
|
||||
let iterator = runnable.call(this, aData.arg);
|
||||
Task.spawn(iterator).then((val) => {
|
||||
sendAsyncMessage("chrome-task:complete", {
|
||||
id,
|
||||
result: val,
|
||||
});
|
||||
}, (e) => {
|
||||
sendAsyncMessage("chrome-task:complete", {
|
||||
id,
|
||||
error: e.toString(),
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
sendAsyncMessage("chrome-task:complete", {
|
||||
id,
|
||||
error: e.toString(),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This object provides the public module functions.
|
||||
*/
|
||||
var ChromeTask = {
|
||||
/**
|
||||
* the ChromeScript if it has already been loaded.
|
||||
*/
|
||||
_chromeScript: null,
|
||||
|
||||
/**
|
||||
* Mapping from message id to associated promise.
|
||||
*/
|
||||
_promises: new Map(),
|
||||
|
||||
/**
|
||||
* Incrementing integer to generate unique message id.
|
||||
*/
|
||||
_messageID: 1,
|
||||
|
||||
/**
|
||||
* Creates and starts a new task in the chrome process.
|
||||
*
|
||||
* @param arg A single serializable argument that will be passed to the
|
||||
* task when executed on the content process.
|
||||
* @param task
|
||||
* - A generator or function which will be serialized and sent to
|
||||
* the remote browser to be executed. Unlike Task.spawn, this
|
||||
* argument may not be an iterator as it will be serialized and
|
||||
* sent to the remote browser.
|
||||
* @return A promise object where you can register completion callbacks to be
|
||||
* called when the task terminates.
|
||||
* @resolves With the final returned value of the task if it executes
|
||||
* successfully.
|
||||
* @rejects An error message if execution fails.
|
||||
*/
|
||||
spawn: function ChromeTask_spawn(arg, task) {
|
||||
// Load the frame script if needed.
|
||||
let handle = ChromeTask._chromeScript;
|
||||
if (!handle) {
|
||||
handle = SpecialPowers.loadChromeScript(ChromeTask_ChromeScript);
|
||||
handle.addMessageListener("chrome-task:complete", ChromeTask.onComplete);
|
||||
handle.addMessageListener("chrome-task:test-result", ChromeTask.onResult);
|
||||
handle.addMessageListener("chrome-task:test-info", ChromeTask.onInfo);
|
||||
handle.addMessageListener("chrome-task:test-todo", ChromeTask.onTodo);
|
||||
handle.addMessageListener("chrome-task:test-todo_is", ChromeTask.onTodoIs);
|
||||
ChromeTask._chromeScript = handle;
|
||||
}
|
||||
|
||||
let deferred = {};
|
||||
deferred.promise = new Promise((resolve, reject) => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
let id = ChromeTask._messageID++;
|
||||
ChromeTask._promises.set(id, deferred);
|
||||
|
||||
handle.sendAsyncMessage(
|
||||
"chrome-task:spawn",
|
||||
{
|
||||
id,
|
||||
runnable: task.toString(),
|
||||
arg,
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
onComplete(aData) {
|
||||
let deferred = ChromeTask._promises.get(aData.id);
|
||||
ChromeTask._promises.delete(aData.id);
|
||||
|
||||
if (aData.error) {
|
||||
deferred.reject(aData.error);
|
||||
} else {
|
||||
deferred.resolve(aData.result);
|
||||
}
|
||||
},
|
||||
|
||||
onResult(aData) {
|
||||
SimpleTest.record(aData.condition, aData.name);
|
||||
},
|
||||
|
||||
onInfo(aData) {
|
||||
SimpleTest.info(aData.name);
|
||||
},
|
||||
|
||||
onTodo(aData) {
|
||||
SimpleTest.todo(aData.expr, aData.name);
|
||||
},
|
||||
|
||||
onTodoIs(aData) {
|
||||
SimpleTest.todo_is(aData.a, aData.b, aData.name);
|
||||
},
|
||||
};
|
|
@ -8,6 +8,7 @@ TEST_HARNESS_FILES.testing.mochitest.tests.SimpleTest += [
|
|||
'/docshell/test/chrome/docshell_helpers.js',
|
||||
'/testing/specialpowers/content/MozillaLogger.js',
|
||||
'AddTask.js',
|
||||
'ChromeTask.js',
|
||||
'EventUtils.js',
|
||||
'ExtensionTestUtils.js',
|
||||
'iframe-between-tests.html',
|
||||
|
|
|
@ -67,6 +67,13 @@ this.AppConstants = Object.freeze({
|
|||
false,
|
||||
#endif
|
||||
|
||||
MOZ_SERVICES_SYNC:
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
true,
|
||||
#else
|
||||
false,
|
||||
#endif
|
||||
|
||||
MOZ_SERVICES_HEALTHREPORT:
|
||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||
true,
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
let gParams;
|
||||
|
||||
const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
function init() {
|
||||
/*
|
||||
* The C++ code passes a dialog param block using its integers as in and out
|
||||
|
@ -13,10 +15,12 @@ function init() {
|
|||
* 1: A return argument, one of nsIToolkitProfileService.downgradeUIChoice.
|
||||
*/
|
||||
gParams = window.arguments[0].QueryInterface(Ci.nsIDialogParamBlock);
|
||||
let hasSync = gParams.GetInt(0) & Ci.nsIToolkitProfileService.hasSync;
|
||||
if (AppConstants.MOZ_SERVICES_SYNC) {
|
||||
let hasSync = gParams.GetInt(0) & Ci.nsIToolkitProfileService.hasSync;
|
||||
|
||||
document.getElementById("sync").hidden = !hasSync;
|
||||
document.getElementById("nosync").hidden = hasSync;
|
||||
document.getElementById("sync").hidden = !hasSync;
|
||||
document.getElementById("nosync").hidden = hasSync;
|
||||
}
|
||||
}
|
||||
|
||||
function quit() {
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
<!DOCTYPE dialog [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
%brandDTD;
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
|
||||
%syncBrandDTD;
|
||||
#endif
|
||||
<!ENTITY % profileDTD SYSTEM "chrome://mozapps/locale/profile/profileDowngrade.dtd">
|
||||
%profileDTD;
|
||||
]>
|
||||
|
@ -32,7 +34,9 @@
|
|||
<image id="info" role="presentation"/>
|
||||
<vbox flex="1">
|
||||
<description id="nosync">&window.nosync;</description>
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<description id="sync">&window.sync;</description>
|
||||
#endif
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
|
|
|
@ -424,6 +424,7 @@ STATIC_ATOMS = [
|
|||
Atom("figure", "figure"),
|
||||
Atom("findbar", "findbar"),
|
||||
Atom("fixed", "fixed"),
|
||||
Atom("fission", "fission"),
|
||||
Atom("flags", "flags"),
|
||||
Atom("flex", "flex"),
|
||||
Atom("flip", "flip"),
|
||||
|
|
Загрузка…
Ссылка в новой задаче