Merge inbound to mozilla-central. a=merge

This commit is contained in:
Bogdan Tara 2019-02-12 07:25:23 +02:00
Родитель 4217c389d1 66a23e9a90
Коммит 87a0b11003
51 изменённых файлов: 1270 добавлений и 331 удалений

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

@ -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.

42
dom/ipc/PRemoteFrame.ipdl Normal file
Просмотреть файл

@ -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"),