Merge inbound to mozilla-central. a=merge

This commit is contained in:
Cosmin Sabou 2018-01-30 00:43:23 +02:00
Родитель ce878c3931 4a6be8beb3
Коммит 397a156a63
120 изменённых файлов: 1828 добавлений и 898 удалений

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

@ -201,7 +201,6 @@ this.PanelMultiView = class extends this.AssociatedToNode {
this.node.getElementsByTagName("panelview"),
node => PanelView.forNode(node)));
this.openViews = [];
this._mainViewHeight = 0;
this.__transitioning = false;
this.showingSubView = false;
@ -357,43 +356,34 @@ this.PanelMultiView = class extends this.AssociatedToNode {
viewNode.panelMultiView = this.node;
let reverse = !!aPreviousView;
if (!reverse) {
nextPanelView.headerText = viewNode.getAttribute("title") ||
(aAnchor && aAnchor.getAttribute("label"));
}
let previousViewNode = aPreviousView || this._currentSubView;
// If the panelview to show is the same as the previous one, the 'ViewShowing'
// event has already been dispatched. Don't do it twice.
let showingSameView = viewNode == previousViewNode;
let playTransition = (!!previousViewNode && !showingSameView && this._panel.state == "open");
let isMainView = viewNode.id == this._mainViewId;
let previousRect = previousViewNode.__lastKnownBoundingRect =
this._dwu.getBoundsWithoutFlushing(previousViewNode);
// Cache the measures that have the same caching lifetime as the width
// or height of the main view, i.e. whilst the panel is shown and/ or
// visible.
if (!this._mainViewWidth) {
this._mainViewWidth = previousRect.width;
}
if (!this._mainViewHeight) {
this._mainViewHeight = previousRect.height;
this._viewContainer.style.minHeight = this._mainViewHeight + "px";
}
let prevPanelView = PanelView.forNode(previousViewNode);
prevPanelView.captureKnownSize();
this._viewShowing = viewNode;
// Because the 'mainview' attribute may be out-of-sync, due to view node
// reparenting in combination with ephemeral PanelMultiView instances,
// this is the best place to correct it (just before showing).
nextPanelView.mainview = isMainView;
let reverse = !!aPreviousView;
if (!reverse) {
// We are opening a new view, either because we are navigating forward
// or because we are showing the main view. Some properties of the view
// may vary between panels, so we make sure to update them every time.
// Firstly, make sure that the header matches how the view was opened.
nextPanelView.headerText = viewNode.getAttribute("title") ||
(aAnchor && aAnchor.getAttribute("label"));
// The main view of a panel can be a subview in another one.
let isMainView = viewNode.id == this._mainViewId;
nextPanelView.mainview = isMainView;
// The constrained width of subviews may also vary between panels.
nextPanelView.minMaxWidth = isMainView ? 0 : prevPanelView.knownWidth;
}
if (aAnchor) {
viewNode.classList.add("PanelUI-subView");
}
if (!isMainView && this._mainViewWidth)
viewNode.style.maxWidth = viewNode.style.minWidth = this._mainViewWidth + "px";
if (!showingSameView || !viewNode.hasAttribute("current")) {
// Emit the ViewShowing event so that the widget definition has a chance
@ -425,8 +415,8 @@ this.PanelMultiView = class extends this.AssociatedToNode {
// Now we have to transition the panel. If we've got an older transition
// still running, make sure to clean it up.
await this._cleanupTransitionPhase();
if (playTransition) {
await this._transitionViews(previousViewNode, viewNode, reverse, previousRect, aAnchor);
if (!showingSameView && this._panel.state == "open") {
await this._transitionViews(previousViewNode, viewNode, reverse, aAnchor);
nextPanelView.focusSelectedElement();
} else {
this.hideAllViewsExcept(nextPanelView);
@ -448,12 +438,10 @@ this.PanelMultiView = class extends this.AssociatedToNode {
* after the transition has finished.
* @param {Boolean} reverse Whether we're navigation back to a
* previous view or forward to a next view.
* @param {Object} previousRect Rect object, with the same structure as
* a DOMRect, of the `previousViewNode`.
* @param {Element} anchor the anchor for which we're opening
* a new panelview, if any
*/
async _transitionViews(previousViewNode, viewNode, reverse, previousRect, anchor) {
async _transitionViews(previousViewNode, viewNode, reverse, anchor) {
// There's absolutely no need to show off our epic animation skillz when
// the panel's not even open.
if (this._panel.state != "open") {
@ -463,6 +451,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
const {window, document} = this;
let nextPanelView = PanelView.forNode(viewNode);
let prevPanelView = PanelView.forNode(previousViewNode);
if (this._autoResizeWorkaroundTimer)
window.clearTimeout(this._autoResizeWorkaroundTimer);
@ -481,23 +470,27 @@ this.PanelMultiView = class extends this.AssociatedToNode {
previousViewNode.setAttribute("in-transition", true);
// Set the viewContainer dimensions to make sure only the current view is
// visible.
this._viewContainer.style.height = Math.max(previousRect.height, this._mainViewHeight) + "px";
this._viewContainer.style.width = previousRect.width + "px";
let olderView = reverse ? nextPanelView : prevPanelView;
this._viewContainer.style.minHeight = olderView.knownHeight + "px";
this._viewContainer.style.height = prevPanelView.knownHeight + "px";
this._viewContainer.style.width = prevPanelView.knownWidth + "px";
// Lock the dimensions of the window that hosts the popup panel.
let rect = this._panel.popupBoxObject.getOuterScreenRect();
this._panel.setAttribute("width", rect.width);
this._panel.setAttribute("height", rect.height);
let viewRect;
if (reverse && viewNode.__lastKnownBoundingRect) {
if (reverse) {
// Use the cached size when going back to a previous view, but not when
// reopening a subview, because its contents may have changed.
viewRect = viewNode.__lastKnownBoundingRect;
viewRect = { width: nextPanelView.knownWidth,
height: nextPanelView.knownHeight };
viewNode.setAttribute("in-transition", true);
} else if (viewNode.customRectGetter) {
// Can't use Object.assign directly with a DOM Rect object because its properties
// aren't enumerable.
let {height, width} = previousRect;
let width = prevPanelView.knownWidth;
let height = prevPanelView.knownHeight;
viewRect = Object.assign({height, width}, viewNode.customRectGetter());
let header = viewNode.firstChild;
if (header && header.classList.contains("panel-header")) {
@ -506,8 +499,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
viewNode.setAttribute("in-transition", true);
} else {
let oldSibling = viewNode.nextSibling || null;
this._offscreenViewStack.style.minHeight =
this._viewContainer.style.height;
this._offscreenViewStack.style.minHeight = olderView.knownHeight + "px";
this._offscreenViewStack.appendChild(viewNode);
viewNode.setAttribute("in-transition", true);
@ -533,7 +525,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
// The 'magic' part: build up the amount of pixels to move right or left.
let moveToLeft = (this._dir == "rtl" && !reverse) || (this._dir == "ltr" && reverse);
let deltaX = previousRect.width;
let deltaX = prevPanelView.knownWidth;
let deepestNode = reverse ? previousViewNode : viewNode;
// With a transition when navigating backwards - user hits the 'back'
@ -554,7 +546,7 @@ this.PanelMultiView = class extends this.AssociatedToNode {
// Now set the viewContainer dimensions to that of the new view, which
// kicks of the height animation.
this._viewContainer.style.height = Math.max(viewRect.height, this._mainViewHeight) + "px";
this._viewContainer.style.height = viewRect.height + "px";
this._viewContainer.style.width = viewRect.width + "px";
this._panel.removeAttribute("width");
this._panel.removeAttribute("height");
@ -757,13 +749,6 @@ this.PanelMultiView = class extends this.AssociatedToNode {
this._transitioning = false;
this.node.removeAttribute("panelopen");
this.showMainView();
for (let panelView of this._viewStack.children) {
if (panelView.nodeName != "children") {
panelView.__lastKnownBoundingRect = null;
panelView.style.removeProperty("min-width");
panelView.style.removeProperty("max-width");
}
}
this.window.removeEventListener("keydown", this);
this._panel.removeEventListener("mousemove", this);
this.openViews.forEach(panelView => panelView.clearNavigation());
@ -771,12 +756,10 @@ this.PanelMultiView = class extends this.AssociatedToNode {
// Clear the main view size caches. The dimensions could be different
// when the popup is opened again, e.g. through touch mode sizing.
this._mainViewHeight = 0;
this._mainViewWidth = 0;
this._viewContainer.style.removeProperty("min-height");
this._viewStack.style.removeProperty("max-height");
this._viewContainer.style.removeProperty("min-width");
this._viewContainer.style.removeProperty("max-width");
this._viewContainer.style.removeProperty("width");
this._viewContainer.style.removeProperty("height");
this.dispatchCustomEvent("PanelMultiViewHidden");
break;
@ -816,6 +799,20 @@ this.PanelView = class extends this.AssociatedToNode {
}
}
/**
* Constrains the width of this view using the "min-width" and "max-width"
* styles. Setting this to zero removes the constraints.
*/
set minMaxWidth(value) {
let style = this.node.style;
if (value) {
style.minWidth = style.maxWidth = value + "px";
} else {
style.removeProperty("min-width");
style.removeProperty("max-width");
}
}
/**
* Adds a header with the given title, or removes it if the title is empty.
*/
@ -867,6 +864,19 @@ this.PanelView = class extends this.AssociatedToNode {
return super.dispatchCustomEvent(...args);
}
/**
* Populates the "knownWidth" and "knownHeight" properties with the current
* dimensions of the view. These may be zero if the view is invisible.
*
* These values are relevant during transitions and are retained for backwards
* navigation if the view is still open but is invisible.
*/
captureKnownSize() {
let rect = this._dwu.getBoundsWithoutFlushing(this.node);
this.knownWidth = rect.width;
this.knownHeight = rect.height;
}
/**
* If the main view or a subview contains wrapping elements, the attribute
* "descriptionheightworkaround" should be set on the view to force all the

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

@ -12,9 +12,18 @@
namespace mozilla {
namespace dom {
ServiceWorkerDescriptor::ServiceWorkerDescriptor()
ServiceWorkerDescriptor::ServiceWorkerDescriptor(uint64_t aId,
nsIPrincipal* aPrincipal,
const nsACString& aScope,
ServiceWorkerState aState)
: mData(MakeUnique<IPCServiceWorkerDescriptor>())
{
MOZ_ALWAYS_SUCCEEDS(
PrincipalToPrincipalInfo(aPrincipal, &mData->principalInfo()));
mData->id() = aId;
mData->scope() = aScope;
mData->state() = aState;
}
ServiceWorkerDescriptor::ServiceWorkerDescriptor(uint64_t aId,

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

@ -6,6 +6,8 @@
#ifndef _mozilla_dom_ServiceWorkerDescriptor_h
#define _mozilla_dom_ServiceWorkerDescriptor_h
class nsIPrincipal;
namespace mozilla {
namespace ipc {
@ -29,7 +31,10 @@ class ServiceWorkerDescriptor final
UniquePtr<IPCServiceWorkerDescriptor> mData;
public:
ServiceWorkerDescriptor();
ServiceWorkerDescriptor(uint64_t aId,
nsIPrincipal* aPrincipal,
const nsACString& aScope,
ServiceWorkerState aState);
ServiceWorkerDescriptor(uint64_t aId,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,

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

@ -221,6 +221,7 @@ ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal,
const nsAString& aCacheName,
nsLoadFlags aImportsLoadFlags)
: mPrincipal(aPrincipal)
, mDescriptor(GetNextID(), aPrincipal, aScope, ServiceWorkerState::Parsed)
, mScriptSpec(aScriptSpec)
, mCacheName(aCacheName)
, mImportsLoadFlags(aImportsLoadFlags)
@ -243,12 +244,6 @@ ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal,
// Otherwise, we might not be able to update a service worker correctly, if
// there is a service worker generating the script.
MOZ_DIAGNOSTIC_ASSERT(mImportsLoadFlags & nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
PrincipalInfo principalInfo;
MOZ_ALWAYS_SUCCEEDS(PrincipalToPrincipalInfo(aPrincipal, &principalInfo));
mDescriptor = ServiceWorkerDescriptor(GetNextID(), principalInfo, aScope,
ServiceWorkerState::Parsed);
}
ServiceWorkerInfo::~ServiceWorkerInfo()

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

@ -101,6 +101,16 @@ dictionary InspectorVariationAxis {
required float defaultValue;
};
dictionary InspectorVariationValue {
required DOMString axis;
required float value;
};
dictionary InspectorVariationInstance {
required DOMString name;
required sequence<InspectorVariationValue> values;
};
[ChromeOnly]
interface InspectorFontFace {
// An indication of how we found this font during font-matching.
@ -115,7 +125,8 @@ interface InspectorFontFace {
// (not necessarily the actual name that was used,
// due to aliases, generics, localized names, etc)
[NewObject] sequence<InspectorVariationAxis> getVariationAxes();
[NewObject,Throws] sequence<InspectorVariationAxis> getVariationAxes();
[NewObject,Throws] sequence<InspectorVariationInstance> getVariationInstances();
// meaningful only when the font is a user font defined using @font-face
readonly attribute CSSFontFaceRule? rule; // null if no associated @font-face rule

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

@ -2166,8 +2166,8 @@ RuntimeService::CrashIfHanging()
nsCString msg;
// A: active Workers | S: active ServiceWorkers | Q: queued Workers
msg.AppendPrintf("Workers Hanging - A:%d|S:%d|Q:%d", activeWorkers,
activeServiceWorkers, inactiveWorkers);
msg.AppendPrintf("Workers Hanging - %d|A:%d|S:%d|Q:%d", mShuttingDown ? 1 : 0,
activeWorkers, activeServiceWorkers, inactiveWorkers);
// For each thread, let's print some data to know what is going wrong.
for (uint32_t i = 0; i < workers.Length(); ++i) {

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

@ -120,7 +120,7 @@ GPUVideoTextureHost::NumSubTextures() const
}
void
GPUVideoTextureHost::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
GPUVideoTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID)

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

@ -51,7 +51,7 @@ public:
virtual uint32_t NumSubTextures() const override;
virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID) override;

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

@ -577,13 +577,13 @@ BufferTextureHost::NumSubTextures() const
}
void
BufferTextureHost::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
BufferTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID)
{
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::ResourceUpdateQueue::AddExternalImage
: &wr::ResourceUpdateQueue::UpdateExternalImage;
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage
: &wr::TransactionBuilder::UpdateExternalImage;
auto bufferType = wr::WrExternalImageBufferType::ExternalBuffer;
if (GetFormat() != gfx::SurfaceFormat::YUV) {

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

@ -42,7 +42,7 @@ class Shmem;
namespace wr {
class DisplayListBuilder;
class ResourceUpdateQueue;
class TransactionBuilder;
}
namespace layers {
@ -637,7 +637,7 @@ public:
};
// Add all necessary TextureHost informations to the resource update queue.
virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID)
@ -754,7 +754,7 @@ public:
virtual uint32_t NumSubTextures() const override;
virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID) override;

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

@ -1090,7 +1090,7 @@ DXGITextureHostD3D11::NumSubTextures() const
}
void
DXGITextureHostD3D11::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
DXGITextureHostD3D11::PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID)
@ -1101,8 +1101,8 @@ DXGITextureHostD3D11::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
}
MOZ_ASSERT(mHandle);
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::ResourceUpdateQueue::AddExternalImage
: &wr::ResourceUpdateQueue::UpdateExternalImage;
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage
: &wr::TransactionBuilder::UpdateExternalImage;
switch (mFormat) {
case gfx::SurfaceFormat::R8G8B8X8:
case gfx::SurfaceFormat::R8G8B8A8:
@ -1341,7 +1341,7 @@ DXGIYCbCrTextureHostD3D11::NumSubTextures() const
}
void
DXGIYCbCrTextureHostD3D11::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
DXGIYCbCrTextureHostD3D11::PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID)
@ -1356,8 +1356,8 @@ DXGIYCbCrTextureHostD3D11::PushResourceUpdates(wr::ResourceUpdateQueue& aResourc
MOZ_ASSERT(mSize.width % 2 == 0);
MOZ_ASSERT(mSize.height % 2 == 0);
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::ResourceUpdateQueue::AddExternalImage
: &wr::ResourceUpdateQueue::UpdateExternalImage;
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage
: &wr::TransactionBuilder::UpdateExternalImage;
auto bufferType = wr::WrExternalImageBufferType::TextureExternalHandle;
// y

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

@ -360,7 +360,7 @@ public:
virtual uint32_t NumSubTextures() const override;
virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID) override;
@ -422,7 +422,7 @@ public:
virtual uint32_t NumSubTextures() const override;
virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID) override;

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

@ -148,15 +148,15 @@ MacIOSurfaceTextureHostOGL::NumSubTextures() const
}
void
MacIOSurfaceTextureHostOGL::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
MacIOSurfaceTextureHostOGL::PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID)
{
MOZ_ASSERT(mSurface);
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::ResourceUpdateQueue::AddExternalImage
: &wr::ResourceUpdateQueue::UpdateExternalImage;
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage
: &wr::TransactionBuilder::UpdateExternalImage;
auto bufferType = wr::WrExternalImageBufferType::TextureRectHandle;
switch (GetFormat()) {

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

@ -67,7 +67,7 @@ public:
virtual uint32_t NumSubTextures() const override;
virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID) override;

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

@ -131,11 +131,9 @@ AsyncImagePipelineManager::RemoveAsyncImagePipeline(const wr::PipelineId& aPipel
AsyncImagePipeline* holder = entry.Data();
++mAsyncImageEpoch; // Update webrender epoch
aTxn.ClearDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
wr::ResourceUpdateQueue resources;
for (wr::ImageKey key : holder->mKeys) {
resources.DeleteImage(key);
aTxn.DeleteImage(key);
}
aTxn.UpdateResources(resources);
entry.Remove();
RemovePipeline(aPipelineId, wr::NewEpoch(mAsyncImageEpoch));
}
@ -165,7 +163,7 @@ AsyncImagePipelineManager::UpdateAsyncImagePipeline(const wr::PipelineId& aPipel
}
Maybe<TextureHost::ResourceUpdateOp>
AsyncImagePipelineManager::UpdateImageKeys(wr::ResourceUpdateQueue& aResources,
AsyncImagePipelineManager::UpdateImageKeys(wr::TransactionBuilder& aResources,
AsyncImagePipeline* aPipeline,
nsTArray<wr::ImageKey>& aKeys)
{
@ -230,7 +228,7 @@ AsyncImagePipelineManager::UpdateImageKeys(wr::ResourceUpdateQueue& aResources,
}
Maybe<TextureHost::ResourceUpdateOp>
AsyncImagePipelineManager::UpdateWithoutExternalImage(wr::ResourceUpdateQueue& aResources,
AsyncImagePipelineManager::UpdateWithoutExternalImage(wr::TransactionBuilder& aResources,
TextureHost* aTexture,
wr::ImageKey aKey,
TextureHost::ResourceUpdateOp aOp)
@ -286,15 +284,11 @@ AsyncImagePipelineManager::ApplyAsyncImages()
// We use a pipeline with a very small display list for each video element.
// Update each of them if needed.
for (auto iter = mAsyncImagePipelines.Iter(); !iter.Done(); iter.Next()) {
wr::ResourceUpdateQueue resourceUpdates;
wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
AsyncImagePipeline* pipeline = iter.Data();
nsTArray<wr::ImageKey> keys;
auto op = UpdateImageKeys(resourceUpdates, pipeline, keys);
txn.UpdateResources(resourceUpdates);
auto op = UpdateImageKeys(txn, pipeline, keys);
bool updateDisplayList = pipeline->mInitialised &&
(pipeline->mIsChanged || op == Some(TextureHost::ADD_IMAGE)) &&

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

@ -155,11 +155,11 @@ private:
};
Maybe<TextureHost::ResourceUpdateOp>
UpdateImageKeys(wr::ResourceUpdateQueue& aResourceUpdates,
UpdateImageKeys(wr::TransactionBuilder& aResourceUpdates,
AsyncImagePipeline* aPipeline,
nsTArray<wr::ImageKey>& aKeys);
Maybe<TextureHost::ResourceUpdateOp>
UpdateWithoutExternalImage(wr::ResourceUpdateQueue& aResources,
UpdateWithoutExternalImage(wr::TransactionBuilder& aResources,
TextureHost* aTexture,
wr::ImageKey aKey,
TextureHost::ResourceUpdateOp);

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

@ -270,7 +270,7 @@ bool
WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<RefCountedShmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems,
wr::ResourceUpdateQueue& aUpdates)
wr::TransactionBuilder& aUpdates)
{
wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
@ -374,7 +374,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
bool
WebRenderBridgeParent::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::ResourceUpdateQueue& aResources)
wr::TransactionBuilder& aResources)
{
Range<wr::ImageKey> keys(&aKey, 1);
// Check if key is obsoleted.
@ -446,16 +446,14 @@ WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourc
return IPC_OK();
}
wr::ResourceUpdateQueue updates;
wr::TransactionBuilder txn;
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, updates)) {
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) {
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
}
wr::TransactionBuilder txn;
txn.UpdateResources(updates);
mApi->SendTransaction(txn);
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
@ -595,14 +593,11 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
ProcessWebRenderParentCommands(aCommands);
wr::ResourceUpdateQueue resources;
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, resources)) {
wr::TransactionBuilder txn;
if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) {
return IPC_FAIL(this, "Failed to deserialize resource updates");
}
wr::TransactionBuilder txn;
txn.UpdateResources(resources);
wr::Vec<uint8_t> dlData(Move(dl));
// If id namespaces do not match, it means the command is obsolete, probably
@ -610,8 +605,9 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
// In that case do not send the commands to webrender.
if (mIdNamespace == aIdNamespace) {
if (mWidget) {
LayoutDeviceIntSize size = mWidget->GetClientSize();
txn.SetWindowParameters(size);
LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
LayoutDeviceIntRect docRect(LayoutDeviceIntPoint(), widgetSize);
txn.SetWindowParameters(widgetSize, docRect);
}
gfx::Color clearColor(0.f, 0.f, 0.f, 0.f);
txn.SetDisplayList(clearColor, wr::NewEpoch(wrEpoch), LayerSize(aSize.width, aSize.height),

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

@ -199,9 +199,9 @@ private:
bool UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<RefCountedShmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems,
wr::ResourceUpdateQueue& aUpdates);
wr::TransactionBuilder& aUpdates);
bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::ResourceUpdateQueue& aResources);
wr::TransactionBuilder& aResources);
uint64_t GetLayersId() const;
void ProcessWebRenderParentCommands(const InfallibleTArray<WebRenderParentCommand>& aCommands);

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

@ -143,7 +143,7 @@ WebRenderTextureHost::NumSubTextures() const
}
void
WebRenderTextureHost::PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
WebRenderTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID)

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

@ -66,7 +66,7 @@ public:
virtual uint32_t NumSubTextures() const override;
virtual void PushResourceUpdates(wr::ResourceUpdateQueue& aResources,
virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
ResourceUpdateOp aOp,
const Range<wr::ImageKey>& aImageKeys,
const wr::ExternalImageId& aExtID) override;

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

@ -649,6 +649,13 @@ gfxDWriteFontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes)
}
}
void
gfxDWriteFontEntry::GetVariationInstances(
nsTArray<gfxFontVariationInstance>& aInstances)
{
gfxFontUtils::GetVariationInstances(this, aInstances);
}
gfxFont *
gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle,
bool aNeedsBold)

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

@ -191,6 +191,7 @@ public:
bool HasVariations() override;
void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes) override;
void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances) override;
void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
bool GetForceGDIClassic() { return mForceGDIClassic; }

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

@ -624,12 +624,15 @@ gfxFT2FontBase::SetupVarCoords(FT_Face aFace,
{
aCoords->TruncateLength(0);
if (aFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
typedef FT_UInt (*GetVarFunc)(FT_Face, FT_MM_Var**);
typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
static GetVarFunc getVar;
typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
static DoneVarFunc doneVar;
static bool firstTime = true;
if (firstTime) {
firstTime = false;
getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
}
FT_MM_Var* ftVar;
if (getVar && FT_Err_Ok == (*getVar)(aFace, &ftVar)) {
@ -645,7 +648,11 @@ gfxFT2FontBase::SetupVarCoords(FT_Face aFace,
}
}
}
free(ftVar);
if (doneVar) {
(*doneVar)(aFace->glyph->library, ftVar);
} else {
free(ftVar);
}
}
}
}

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

@ -360,8 +360,37 @@ gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
mIgnoreFcCharmap = true;
}
typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
static GetVarFunc sGetVar;
static DoneVarFunc sDoneVar;
static bool sInitializedVarFuncs = false;
static void
InitializeVarFuncs()
{
if (sInitializedVarFuncs) {
return;
}
sInitializedVarFuncs = true;
sGetVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
sDoneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
}
gfxFontconfigFontEntry::~gfxFontconfigFontEntry()
{
if (mMMVar) {
// Prior to freetype 2.9, there was no specific function to free the
// FT_MM_Var record, and the docs just said to use free().
// InitializeVarFuncs must have been called in order for mMMVar to be
// non-null here, so we don't need to do it again.
if (sDoneVar) {
MOZ_ASSERT(mFTFace, "How did mMMVar get set without a face?");
(*sDoneVar)(mFTFace->glyph->library, mMMVar);
} else {
free(mMMVar);
}
}
}
nsresult
@ -469,6 +498,14 @@ gfxFontconfigFontEntry::MaybeReleaseFTFace()
// only close out FT_Face for system fonts, not for data fonts
if (!mIsDataUserFont) {
if (mFTFace) {
if (mMMVar) {
if (sDoneVar) {
(*sDoneVar)(mFTFace->glyph->library, mMMVar);
} else {
free(mMMVar);
}
mMMVar = nullptr;
}
Factory::ReleaseFTFace(mFTFace);
mFTFace = nullptr;
}
@ -1017,31 +1054,36 @@ gfxFontconfigFontEntry::HasVariations()
return false;
}
FT_MM_Var*
gfxFontconfigFontEntry::GetMMVar()
{
if (mMMVarInitialized) {
return mMMVar;
}
mMMVarInitialized = true;
InitializeVarFuncs();
if (!sGetVar) {
return nullptr;
}
FT_Face face = GetFTFace();
if (!face) {
return nullptr;
}
if (FT_Err_Ok != (*sGetVar)(face, &mMMVar)) {
mMMVar = nullptr;
}
return mMMVar;
}
void
gfxFontconfigFontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes)
{
MOZ_ASSERT(aAxes.IsEmpty());
FT_Face face = GetFTFace();
if (!face) {
return;
}
typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**);
static GetVarFunc getVar;
typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*);
static DoneVarFunc doneVar;
static bool firstTime = true;
if (firstTime) {
firstTime = false;
getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var");
doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var");
}
if (!getVar) {
return;
}
FT_MM_Var* mmVar;
if (FT_Err_Ok != (*getVar)(face, &mmVar)) {
FT_MM_Var* mmVar = GetMMVar();
if (!mmVar) {
return;
}
aAxes.SetCapacity(mmVar->num_axis);
for (unsigned i = 0; i < mmVar->num_axis; i++) {
const auto& a = mmVar->axis[i];
gfxFontVariationAxis axis;
@ -1052,13 +1094,40 @@ gfxFontconfigFontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes)
axis.mName.Assign(NS_ConvertUTF8toUTF16(a.name));
aAxes.AppendElement(axis);
}
// Prior to freetype 2.9, there was no specific function to free the FT_MM_Var,
// and the docs just said to use free().
if (doneVar) {
(*doneVar)(face->glyph->library, mmVar);
} else {
free(mmVar);
}
void
gfxFontconfigFontEntry::GetVariationInstances(
nsTArray<gfxFontVariationInstance>& aInstances)
{
MOZ_ASSERT(aInstances.IsEmpty());
FT_MM_Var* mmVar = GetMMVar();
if (!mmVar) {
return;
}
hb_blob_t* nameTable = GetFontTable(TRUETYPE_TAG('n','a','m','e'));
if (!nameTable) {
return;
}
aInstances.SetCapacity(mmVar->num_namedstyles);
for (unsigned i = 0; i < mmVar->num_namedstyles; i++) {
const auto& ns = mmVar->namedstyle[i];
gfxFontVariationInstance inst;
nsresult rv =
gfxFontUtils::ReadCanonicalName(nameTable, ns.strid, inst.mName);
if (NS_FAILED(rv)) {
continue;
}
inst.mValues.SetCapacity(mmVar->num_axis);
for (unsigned j = 0; j < mmVar->num_axis; j++) {
gfxFontVariationValue value;
value.mAxis = mmVar->axis[j].tag;
value.mValue = ns.coords[j] / 65536.0;
inst.mValues.AppendElement(value);
}
aInstances.AppendElement(inst);
}
hb_blob_destroy(nameTable);
}
nsresult

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

@ -18,6 +18,7 @@
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_TRUETYPE_TABLES_H
#include FT_MULTIPLE_MASTERS_H
#include <cairo.h>
#include <cairo-ft.h>
@ -115,8 +116,11 @@ public:
FT_Face GetFTFace();
FT_MM_Var* GetMMVar();
bool HasVariations() override;
void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes) override;
void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances) override;
hb_blob_t* GetFontTable(uint32_t aTableTag) override;
@ -188,6 +192,11 @@ protected:
};
UnscaledFontCache mUnscaledFontCache;
// Because of FreeType bug 52955, we keep the FT_MM_Var struct when it is
// first loaded, rather than releasing it and re-fetching it as needed.
FT_MM_Var* mMMVar = nullptr;
bool mMMVarInitialized = false;
};
class gfxFontconfigFontFamily : public gfxFontFamily {

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

@ -354,6 +354,9 @@ public:
virtual void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes)
{
}
virtual void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances)
{
}
nsString mName;
nsString mFamilyName;

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

@ -7,6 +7,8 @@
#include "mozilla/BinarySearch.h"
#include "gfxFontUtils.h"
#include "gfxFontEntry.h"
#include "gfxFontVariations.h"
#include "nsServiceManagerUtils.h"
@ -1803,6 +1805,145 @@ gfxFontUtils::GetColorGlyphLayers(hb_blob_t* aCOLR,
return true;
}
void
gfxFontUtils::GetVariationInstances(gfxFontEntry* aFontEntry,
nsTArray<gfxFontVariationInstance>& aInstances)
{
MOZ_ASSERT(aInstances.IsEmpty());
if (!aFontEntry->HasVariations()) {
return;
}
// Some platforms don't offer a simple API to return the list of instances,
// so we have to interpret the 'fvar' table ourselves.
// https://www.microsoft.com/typography/otspec/fvar.htm#fvarHeader
struct FvarHeader {
AutoSwap_PRUint16 majorVersion;
AutoSwap_PRUint16 minorVersion;
AutoSwap_PRUint16 axesArrayOffset;
AutoSwap_PRUint16 reserved;
AutoSwap_PRUint16 axisCount;
AutoSwap_PRUint16 axisSize;
AutoSwap_PRUint16 instanceCount;
AutoSwap_PRUint16 instanceSize;
};
// https://www.microsoft.com/typography/otspec/fvar.htm#variationAxisRecord
struct AxisRecord {
AutoSwap_PRUint32 axisTag;
AutoSwap_PRInt32 minValue;
AutoSwap_PRInt32 defaultValue;
AutoSwap_PRInt32 maxValue;
AutoSwap_PRUint16 flags;
AutoSwap_PRUint16 axisNameID;
};
// https://www.microsoft.com/typography/otspec/fvar.htm#instanceRecord
struct InstanceRecord {
AutoSwap_PRUint16 subfamilyNameID;
AutoSwap_PRUint16 flags;
AutoSwap_PRInt32 coordinates[1]; // variable-size array [axisCount]
// The variable-length 'coordinates' array may be followed by an
// optional extra field 'postScriptNameID'. We can't directly
// represent this in the struct, because its offset varies depending
// on the number of axes present.
// (Not currently used by our code here anyhow.)
// AutoSwap_PRUint16 postScriptNameID;
};
// Helper to ensure we free a font table when we return.
class AutoHBBlob {
public:
explicit AutoHBBlob(hb_blob_t* aBlob) : mBlob(aBlob)
{ }
~AutoHBBlob() {
if (mBlob) {
hb_blob_destroy(mBlob);
}
}
operator hb_blob_t* () { return mBlob; }
private:
hb_blob_t* const mBlob;
};
// Load the two font tables we need as harfbuzz blobs; if either is absent,
// just bail out.
AutoHBBlob fvarTable(aFontEntry->GetFontTable(TRUETYPE_TAG('f','v','a','r')));
AutoHBBlob nameTable(aFontEntry->GetFontTable(TRUETYPE_TAG('n','a','m','e')));
if (!fvarTable || !nameTable) {
return;
}
unsigned int len;
const char* data = hb_blob_get_data(fvarTable, &len);
if (len < sizeof(FvarHeader)) {
return;
}
// Read the fields of the table header; bail out if it looks broken.
auto fvar = reinterpret_cast<const FvarHeader*>(data);
if (uint16_t(fvar->majorVersion) != 1 ||
uint16_t(fvar->minorVersion) != 0 ||
uint16_t(fvar->reserved) != 2) {
return;
}
uint16_t axisCount = fvar->axisCount;
uint16_t axisSize = fvar->axisSize;
uint16_t instanceCount = fvar->instanceCount;
uint16_t instanceSize = fvar->instanceSize;
if (axisCount == 0 || // no axes?
// https://www.microsoft.com/typography/otspec/fvar.htm#axisSize
axisSize != 20 || // required value for current table version
instanceCount == 0 || // no instances?
// https://www.microsoft.com/typography/otspec/fvar.htm#instanceSize
(instanceSize != axisCount * sizeof(int32_t) + 4 &&
instanceSize != axisCount * sizeof(int32_t) + 6)) {
return;
}
// Check that axis array will not exceed table size
uint16_t axesOffset = fvar->axesArrayOffset;
if (axesOffset + uint32_t(axisCount) * axisSize > len) {
return;
}
// Get pointer to the array of axis records
auto axes = reinterpret_cast<const AxisRecord*>(data + axesOffset);
// Get address of instance array, and check it doesn't overflow table size.
// https://www.microsoft.com/typography/otspec/fvar.htm#axisAndInstanceArrays
auto instData = data + axesOffset + axisCount * axisSize;
if (instData + uint32_t(instanceCount) * instanceSize > data + len) {
return;
}
aInstances.SetCapacity(instanceCount);
for (unsigned i = 0; i < instanceCount; ++i, instData += instanceSize) {
// Typed pointer to the current instance record, to read its fields.
auto inst = reinterpret_cast<const InstanceRecord*>(instData);
// Pointer to the coordinates array within the instance record.
// This array has axisCount elements, and is included in instanceSize
// (which depends on axisCount, and was validated above) so we know
// access to coords[j] below will not be outside the table bounds.
auto coords = &inst->coordinates[0];
gfxFontVariationInstance instance;
uint16_t nameID = inst->subfamilyNameID;
nsresult rv =
ReadCanonicalName(nameTable, nameID, instance.mName);
if (NS_FAILED(rv)) {
// If no name was available for the instance, ignore it.
continue;
}
instance.mValues.SetCapacity(axisCount);
for (unsigned j = 0; j < axisCount; ++j) {
gfxFontVariationValue value;
value.mAxis = axes[j].axisTag;
value.mValue = int32_t(coords[j]) / 65536.0;
instance.mValues.AppendElement(value);
}
aInstances.AppendElement(instance);
}
}
#ifdef XP_WIN
/* static */

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

@ -26,6 +26,8 @@
typedef struct hb_blob_t hb_blob_t;
struct gfxFontVariationInstance;
class gfxSparseBitSet {
private:
enum { BLOCK_SIZE = 32 }; // ==> 256 codepoints per block
@ -1000,6 +1002,15 @@ public:
nsTArray<uint16_t> &aGlyphs,
nsTArray<mozilla::gfx::Color> &aColors);
// Helper used to implement gfxFontEntry::GetVariationInstances for
// platforms where the native font APIs don't provide the info we want
// in a convenient form.
// (Not used on platforms -- currently, freetype -- where the font APIs
// expose variation instance details directly.)
static void
GetVariationInstances(gfxFontEntry* aFontEntry,
nsTArray<gfxFontVariationInstance>& aInstances);
protected:
friend struct MacCharsetMappingComparator;

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

@ -11,12 +11,29 @@
typedef mozilla::gfx::FontVariation gfxFontVariation;
// Structure that describes a single axis of variation in an
// OpenType Variation or Multiple-Master font.
struct gfxFontVariationAxis {
uint32_t mTag;
nsString mName;
nsString mName; // may be empty
float mMinValue;
float mMaxValue;
float mDefaultValue;
};
// A single <axis, value> pair that may be applied to a variation font.
struct gfxFontVariationValue {
uint32_t mAxis;
float mValue;
};
// Structure that describes a named instance of a variation font:
// a name like "Light Condensed" or "Black Ultra Extended" etc.,
// and a list of the corresponding <variation-axis, value> pairs
// to be used.
struct gfxFontVariationInstance {
nsString mName;
nsTArray<gfxFontVariationValue> mValues;
};
#endif

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

@ -63,6 +63,7 @@ public:
bool HasVariations() override;
void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes) override;
void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances) override;
bool IsCFF();

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

@ -342,6 +342,12 @@ MacOSFontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes)
}
}
void
MacOSFontEntry::GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances)
{
gfxFontUtils::GetVariationInstances(this, aInstances);
}
bool
MacOSFontEntry::IsCFF()
{

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

@ -135,11 +135,13 @@ private:
TransactionBuilder::TransactionBuilder()
{
mTxn = wr_transaction_new();
mResourceUpdates = wr_resource_updates_new();
}
TransactionBuilder::~TransactionBuilder()
{
wr_transaction_delete(mTxn);
wr_resource_updates_delete(mResourceUpdates);
}
void
@ -211,15 +213,18 @@ TransactionBuilder::IsEmpty() const
}
void
TransactionBuilder::SetWindowParameters(LayoutDeviceIntSize size)
TransactionBuilder::SetWindowParameters(const LayoutDeviceIntSize& aWindowSize,
const LayoutDeviceIntRect& aDocumentRect)
{
wr_transaction_set_window_parameters(mTxn, size.width, size.height);
}
void
TransactionBuilder::UpdateResources(ResourceUpdateQueue& aUpdates)
{
wr_transaction_update_resources(mTxn, aUpdates.Raw());
wr::DeviceUintSize wrWindowSize;
wrWindowSize.width = aWindowSize.width;
wrWindowSize.height = aWindowSize.height;
wr::DeviceUintRect wrDocRect;
wrDocRect.origin.x = aDocumentRect.x;
wrDocRect.origin.y = aDocumentRect.y;
wrDocRect.size.width = aDocumentRect.width;
wrDocRect.size.height = aDocumentRect.height;
wr_transaction_set_window_parameters(mTxn, &wrWindowSize, &wrDocRect);
}
void
@ -287,9 +292,28 @@ WebRenderAPI::Clone()
RefPtr<WebRenderAPI> renderApi = new WebRenderAPI(docHandle, mId, mMaxTextureSize, mUseANGLE, mSyncHandle);
renderApi->mRootApi = this; // Hold root api
renderApi->mRootDocumentApi = this;
return renderApi.forget();
}
already_AddRefed<WebRenderAPI>
WebRenderAPI::CreateDocument(LayoutDeviceIntSize aSize, int8_t aLayerIndex)
{
wr::DeviceUintSize wrSize;
wrSize.width = aSize.width;
wrSize.height = aSize.height;
wr::DocumentHandle* newDoc;
wr_api_create_document(mDocHandle, &newDoc, wrSize, aLayerIndex);
RefPtr<WebRenderAPI> api(new WebRenderAPI(newDoc, mId,
mMaxTextureSize,
mUseANGLE,
mSyncHandle));
api->mRootApi = this;
return api.forget();
}
wr::WrIdNamespace
WebRenderAPI::GetNamespace() {
return wr_api_get_namespace(mDocHandle);
@ -299,14 +323,19 @@ extern void ClearBlobImageResources(WrIdNamespace aNamespace);
WebRenderAPI::~WebRenderAPI()
{
if (!mRootApi) {
if (!mRootDocumentApi) {
wr_api_delete_document(mDocHandle);
}
if (!mRootApi) {
RenderThread::Get()->SetDestroyed(GetId());
layers::SynchronousTask task("Destroy WebRenderAPI");
auto event = MakeUnique<RemoveRenderer>(&task);
RunOnRenderThread(Move(event));
task.Wait();
wr_api_shut_down(mDocHandle);
}
// wr_api_get_namespace cannot be marked destructor-safe because it has a
@ -330,6 +359,7 @@ WebRenderAPI::~WebRenderAPI()
void
WebRenderAPI::SendTransaction(TransactionBuilder& aTxn)
{
wr_transaction_update_resources(aTxn.Raw(), aTxn.RawUpdates());
wr_api_send_transaction(mDocHandle, aTxn.Raw());
}
@ -513,66 +543,40 @@ WebRenderAPI::Capture()
}
ResourceUpdateQueue::ResourceUpdateQueue()
void
TransactionBuilder::Clear()
{
mUpdates = wr_resource_updates_new();
}
ResourceUpdateQueue::ResourceUpdateQueue(ResourceUpdateQueue&& aFrom)
{
mUpdates = aFrom.mUpdates;
aFrom.mUpdates = nullptr;
}
ResourceUpdateQueue&
ResourceUpdateQueue::operator=(ResourceUpdateQueue&& aFrom)
{
mUpdates = aFrom.mUpdates;
aFrom.mUpdates = nullptr;
return *this;
}
ResourceUpdateQueue::~ResourceUpdateQueue()
{
if (mUpdates) {
wr_resource_updates_delete(mUpdates);
}
wr_resource_updates_clear(mResourceUpdates);
}
void
ResourceUpdateQueue::Clear()
TransactionBuilder::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes)
{
wr_resource_updates_clear(mUpdates);
}
void
ResourceUpdateQueue::AddImage(ImageKey key, const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes)
{
wr_resource_updates_add_image(mUpdates,
wr_resource_updates_add_image(mResourceUpdates,
key,
&aDescriptor,
&aBytes.inner);
}
void
ResourceUpdateQueue::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes)
TransactionBuilder::AddBlobImage(ImageKey key, const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes)
{
wr_resource_updates_add_blob_image(mUpdates,
wr_resource_updates_add_blob_image(mResourceUpdates,
key,
&aDescriptor,
&aBytes.inner);
}
void
ResourceUpdateQueue::AddExternalImage(ImageKey key,
const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::WrExternalImageBufferType aBufferType,
uint8_t aChannelIndex)
TransactionBuilder::AddExternalImage(ImageKey key,
const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::WrExternalImageBufferType aBufferType,
uint8_t aChannelIndex)
{
wr_resource_updates_add_external_image(mUpdates,
wr_resource_updates_add_external_image(mResourceUpdates,
key,
&aDescriptor,
aExtID,
@ -581,9 +585,9 @@ ResourceUpdateQueue::AddExternalImage(ImageKey key,
}
void
ResourceUpdateQueue::AddExternalImageBuffer(ImageKey aKey,
const ImageDescriptor& aDescriptor,
ExternalImageId aHandle)
TransactionBuilder::AddExternalImageBuffer(ImageKey aKey,
const ImageDescriptor& aDescriptor,
ExternalImageId aHandle)
{
auto channelIndex = 0;
AddExternalImage(aKey, aDescriptor, aHandle,
@ -592,23 +596,23 @@ ResourceUpdateQueue::AddExternalImageBuffer(ImageKey aKey,
}
void
ResourceUpdateQueue::UpdateImageBuffer(ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes)
TransactionBuilder::UpdateImageBuffer(ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes)
{
wr_resource_updates_update_image(mUpdates,
wr_resource_updates_update_image(mResourceUpdates,
aKey,
&aDescriptor,
&aBytes.inner);
}
void
ResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes,
const wr::DeviceUintRect& aDirtyRect)
TransactionBuilder::UpdateBlobImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes,
const wr::DeviceUintRect& aDirtyRect)
{
wr_resource_updates_update_blob_image(mUpdates,
wr_resource_updates_update_blob_image(mResourceUpdates,
aKey,
&aDescriptor,
&aBytes.inner,
@ -616,13 +620,13 @@ ResourceUpdateQueue::UpdateBlobImage(ImageKey aKey,
}
void
ResourceUpdateQueue::UpdateExternalImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::WrExternalImageBufferType aBufferType,
uint8_t aChannelIndex)
TransactionBuilder::UpdateExternalImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::WrExternalImageBufferType aBufferType,
uint8_t aChannelIndex)
{
wr_resource_updates_update_external_image(mUpdates,
wr_resource_updates_update_external_image(mResourceUpdates,
aKey,
&aDescriptor,
aExtID,
@ -631,46 +635,46 @@ ResourceUpdateQueue::UpdateExternalImage(ImageKey aKey,
}
void
ResourceUpdateQueue::DeleteImage(ImageKey aKey)
TransactionBuilder::DeleteImage(ImageKey aKey)
{
wr_resource_updates_delete_image(mUpdates, aKey);
wr_resource_updates_delete_image(mResourceUpdates, aKey);
}
void
ResourceUpdateQueue::AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex)
TransactionBuilder::AddRawFont(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex)
{
wr_resource_updates_add_raw_font(mUpdates, aKey, &aBytes.inner, aIndex);
wr_resource_updates_add_raw_font(mResourceUpdates, aKey, &aBytes.inner, aIndex);
}
void
ResourceUpdateQueue::AddFontDescriptor(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex)
TransactionBuilder::AddFontDescriptor(wr::FontKey aKey, wr::Vec<uint8_t>& aBytes, uint32_t aIndex)
{
wr_resource_updates_add_font_descriptor(mUpdates, aKey, &aBytes.inner, aIndex);
wr_resource_updates_add_font_descriptor(mResourceUpdates, aKey, &aBytes.inner, aIndex);
}
void
ResourceUpdateQueue::DeleteFont(wr::FontKey aKey)
TransactionBuilder::DeleteFont(wr::FontKey aKey)
{
wr_resource_updates_delete_font(mUpdates, aKey);
wr_resource_updates_delete_font(mResourceUpdates, aKey);
}
void
ResourceUpdateQueue::AddFontInstance(wr::FontInstanceKey aKey,
wr::FontKey aFontKey,
float aGlyphSize,
const wr::FontInstanceOptions* aOptions,
const wr::FontInstancePlatformOptions* aPlatformOptions,
wr::Vec<uint8_t>& aVariations)
TransactionBuilder::AddFontInstance(wr::FontInstanceKey aKey,
wr::FontKey aFontKey,
float aGlyphSize,
const wr::FontInstanceOptions* aOptions,
const wr::FontInstancePlatformOptions* aPlatformOptions,
wr::Vec<uint8_t>& aVariations)
{
wr_resource_updates_add_font_instance(mUpdates, aKey, aFontKey, aGlyphSize,
wr_resource_updates_add_font_instance(mResourceUpdates, aKey, aFontKey, aGlyphSize,
aOptions, aPlatformOptions,
&aVariations.inner);
}
void
ResourceUpdateQueue::DeleteFontInstance(wr::FontInstanceKey aKey)
TransactionBuilder::DeleteFontInstance(wr::FontInstanceKey aKey)
{
wr_resource_updates_delete_font_instance(mUpdates, aKey);
wr_resource_updates_delete_font_instance(mResourceUpdates, aKey);
}
class FrameStartTime : public RendererEvent

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

@ -50,16 +50,42 @@ struct Line {
wr::LineStyle style;
};
/// Updates to retained resources such as images and fonts, applied within the
/// same transaction.
class ResourceUpdateQueue {
class TransactionBuilder {
public:
ResourceUpdateQueue();
~ResourceUpdateQueue();
ResourceUpdateQueue(ResourceUpdateQueue&&);
ResourceUpdateQueue(const ResourceUpdateQueue&) = delete;
ResourceUpdateQueue& operator=(ResourceUpdateQueue&&);
ResourceUpdateQueue& operator=(const ResourceUpdateQueue&) = delete;
TransactionBuilder();
~TransactionBuilder();
void UpdateEpoch(PipelineId aPipelineId, Epoch aEpoch);
void SetRootPipeline(PipelineId aPipelineId);
void RemovePipeline(PipelineId aPipelineId);
void SetDisplayList(gfx::Color aBgColor,
Epoch aEpoch,
mozilla::LayerSize aViewportSize,
wr::WrPipelineId pipeline_id,
const wr::LayoutSize& content_size,
wr::BuiltDisplayListDescriptor dl_descriptor,
wr::Vec<uint8_t>& dl_data);
void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline);
void GenerateFrame();
void UpdateDynamicProperties(const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
const nsTArray<wr::WrTransformProperty>& aTransformArray);
void SetWindowParameters(const LayoutDeviceIntSize& aWindowSize,
const LayoutDeviceIntRect& aDocRect);
void UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
const layers::FrameMetrics::ViewID& aScrollId,
const wr::LayoutPoint& aScrollPosition);
bool IsEmpty() const;
void AddImage(wr::ImageKey aKey,
const ImageDescriptor& aDescriptor,
@ -113,56 +139,11 @@ public:
void Clear();
// Try to avoid using this when possible.
wr::ResourceUpdates* Raw() { return mUpdates; }
protected:
explicit ResourceUpdateQueue(wr::ResourceUpdates* aUpdates)
: mUpdates(aUpdates) {}
wr::ResourceUpdates* mUpdates;
};
class TransactionBuilder {
public:
TransactionBuilder();
~TransactionBuilder();
void UpdateEpoch(PipelineId aPipelineId, Epoch aEpoch);
void SetRootPipeline(PipelineId aPipelineId);
void RemovePipeline(PipelineId aPipelineId);
void SetDisplayList(gfx::Color aBgColor,
Epoch aEpoch,
mozilla::LayerSize aViewportSize,
wr::WrPipelineId pipeline_id,
const wr::LayoutSize& content_size,
wr::BuiltDisplayListDescriptor dl_descriptor,
wr::Vec<uint8_t>& dl_data);
void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline);
void GenerateFrame();
void UpdateDynamicProperties(const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
const nsTArray<wr::WrTransformProperty>& aTransformArray);
void SetWindowParameters(LayoutDeviceIntSize size);
void UpdateResources(ResourceUpdateQueue& aUpdates);
void UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
const layers::FrameMetrics::ViewID& aScrollId,
const wr::LayoutPoint& aScrollPosition);
bool IsEmpty() const;
Transaction* Raw() { return mTxn; }
wr::ResourceUpdates* RawUpdates() { return mResourceUpdates; }
protected:
Transaction* mTxn;
wr::ResourceUpdates* mResourceUpdates;
};
class WebRenderAPI
@ -175,6 +156,8 @@ public:
RefPtr<widget::CompositorWidget>&& aWidget,
LayoutDeviceIntSize aSize);
already_AddRefed<WebRenderAPI> CreateDocument(LayoutDeviceIntSize aSize, int8_t aLayerIndex);
// Redirect the WR's log to gfxCriticalError/Note.
static void InitExternalLogHandler();
static void ShutdownExternalLogHandler();
@ -224,7 +207,17 @@ protected:
uint32_t mMaxTextureSize;
bool mUseANGLE;
layers::SyncHandle mSyncHandle;
// We maintain alive the root api to know when to shut the render backend down,
// and the root api for the document to know when to delete the document.
// mRootApi is null for the api object that owns the channel (and is responsible
// for shutting it down), and mRootDocumentApi is null for the api object owning
// (and responsible for destroying) a given document.
// All api objects in the same window use the same channel, and some api objects
// write to the same document (but there is only one owner for each channel and
// for each document).
RefPtr<wr::WebRenderAPI> mRootApi;
RefPtr<wr::WebRenderAPI> mRootDocumentApi;
friend class DisplayListBuilder;
friend class layers::WebRenderBridgeParent;

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

@ -100,8 +100,7 @@ pub struct DocumentHandle {
}
impl DocumentHandle {
pub fn new(api: RenderApi, size: DeviceUintSize) -> DocumentHandle {
let layer = 0; //TODO
pub fn new(api: RenderApi, size: DeviceUintSize, layer: i8) -> DocumentHandle {
let doc = api.add_document(size, layer);
DocumentHandle {
api: api,
@ -782,16 +781,41 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
*out_max_texture_size = renderer.get_max_texture_size();
}
let window_size = DeviceUintSize::new(window_width, window_height);
let layer = 0;
*out_handle = Box::into_raw(Box::new(
DocumentHandle::new(sender.create_api(), window_size)));
DocumentHandle::new(sender.create_api(), window_size, layer)));
*out_renderer = Box::into_raw(Box::new(renderer));
return true;
}
#[no_mangle]
pub extern "C" fn wr_api_clone(dh: &mut DocumentHandle,
out_handle: &mut *mut DocumentHandle) {
pub extern "C" fn wr_api_create_document(
root_dh: &mut DocumentHandle,
out_handle: &mut *mut DocumentHandle,
doc_size: DeviceUintSize,
layer: i8,
) {
assert!(unsafe { is_in_compositor_thread() });
*out_handle = Box::into_raw(Box::new(DocumentHandle::new(
root_dh.api.clone_sender().create_api(),
doc_size,
layer
)));
}
/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
#[no_mangle]
pub unsafe extern "C" fn wr_api_delete_document(dh: &mut DocumentHandle) {
dh.api.delete_document(dh.document_id);
}
#[no_mangle]
pub extern "C" fn wr_api_clone(
dh: &mut DocumentHandle,
out_handle: &mut *mut DocumentHandle
) {
assert!(unsafe { is_in_compositor_thread() });
let handle = DocumentHandle {
@ -804,11 +828,13 @@ pub extern "C" fn wr_api_clone(dh: &mut DocumentHandle,
/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
#[no_mangle]
pub unsafe extern "C" fn wr_api_delete(dh: *mut DocumentHandle) {
let handle = Box::from_raw(dh);
if handle.document_id.0 == handle.api.get_namespace_id() {
handle.api.delete_document(handle.document_id);
handle.api.shut_down();
}
let _ = Box::from_raw(dh);
}
/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
#[no_mangle]
pub unsafe extern "C" fn wr_api_shut_down(dh: &mut DocumentHandle) {
dh.api.shut_down();
}
#[no_mangle]
@ -888,19 +914,21 @@ pub extern "C" fn wr_transaction_update_resources(
txn: &mut Transaction,
resource_updates: &mut ResourceUpdates
) {
if resource_updates.updates.is_empty() {
return;
}
txn.update_resources(mem::replace(resource_updates, ResourceUpdates::new()));
}
#[no_mangle]
pub extern "C" fn wr_transaction_set_window_parameters(
txn: &mut Transaction,
window_width: i32,
window_height: i32,
window_size: &DeviceUintSize,
doc_rect: &DeviceUintRect,
) {
let size = DeviceUintSize::new(window_width as u32, window_height as u32);
txn.set_window_parameters(
size,
DeviceUintRect::new(DeviceUintPoint::new(0, 0), size),
*window_size,
*doc_rect,
1.0,
);
}

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

@ -325,6 +325,8 @@ struct TypedSize2D {
}
};
using DeviceUintSize = TypedSize2D<uint32_t, DevicePixel>;
using LayerSize = TypedSize2D<float, LayerPixel>;
using LayoutSize = LayerSize;
@ -986,10 +988,21 @@ void wr_api_clone(DocumentHandle *aDh,
DocumentHandle **aOutHandle)
WR_FUNC;
WR_INLINE
void wr_api_create_document(DocumentHandle *aRootDh,
DocumentHandle **aOutHandle,
DeviceUintSize aDocSize,
int8_t aLayer)
WR_FUNC;
WR_INLINE
void wr_api_delete(DocumentHandle *aDh)
WR_DESTRUCTOR_SAFE_FUNC;
WR_INLINE
void wr_api_delete_document(DocumentHandle *aDh)
WR_DESTRUCTOR_SAFE_FUNC;
WR_INLINE
void wr_api_finalize_builder(WrState *aState,
LayoutSize *aContentSize,
@ -1019,6 +1032,10 @@ void wr_api_send_transaction(DocumentHandle *aDh,
Transaction *aTransaction)
WR_FUNC;
WR_INLINE
void wr_api_shut_down(DocumentHandle *aDh)
WR_DESTRUCTOR_SAFE_FUNC;
WR_INLINE
void wr_clear_item_tag(WrState *aState)
WR_FUNC;
@ -1587,8 +1604,8 @@ WR_FUNC;
WR_INLINE
void wr_transaction_set_window_parameters(Transaction *aTxn,
int32_t aWindowWidth,
int32_t aWindowHeight)
const DeviceUintSize *aWindowSize,
const DeviceUintRect *aDocRect)
WR_FUNC;
WR_INLINE

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

@ -14,10 +14,11 @@
#include "threading/ConditionVariable.h"
#include "vm/MutexIDs.h"
#include "vm/NativeObject.h"
namespace js {
class AtomicsObject : public JSObject
class AtomicsObject : public NativeObject
{
public:
static const Class class_;

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

@ -4963,6 +4963,24 @@ IsLegacyIterator(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
EnableExpressionClosures(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS::ContextOptionsRef(cx).setExpressionClosures(true);
args.rval().setUndefined();
return true;
}
static bool
DisableExpressionClosures(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS::ContextOptionsRef(cx).setExpressionClosures(false);
args.rval().setUndefined();
return true;
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
JS_FN_HELP("gc", ::GC, 0, 0,
"gc([obj] | 'zone' [, 'shrinking'])",
@ -5579,6 +5597,14 @@ gc::ZealModeHelpText),
"getTimeZone()",
" Get the current time zone.\n"),
JS_FN_HELP("enableExpressionClosures", EnableExpressionClosures, 0, 0,
"enableExpressionClosures()",
" Enables the deprecated, non-standard expression closures.\n"),
JS_FN_HELP("disableExpressionClosures", DisableExpressionClosures, 0, 0,
"disableExpressionClosures()",
" Disables the deprecated, non-standard expression closures.\n"),
JS_FS_HELP_END
};

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

@ -1449,6 +1449,8 @@ OutlineTypedObject::createUnattachedWithClass(JSContext* cx,
MOZ_ASSERT(clasp == &OutlineTransparentTypedObject::class_ ||
clasp == &OutlineOpaqueTypedObject::class_);
AutoSetNewObjectMetadata metadata(cx);
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp,
TaggedProto(&descr->typedProto()),
descr));
@ -2225,7 +2227,7 @@ const ObjectOps TypedObject::objectOps_ = {
nullptr, /* thisValue */
};
#define DEFINE_TYPEDOBJ_CLASS(Name, Trace, Moved, flag) \
#define DEFINE_TYPEDOBJ_CLASS(Name, Trace, Moved) \
static const ClassOps Name##ClassOps = { \
nullptr, /* addProperty */ \
nullptr, /* delProperty */ \
@ -2245,7 +2247,8 @@ const ObjectOps TypedObject::objectOps_ = {
}; \
const Class Name::class_ = { \
# Name, \
Class::NON_NATIVE | flag, \
Class::NON_NATIVE | \
JSCLASS_DELAY_METADATA_BUILDER, \
&Name##ClassOps, \
JS_NULL_CLASS_SPEC, \
&Name##ClassExt, \
@ -2254,20 +2257,16 @@ const ObjectOps TypedObject::objectOps_ = {
DEFINE_TYPEDOBJ_CLASS(OutlineTransparentTypedObject,
OutlineTypedObject::obj_trace,
nullptr,
0);
nullptr);
DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTypedObject,
OutlineTypedObject::obj_trace,
nullptr,
0);
nullptr);
DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject,
InlineTypedObject::obj_trace,
InlineTypedObject::obj_moved,
JSCLASS_DELAY_METADATA_BUILDER);
InlineTypedObject::obj_moved);
DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject,
InlineTypedObject::obj_trace,
InlineTypedObject::obj_moved,
JSCLASS_DELAY_METADATA_BUILDER);
InlineTypedObject::obj_moved);
static int32_t
LengthForType(TypeDescr& descr)
@ -2410,15 +2409,11 @@ TypedObject::create(JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap h
return cx->alreadyReportedOOM();
TypedObject* tobj = static_cast<TypedObject*>(obj);
tobj->group_.init(group);
tobj->initGroup(group);
tobj->initShape(shape);
tobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
if (clasp->shouldDelayMetadataBuilder())
cx->compartment()->setObjectPendingMetadata(cx, tobj);
else
tobj = SetNewObjectMetadata(cx, tobj);
MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
cx->compartment()->setObjectPendingMetadata(cx, tobj);
js::gc::TraceCreateObject(tobj);

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

@ -752,7 +752,7 @@ class InlineOpaqueTypedObject : public InlineTypedObject
};
// Class for the global SIMD object.
class SimdObject : public JSObject
class SimdObject : public NativeObject
{
public:
static const Class class_;

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

@ -3260,15 +3260,15 @@ Parser<FullParseHandler, CharT>::skipLazyInnerFunction(ParseNode* funcNode, uint
if (!tokenStream.advance(fun->lazyScript()->end()))
return false;
#if JS_HAS_EXPR_CLOSURES
// Only expression closure can be Statement kind.
// If we remove expression closure, we can remove isExprBody flag from
// LazyScript and JSScript.
if (kind == Statement && funbox->isExprBody()) {
if (!matchOrInsertSemicolon())
return false;
if (allowExpressionClosures()) {
// Only expression closure can be Statement kind.
// If we remove expression closure, we can remove isExprBody flag from
// LazyScript and JSScript.
if (kind == Statement && funbox->isExprBody()) {
if (!matchOrInsertSemicolon())
return false;
}
}
#endif
// Append possible Annex B function box only upon successfully parsing.
if (tryAnnexB && !pc->innermostScope()->addPossibleAnnexBFunctionBox(pc, funbox))
@ -3778,14 +3778,14 @@ GeneralParser<ParseHandler, CharT>::functionFormalParametersAndBody(InHandling i
return false;
}
#if JS_HAS_EXPR_CLOSURES
this->addTelemetry(DeprecatedLanguageExtension::ExpressionClosure);
if (!warnOnceAboutExprClosure())
if (allowExpressionClosures()) {
this->addTelemetry(DeprecatedLanguageExtension::ExpressionClosure);
if (!warnOnceAboutExprClosure())
return false;
} else {
error(JSMSG_CURLY_BEFORE_BODY);
return false;
#else
error(JSMSG_CURLY_BEFORE_BODY);
return false;
#endif
}
}
anyChars.ungetToken();
@ -3847,9 +3847,8 @@ GeneralParser<ParseHandler, CharT>::functionFormalParametersAndBody(InHandling i
JSMSG_CURLY_OPENED, openedPos));
funbox->setEnd(anyChars);
} else {
#if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow);
#endif
MOZ_ASSERT_IF(!allowExpressionClosures(), kind == Arrow);
if (anyChars.hadError())
return false;
funbox->setEnd(anyChars);

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

@ -340,7 +340,9 @@ class ParserBase
bool hasValidSimpleStrictParameterNames();
bool allowExpressionClosures() const {
return options().expressionClosuresOption;
}
/*
* Create a new function object given a name (which is optional if this is
* a function expression).
@ -703,6 +705,7 @@ class GeneralParser
using Base::isValidSimpleAssignmentTarget;
using Base::pc;
using Base::usedNames;
using Base::allowExpressionClosures;
private:
using Base::checkAndMarkSuperScope;
@ -1403,6 +1406,7 @@ class Parser<FullParseHandler, CharT> final
using Base::pos;
using Base::ss;
using Base::tokenStream;
using Base::allowExpressionClosures;
private:
using Base::alloc;

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

@ -38,7 +38,7 @@ js::Allocate(JSContext* cx, AllocKind kind, size_t nDynamicSlots, InitialHeap he
static_assert(sizeof(JSObject_Slots0) >= MinCellSize,
"All allocations must be at least the allocator-imposed minimum size.");
MOZ_ASSERT_IF(nDynamicSlots != 0, clasp->isNative() || clasp->isProxy());
MOZ_ASSERT_IF(nDynamicSlots != 0, clasp->isNative());
// Off-thread alloc cannot trigger GC or make runtime assertions.
if (cx->helperThread()) {
@ -119,10 +119,12 @@ GCRuntime::tryNewTenuredObject(JSContext* cx, AllocKind kind, size_t thingSize,
JSObject* obj = tryNewTenuredThing<JSObject, allowGC>(cx, kind, thingSize);
if (obj)
obj->setInitialSlotsMaybeNonNative(slots);
else
if (obj) {
if (nDynamicSlots)
static_cast<NativeObject*>(obj)->initSlots(slots);
} else {
js_free(slots);
}
return obj;
}

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

@ -21,7 +21,8 @@ struct Class;
//
// Note that JSObject allocation must use the longer signature below that
// includes slot, heap, and finalizer information in support of various
// object-specific optimizations.
// object-specific optimizations. If dynamic slots are requested they will be
// allocated and the pointer stored directly in |NativeObject::slots_|.
template <typename T, AllowGC allowGC = CanGC>
T*
Allocate(JSContext* cx);

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

@ -265,7 +265,7 @@ js::Nursery::leaveZealMode() {
#endif // JS_GC_ZEAL
JSObject*
js::Nursery::allocateObject(JSContext* cx, size_t size, size_t numDynamic, const js::Class* clasp)
js::Nursery::allocateObject(JSContext* cx, size_t size, size_t nDynamicSlots, const js::Class* clasp)
{
/* Ensure there's enough space to replace the contents with a RelocationOverlay. */
MOZ_ASSERT(size >= sizeof(RelocationOverlay));
@ -281,9 +281,9 @@ js::Nursery::allocateObject(JSContext* cx, size_t size, size_t numDynamic, const
/* If we want external slots, add them. */
HeapSlot* slots = nullptr;
if (numDynamic) {
if (nDynamicSlots) {
MOZ_ASSERT(clasp->isNative());
slots = static_cast<HeapSlot*>(allocateBuffer(cx->zone(), numDynamic * sizeof(HeapSlot)));
slots = static_cast<HeapSlot*>(allocateBuffer(cx->zone(), nDynamicSlots * sizeof(HeapSlot)));
if (!slots) {
/*
* It is safe to leave the allocated object uninitialized, since we
@ -293,8 +293,11 @@ js::Nursery::allocateObject(JSContext* cx, size_t size, size_t numDynamic, const
}
}
/* Always initialize the slots field to match the JIT behavior. */
obj->setInitialSlotsMaybeNonNative(slots);
/* Store slots pointer directly in new object. If no dynamic slots were
* requested, caller must initialize slots_ field itself as needed. We
* don't know if the caller was a native object or not. */
if (nDynamicSlots)
static_cast<NativeObject*>(obj)->initSlots(slots);
TraceNurseryAlloc(obj, size);
return obj;

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

@ -1104,12 +1104,11 @@ function test_syntax(postfixes, check_error, ignore_opts) {
// Expression closures
if (getBuildConfiguration().release_or_beta) {
test("function f() 1 ");
test("function f() 1; ");
test("(function () 1 ");
test("(function () 1); ");
}
enableExpressionClosures();
test("function f() 1 ");
test("function f() 1; ");
test("(function () 1 ");
test("(function () 1); ");
// ==== asm.js ====

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

@ -1,11 +1,11 @@
load(libdir + "asm.js");
load(libdir + "asserts.js");
if (getBuildConfiguration().release_or_beta) {
assertAsmTypeFail(USE_ASM + 'function f() 0');
assertAsmTypeFail(USE_ASM + 'function f() 0; return 0');
assertAsmTypeFail(USE_ASM + 'function f() 0; return f');
}
enableExpressionClosures();
assertAsmTypeFail(USE_ASM + 'function f() 0');
assertAsmTypeFail(USE_ASM + 'function f() 0; return 0');
assertAsmTypeFail(USE_ASM + 'function f() 0; return f');
assertAsmTypeFail(USE_ASM);
assertAsmTypeFail(USE_ASM + 'return');

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

@ -10,7 +10,7 @@ f = Function("");
assertEq(f.toString(), "function anonymous(\n) {\n\n}");
f = Function("", "(abc)");
assertEq(f.toString(), "function anonymous(\n) {\n(abc)\n}");
if (getBuildConfiguration().release_or_beta) {
f = Function("", "return function (a,b) a + b;")();
assertEq(f.toString(), "function (a,b) a + b");
}
enableExpressionClosures();
f = Function("", "return function (a,b) a + b;")();
assertEq(f.toString(), "function (a,b) a + b");

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

@ -1,4 +1,4 @@
if (getBuildConfiguration().release_or_beta)
enableExpressionClosures();
eval(`
function f1(foo, bar) foo + bar;
assertEq(f1.toString(), "function f1(foo, bar) foo + bar");

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

@ -0,0 +1,35 @@
// Testing InstanceOf IC.
Array.prototype.sum = function() {
return this.reduce(( acc, cur ) => acc + cur, 0);
}
Iters = 20;
function resultArray(fn, obj) {
res = new Array();
for (var x = 0; x < Iters; x++) {
res.push(fn(obj) ? 1 : 0);
}
return res;
}
// Ensure alteration of .prototype invalidates IC
function basic() {};
protoA = { prop1: "1"};
basic.prototype = protoA;
io1 = x => { return x instanceof basic; }
var x = new basic();
beforePrototypeModification = resultArray(io1,x).sum(); //Attach and test IC
assertEq(beforePrototypeModification,Iters);
basic.prototype = {}; // Invalidate IC
afterPrototypeModification = resultArray(io1,x).sum(); //Test
assertEq(afterPrototypeModification,0);
//Primitive LHS returns false.
assertEq(resultArray(io1,0).sum(),0);

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

@ -1,4 +1,4 @@
if (getBuildConfiguration().release_or_beta)
enableExpressionClosures();
eval(`
m = {
i() {},

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

@ -1,12 +1,11 @@
if (getBuildConfiguration().release_or_beta) {
eval(`
function f() {
// The expression closure is deliberate here, testing the semicolon after
// one when it appears as a FunctionDeclaration from B.3.4
// FunctionDeclarations in IfStatement Statement Clauses.
if (0)
function g() x;
else;
}
f();`)
enableExpressionClosures();
eval(`
function f() {
// The expression closure is deliberate here, testing the semicolon after
// one when it appears as a FunctionDeclaration from B.3.4
// FunctionDeclarations in IfStatement Statement Clauses.
if (0)
function g() x;
else;
}
f();`)

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

@ -2,14 +2,13 @@
var release_or_beta = getBuildConfiguration().release_or_beta;
enableExpressionClosures();
function testWarn(code) {
if (release_or_beta) {
// Warning for expression closure is non-release-only (not Release/Beta).
testPass(code);
return;
} else {
// !!! expression closures are currently completely disabled in Nightly
return;
}
enableLastWarning();

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

@ -449,6 +449,34 @@ BaselineCacheIRCompiler::emitGuardXrayExpandoShapeAndDefaultProto()
return true;
}
bool
BaselineCacheIRCompiler::emitGuardFunctionPrototype()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register prototypeObject = allocator.useRegister(masm, reader.objOperandId());
// Allocate registers before the failure path to make sure they're registered
// by addFailurePath.
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
// Guard on the .prototype object.
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch1);
masm.load32(Address(stubAddress(reader.stubOffset())), scratch2);
BaseValueIndex prototypeSlot(scratch1, scratch2);
masm.branchTestObject(Assembler::NotEqual, prototypeSlot, failure->label());
masm.unboxObject(prototypeSlot, scratch1);
masm.branchPtr(Assembler::NotEqual,
prototypeObject,
scratch1, failure->label());
return true;
}
bool
BaselineCacheIRCompiler::emitLoadFixedSlotResult()
{
@ -2076,6 +2104,7 @@ BaselineCacheIRCompiler::init(CacheKind kind)
case CacheKind::SetProp:
case CacheKind::In:
case CacheKind::HasOwn:
case CacheKind::InstanceOf:
MOZ_ASSERT(numInputs == 2);
allocator.initInputLocation(0, R0);
allocator.initInputLocation(1, R1);

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

@ -4292,46 +4292,34 @@ ICIteratorClose_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
static bool
TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub,
HandleFunction fun, bool* attached)
HandleValue lhs, HandleObject rhs, bool* attached)
{
MOZ_ASSERT(!*attached);
if (fun->isBoundFunction())
return true;
FallbackICSpew(cx, stub, "InstanceOf");
// If the user has supplied their own @@hasInstance method we shouldn't
// clobber it.
if (!js::FunctionHasDefaultHasInstance(fun, cx->wellKnownSymbols()))
return true;
if (stub->state().maybeTransition())
stub->discardStubs(cx);
// Refuse to optimize any function whose [[Prototype]] isn't
// Function.prototype.
if (!fun->hasStaticPrototype() || fun->hasUncacheableProto())
return true;
if (stub->state().canAttachStub()) {
RootedScript script(cx, frame->script());
jsbytecode* pc = stub->icEntry()->pc(script);
Value funProto = cx->global()->getPrototype(JSProto_Function);
if (funProto.isObject() && fun->staticPrototype() != &funProto.toObject())
return true;
ICStubEngine engine = ICStubEngine::Baseline;
InstanceOfIRGenerator gen(cx, script, pc, stub->state().mode(),
lhs,
rhs);
Shape* shape = fun->lookupPure(cx->names().prototype);
if (!shape || !shape->isDataProperty())
return true;
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
BaselineCacheIRStubKind::Regular,
engine, script, stub, attached);
if (newStub)
JitSpew(JitSpew_BaselineIC, " Attached InstanceOf CacheIR stub, attached is now %d", *attached);
}
if (!attached)
stub->state().trackNotAttached();
}
uint32_t slot = shape->slot();
MOZ_ASSERT(fun->numFixedSlots() == 0, "Stub code relies on this");
if (!fun->getSlot(slot).isObject())
return true;
JSObject* protoObject = &fun->getSlot(slot).toObject();
JitSpew(JitSpew_BaselineIC, " Generating InstanceOf(Function) stub");
ICInstanceOf_Function::Compiler compiler(cx, fun->lastProperty(), protoObject, slot);
ICStub* newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
return true;
}
@ -4362,12 +4350,8 @@ DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback*
// for use during Ion compilation.
EnsureTrackPropertyTypes(cx, obj, NameToId(cx->names().prototype));
if (stub->numOptimizedStubs() >= ICInstanceOf_Fallback::MAX_OPTIMIZED_STUBS)
return true;
RootedFunction fun(cx, &obj->as<JSFunction>());
bool attached = false;
if (!TryAttachInstanceOfStub(cx, frame, stub, fun, &attached))
if (!TryAttachInstanceOfStub(cx, frame, stub, lhs, obj, &attached))
return false;
if (!attached)
stub->noteUnoptimizableAccess();
@ -4399,82 +4383,6 @@ ICInstanceOf_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
return tailCallVM(DoInstanceOfFallbackInfo, masm);
}
bool
ICInstanceOf_Function::Compiler::generateStubCode(MacroAssembler& masm)
{
MOZ_ASSERT(engine_ == Engine::Baseline);
Label failure;
// Ensure RHS is an object.
masm.branchTestObject(Assembler::NotEqual, R1, &failure);
Register rhsObj = masm.extractObject(R1, ExtractTemp0);
// Allow using R1's type register as scratch. We have to restore it when
// we want to jump to the next stub.
Label failureRestoreR1;
AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
regs.takeUnchecked(rhsObj);
Register scratch1 = regs.takeAny();
Register scratch2 = regs.takeAny();
// Shape guard.
masm.loadPtr(Address(ICStubReg, ICInstanceOf_Function::offsetOfShape()), scratch1);
masm.branchTestObjShape(Assembler::NotEqual, rhsObj, scratch1, &failureRestoreR1);
// Guard on the .prototype object.
masm.loadPtr(Address(rhsObj, NativeObject::offsetOfSlots()), scratch1);
masm.load32(Address(ICStubReg, ICInstanceOf_Function::offsetOfSlot()), scratch2);
BaseValueIndex prototypeSlot(scratch1, scratch2);
masm.branchTestObject(Assembler::NotEqual, prototypeSlot, &failureRestoreR1);
masm.unboxObject(prototypeSlot, scratch1);
masm.branchPtr(Assembler::NotEqual,
Address(ICStubReg, ICInstanceOf_Function::offsetOfPrototypeObject()),
scratch1, &failureRestoreR1);
// If LHS is a primitive, return false.
Label returnFalse, returnTrue;
masm.branchTestObject(Assembler::NotEqual, R0, &returnFalse);
// LHS is an object. Load its proto.
masm.unboxObject(R0, scratch2);
masm.loadObjProto(scratch2, scratch2);
{
// Walk the proto chain until we either reach the target object,
// nullptr or LazyProto.
Label loop;
masm.bind(&loop);
masm.branchPtr(Assembler::Equal, scratch2, scratch1, &returnTrue);
masm.branchTestPtr(Assembler::Zero, scratch2, scratch2, &returnFalse);
MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
masm.branchPtr(Assembler::Equal, scratch2, ImmWord(1), &failureRestoreR1);
masm.loadObjProto(scratch2, scratch2);
masm.jump(&loop);
}
EmitReturnFromIC(masm);
masm.bind(&returnFalse);
masm.moveValue(BooleanValue(false), R0);
EmitReturnFromIC(masm);
masm.bind(&returnTrue);
masm.moveValue(BooleanValue(true), R0);
EmitReturnFromIC(masm);
masm.bind(&failureRestoreR1);
masm.tagValue(JSVAL_TYPE_OBJECT, rhsObj, R1);
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
//
// TypeOf_Fallback
//
@ -4667,14 +4575,6 @@ ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(JitCode* stubCode, const Value&
ICGetIntrinsic_Constant::~ICGetIntrinsic_Constant()
{ }
ICInstanceOf_Function::ICInstanceOf_Function(JitCode* stubCode, Shape* shape,
JSObject* prototypeObj, uint32_t slot)
: ICStub(InstanceOf_Function, stubCode),
shape_(shape),
prototypeObj_(prototypeObj),
slot_(slot)
{ }
ICCall_Scripted::ICCall_Scripted(JitCode* stubCode, ICStub* firstMonitorStub,
JSFunction* callee, JSObject* templateObject,
uint32_t pcOffset)

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

@ -1454,7 +1454,6 @@ class ICInstanceOf_Fallback : public ICFallbackStub
static const uint16_t UNOPTIMIZABLE_ACCESS_BIT = 0x1;
public:
static const uint32_t MAX_OPTIMIZED_STUBS = 4;
void noteUnoptimizableAccess() {
extra_ |= UNOPTIMIZABLE_ACCESS_BIT;
@ -1478,59 +1477,6 @@ class ICInstanceOf_Fallback : public ICFallbackStub
};
};
class ICInstanceOf_Function : public ICStub
{
friend class ICStubSpace;
GCPtrShape shape_;
GCPtrObject prototypeObj_;
uint32_t slot_;
ICInstanceOf_Function(JitCode* stubCode, Shape* shape, JSObject* prototypeObj, uint32_t slot);
public:
GCPtrShape& shape() {
return shape_;
}
GCPtrObject& prototypeObject() {
return prototypeObj_;
}
uint32_t slot() const {
return slot_;
}
static size_t offsetOfShape() {
return offsetof(ICInstanceOf_Function, shape_);
}
static size_t offsetOfPrototypeObject() {
return offsetof(ICInstanceOf_Function, prototypeObj_);
}
static size_t offsetOfSlot() {
return offsetof(ICInstanceOf_Function, slot_);
}
class Compiler : public ICStubCompiler {
RootedShape shape_;
RootedObject prototypeObj_;
uint32_t slot_;
protected:
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override;
public:
Compiler(JSContext* cx, Shape* shape, JSObject* prototypeObj, uint32_t slot)
: ICStubCompiler(cx, ICStub::InstanceOf_Function, Engine::Baseline),
shape_(cx, shape),
prototypeObj_(cx, prototypeObj),
slot_(slot)
{}
ICStub* getStub(ICStubSpace* space) override {
return newStub<ICInstanceOf_Function>(space, getStubCode(), shape_, prototypeObj_,
slot_);
}
};
};
// TypeOf
// JSOP_TYPEOF
// JSOP_TYPEOFEXPR

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

@ -1383,27 +1383,49 @@ BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
JSObject** prototypeObject)
{
MOZ_ASSERT(*pc == JSOP_INSTANCEOF);
if (!hasBaselineScript())
return false;
const ICEntry& entry = icEntryFromPC(pc);
ICStub* firstStub = entry.firstStub();
ICStub* stub = entry.firstStub();
if (!stub->isInstanceOf_Function() ||
!stub->next()->isInstanceOf_Fallback() ||
stub->next()->toInstanceOf_Fallback()->hadUnoptimizableAccess())
{
// Ensure singleton instanceof stub
if (!firstStub->next() ||
!firstStub->isCacheIR_Regular() ||
!firstStub->next()->isInstanceOf_Fallback() ||
firstStub->next()->toInstanceOf_Fallback()->hadUnoptimizableAccess())
{
return false;
}
ICCacheIR_Regular* stub = entry.firstStub()->toCacheIR_Regular();
CacheIRReader reader(stub->stubInfo());
ObjOperandId rhsId = ObjOperandId(1);
ObjOperandId resId = ObjOperandId(2);
if (!reader.matchOp(CacheOp::GuardIsObject, rhsId))
return false;
}
ICInstanceOf_Function* optStub = stub->toInstanceOf_Function();
*shape = optStub->shape();
*prototypeObject = optStub->prototypeObject();
*slot = optStub->slot();
if (!reader.matchOp(CacheOp::GuardShape, rhsId))
return false;
*shape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
if (!reader.matchOp(CacheOp::LoadObject, resId))
return false;
*prototypeObject = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset()).get();
if (IsInsideNursery(*prototypeObject))
return false;
if (!reader.matchOp(CacheOp::GuardFunctionPrototype, rhsId))
return false;
reader.skip(); // Skip over the protoID;
*slot = stub->stubInfo()->getStubRawWord(stub, reader.stubOffset());
return true;
}

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

@ -4001,6 +4001,120 @@ SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape
return true;
}
InstanceOfIRGenerator::InstanceOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleValue lhs, HandleObject rhs)
: IRGenerator(cx, script, pc, CacheKind::InstanceOf, mode),
lhsVal_(lhs),
rhsObj_(rhs)
{ }
bool
InstanceOfIRGenerator::tryAttachStub()
{
MOZ_ASSERT(cacheKind_ == CacheKind::InstanceOf);
AutoAssertNoPendingException aanpe(cx_);
// Ensure RHS is a function -- could be a Proxy, which the IC isn't prepared to handle.
if (!rhsObj_->is<JSFunction>()) {
trackNotAttached();
return false;
}
HandleFunction fun = rhsObj_.as<JSFunction>();
if (fun->isBoundFunction()) {
trackNotAttached();
return false;
}
// If the user has supplied their own @@hasInstance method we shouldn't
// clobber it.
if (!js::FunctionHasDefaultHasInstance(fun, cx_->wellKnownSymbols())) {
trackNotAttached();
return false;
}
// Refuse to optimize any function whose [[Prototype]] isn't
// Function.prototype.
if (!fun->hasStaticPrototype() || fun->hasUncacheableProto()) {
trackNotAttached();
return false;
}
Value funProto = cx_->global()->getPrototype(JSProto_Function);
if (!funProto.isObject() || fun->staticPrototype() != &funProto.toObject()) {
trackNotAttached();
return false;
}
// Ensure that the function's prototype slot is the same.
Shape* shape = fun->lookupPure(cx_->names().prototype);
if (!shape || !shape->isDataProperty()) {
trackNotAttached();
return false;
}
uint32_t slot = shape->slot();
MOZ_ASSERT(fun->numFixedSlots() == 0, "Stub code relies on this");
if (!fun->getSlot(slot).isObject()) {
trackNotAttached();
return false;
}
JSObject* prototypeObject = &fun->getSlot(slot).toObject();
// Abstract Objects
ValOperandId lhs(writer.setInputOperandId(0));
ValOperandId rhs(writer.setInputOperandId(1));
ObjOperandId rhsId = writer.guardIsObject(rhs);
writer.guardShape(rhsId, fun->lastProperty());
// Load prototypeObject into the cache -- consumed twice in the IC
ObjOperandId protoId = writer.loadObject(prototypeObject);
// Ensure that rhs[slot] == prototypeObject.
writer.guardFunctionPrototype(rhsId, slot, protoId);
// Needn't guard LHS is object, because the actual stub can handle that
// and correctly return false.
writer.loadInstanceOfObjectResult(lhs, protoId, slot);
writer.returnFromIC();
trackAttached("InstanceOf");
return true;
}
void
InstanceOfIRGenerator::trackAttached(const char* name)
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
sp.valueProperty(guard, "lhs", lhsVal_);
sp.valueProperty(guard, "rhs", ObjectValue(*rhsObj_));
sp.attached(guard, name);
sp.endCache(guard);
}
#endif
}
void
InstanceOfIRGenerator::trackNotAttached()
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
sp.valueProperty(guard, "lhs", lhsVal_);
sp.valueProperty(guard, "rhs", ObjectValue(*rhsObj_));
sp.endCache(guard);
}
#endif
}
TypeOfIRGenerator::TypeOfIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleValue value)
: IRGenerator(cx, script, pc, CacheKind::TypeOf, mode),

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

@ -148,6 +148,7 @@ class TypedOperandId : public OperandId
_(In) \
_(HasOwn) \
_(TypeOf) \
_(InstanceOf) \
_(GetIterator) \
_(Compare) \
_(Call)
@ -195,6 +196,7 @@ extern const char* CacheKindNames[];
_(GuardGroupHasUnanalyzedNewScript) \
_(GuardIndexIsNonNegative) \
_(GuardXrayExpandoShapeAndDefaultProto) \
_(GuardFunctionPrototype) \
_(LoadStackValue) \
_(LoadObject) \
_(LoadProto) \
@ -264,6 +266,7 @@ extern const char* CacheKindNames[];
_(LoadUndefinedResult) \
_(LoadBooleanResult) \
_(LoadStringResult) \
_(LoadInstanceOfObjectResult) \
_(LoadTypeOfObjectResult) \
\
_(CallStringSplitResult) \
@ -533,6 +536,12 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::GuardXrayExpandoShapeAndDefaultProto, obj);
buffer_.writeByte(uint32_t(!!shapeWrapper)); addStubField(uintptr_t(shapeWrapper), StubField::Type::JSObject);
}
// Guard rhs[slot] == prototypeObject
void guardFunctionPrototype(ObjOperandId rhs, uint32_t slot, ObjOperandId protoId) {
writeOpWithOperandId(CacheOp::GuardFunctionPrototype, rhs);
writeOperandId(protoId);
addStubField(slot, StubField::Type::RawWord);
}
void guardGroup(ObjOperandId obj, ObjectGroup* group) {
writeOpWithOperandId(CacheOp::GuardGroup, obj);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
@ -992,10 +1001,14 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
void loadObjectResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadObjectResult, obj);
}
void loadInstanceOfObjectResult(ValOperandId lhs, ObjOperandId protoId, uint32_t slot) {
writeOp(CacheOp::LoadInstanceOfObjectResult);
writeOperandId(lhs);
writeOperandId(protoId);
}
void loadTypeOfObjectResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadTypeOfObjectResult, obj);
}
void callStringSplitResult(StringOperandId str, StringOperandId sep, ObjectGroup* group) {
writeOp(CacheOp::CallStringSplitResult);
writeOperandId(str);
@ -1063,6 +1076,9 @@ class MOZ_RAII CacheIRReader
return CacheOp(buffer_.readByte());
}
// Skip data not currently used.
void skip() { buffer_.readByte(); }
ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
StringOperandId stringOperandId() { return StringOperandId(buffer_.readByte()); }
@ -1485,6 +1501,20 @@ class MOZ_RAII HasPropIRGenerator : public IRGenerator
bool tryAttachStub();
};
class MOZ_RAII InstanceOfIRGenerator : public IRGenerator
{
HandleValue lhsVal_;
HandleObject rhsObj_;
void trackAttached(const char* name);
void trackNotAttached();
public:
InstanceOfIRGenerator(JSContext*, HandleScript, jsbytecode*, ICState::Mode,
HandleValue, HandleObject);
bool tryAttachStub();
};
class MOZ_RAII TypeOfIRGenerator : public IRGenerator
{
HandleValue val_;

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

@ -863,6 +863,13 @@ AsGCPtr(uintptr_t* ptr)
return reinterpret_cast<GCPtr<T>*>(ptr);
}
uintptr_t
CacheIRStubInfo::getStubRawWord(ICStub* stub, uint32_t offset) const {
uint8_t* stubData = (uint8_t*)stub + stubDataOffset_;
MOZ_ASSERT(uintptr_t(stubData) % sizeof(uintptr_t) == 0);
return *(uintptr_t*)(stubData + offset);
}
template<class Stub, class T>
GCPtr<T>&
CacheIRStubInfo::getStubField(Stub* stub, uint32_t offset) const
@ -2631,3 +2638,50 @@ CacheIRCompiler::emitCallObjectHasSparseElementResult()
masm.adjustStack(sizeof(Value));
return true;
}
bool
CacheIRCompiler::emitLoadInstanceOfObjectResult()
{
AutoOutputRegister output(*this);
ValueOperand lhs = allocator.useValueRegister(masm, reader.valOperandId());
Register proto = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
Label returnFalse, returnTrue, done;
masm.branchTestObject(Assembler::NotEqual, lhs, &returnFalse);
// LHS is an object. Load its proto.
masm.unboxObject(lhs, scratch);
masm.loadObjProto(scratch, scratch);
{
// Walk the proto chain until we either reach the target object,
// nullptr or LazyProto.
Label loop;
masm.bind(&loop);
masm.branchPtr(Assembler::Equal, scratch, proto, &returnTrue);
masm.branchTestPtr(Assembler::Zero, scratch, scratch, &returnFalse);
MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
masm.branchPtr(Assembler::Equal, scratch, ImmWord(1), failure->label());
masm.loadObjProto(scratch, scratch);
masm.jump(&loop);
}
masm.bind(&returnFalse);
EmitStoreBoolean(masm, false, output);
masm.jump(&done);
masm.bind(&returnTrue);
EmitStoreBoolean(masm, true, output);
//fallthrough
masm.bind(&done);
return true;
}

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

@ -47,6 +47,7 @@ namespace jit {
_(LoadStringLengthResult) \
_(LoadStringCharResult) \
_(LoadArgumentsObjectArgResult) \
_(LoadInstanceOfObjectResult) \
_(LoadDenseElementResult) \
_(LoadDenseElementHoleResult) \
_(LoadDenseElementExistsResult) \
@ -712,6 +713,8 @@ class CacheIRStubInfo
return getStubField<ICStub, T>(stub, field);
}
uintptr_t getStubRawWord(ICStub* stub, uint32_t field) const;
void copyStubData(ICStub* src, ICStub* dest) const;
};

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

@ -173,6 +173,12 @@ typedef bool (*IonInICFn)(JSContext*, HandleScript, IonInIC*, HandleValue, Handl
static const VMFunction IonInICInfo =
FunctionInfo<IonInICFn>(IonInIC::update, "IonInIC::update");
typedef bool (*IonInstanceOfICFn)(JSContext*, HandleScript, IonInstanceOfIC*,
HandleValue lhs, HandleObject rhs, bool* res);
static const VMFunction IonInstanceOfInfo =
FunctionInfo<IonInstanceOfICFn>(IonInstanceOfIC::update, "IonInstanceOfIC::update");
void
CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
{
@ -331,6 +337,24 @@ CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
masm.jump(ool->rejoin());
return;
}
case CacheKind::InstanceOf: {
IonInstanceOfIC* hasInstanceOfIC = ic->asInstanceOfIC();
saveLive(lir);
pushArg(hasInstanceOfIC->rhs());
pushArg(hasInstanceOfIC->lhs());
icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
pushArg(ImmGCPtr(gen->info().script()));
callVM(IonInstanceOfInfo, lir);
StoreRegisterTo(hasInstanceOfIC->output()).generate(this);
restoreLiveIgnore(lir, StoreRegisterTo(hasInstanceOfIC->output()).clobbered());
masm.jump(ool->rejoin());
return;
}
case CacheKind::Call:
case CacheKind::Compare:
case CacheKind::TypeOf:
@ -11611,15 +11635,16 @@ typedef bool (*HasInstanceFn)(JSContext*, HandleObject, HandleValue, bool*);
static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance, "HasInstance");
void
CodeGenerator::visitCallInstanceOf(LCallInstanceOf* ins)
CodeGenerator::visitInstanceOfCache(LInstanceOfCache* ins)
{
ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
// The Lowering ensures that RHS is an object, and that LHS is a value.
LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
TypedOrValueRegister lhs = TypedOrValueRegister(ToValue(ins, LInstanceOfCache::LHS));
Register rhs = ToRegister(ins->rhs());
MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
Register output = ToRegister(ins->output());
pushArg(lhs);
pushArg(rhs);
callVM(HasInstanceInfo, ins);
IonInstanceOfIC ic(liveRegs, lhs, rhs, output);
addIC(ins, allocateIC(ic));
}
void

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

@ -371,7 +371,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitInArray(LInArray* ins) override;
void visitInstanceOfO(LInstanceOfO* ins) override;
void visitInstanceOfV(LInstanceOfV* ins) override;
void visitCallInstanceOf(LCallInstanceOf* ins) override;
void visitInstanceOfCache(LInstanceOfCache* ins) override;
void visitGetDOMProperty(LGetDOMProperty* lir) override;
void visitGetDOMMemberV(LGetDOMMemberV* lir) override;
void visitGetDOMMemberT(LGetDOMMemberT* lir) override;

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

@ -13214,7 +13214,7 @@ IonBuilder::jsop_instanceof()
return resumeAfter(ins);
} while (false);
MCallInstanceOf* ins = MCallInstanceOf::New(alloc(), obj, rhs);
MInstanceOfCache* ins = MInstanceOfCache::New(alloc(), obj, rhs);
current->add(ins);
current->push(ins);

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

@ -530,6 +530,19 @@ IonCacheIRCompiler::init()
allocator.initInputLocation(1, ic->value());
break;
}
case CacheKind::InstanceOf: {
IonInstanceOfIC* ic = ic_->asInstanceOfIC();
Register output = ic->output();
available.add(output);
liveRegs_.emplace(ic->liveRegs());
outputUnchecked_.emplace(TypedOrValueRegister(MIRType::Boolean, AnyRegister(output)));
MOZ_ASSERT(numInputs == 2);
allocator.initInputLocation(0, ic->lhs());
allocator.initInputLocation(1, TypedOrValueRegister(MIRType::Object,
AnyRegister(ic->rhs())));
break;
}
case CacheKind::Call:
case CacheKind::Compare:
case CacheKind::TypeOf:
@ -844,6 +857,35 @@ IonCacheIRCompiler::emitGuardXrayExpandoShapeAndDefaultProto()
return true;
}
bool
IonCacheIRCompiler::emitGuardFunctionPrototype()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register prototypeObject = allocator.useRegister(masm, reader.objOperandId());
// Allocate registers before the failure path to make sure they're registered
// by addFailurePath.
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure))
return false;
// Guard on the .prototype object.
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch1);
uintptr_t slot = readStubWord(reader.stubOffset(), StubField::Type::RawWord);
masm.move32(Imm32(slot), scratch2);
BaseValueIndex prototypeSlot(scratch1, scratch2);
masm.branchTestObject(Assembler::NotEqual, prototypeSlot, failure->label());
masm.unboxObject(prototypeSlot, scratch1);
masm.branchPtr(Assembler::NotEqual,
prototypeObject,
scratch1, failure->label());
return true;
}
bool
IonCacheIRCompiler::emitLoadFixedSlotResult()
{

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

@ -58,6 +58,8 @@ IonIC::scratchRegisterForEntryJump()
return asHasOwnIC()->output();
case CacheKind::GetIterator:
return asGetIteratorIC()->temp1();
case CacheKind::InstanceOf:
return asInstanceOfIC()->output();
case CacheKind::Call:
case CacheKind::Compare:
case CacheKind::TypeOf:
@ -474,6 +476,32 @@ IonInIC::update(JSContext* cx, HandleScript outerScript, IonInIC* ic,
return OperatorIn(cx, key, obj, res);
}
/* static */ bool
IonInstanceOfIC::update(JSContext* cx, HandleScript outerScript, IonInstanceOfIC* ic,
HandleValue lhs, HandleObject rhs, bool* res)
{
IonScript* ionScript = outerScript->ionScript();
if (ic->state().maybeTransition())
ic->discardStubs(cx->zone());
if (ic->state().canAttachStub()) {
bool attached = false;
RootedScript script(cx, ic->script());
jsbytecode* pc = ic->pc();
InstanceOfIRGenerator gen(cx, script, pc, ic->state().mode(),
lhs, rhs);
if (gen.tryAttachStub())
ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
if (!attached)
ic->state().trackNotAttached();
}
return HasInstance(cx, rhs, lhs, res);
}
uint8_t*
IonICStub::stubDataStart()

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

@ -64,6 +64,7 @@ class IonBindNameIC;
class IonGetIteratorIC;
class IonHasOwnIC;
class IonInIC;
class IonInstanceOfIC;
class IonIC
{
@ -167,6 +168,10 @@ class IonIC
MOZ_ASSERT(kind_ == CacheKind::In);
return (IonInIC*)this;
}
IonInstanceOfIC* asInstanceOfIC() {
MOZ_ASSERT(kind_ == CacheKind::InstanceOf);
return (IonInstanceOfIC*)this;
}
void updateBaseAddress(JitCode* code, MacroAssembler& masm);
@ -441,6 +446,35 @@ class IonInIC : public IonIC
HandleValue key, HandleObject obj, bool* res);
};
class IonInstanceOfIC : public IonIC
{
LiveRegisterSet liveRegs_;
TypedOrValueRegister lhs_;
Register rhs_;
Register output_;
public:
IonInstanceOfIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, Register rhs,
Register output)
: IonIC(CacheKind::InstanceOf),
liveRegs_(liveRegs),
lhs_(lhs),
rhs_(rhs),
output_(output)
{ }
LiveRegisterSet liveRegs() const { return liveRegs_; }
TypedOrValueRegister lhs() const { return lhs_; }
Register rhs() const { return rhs_; }
Register output() const { return output_; }
// This signature mimics that of TryAttachInstanceOfStub in baseline
static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonInstanceOfIC* ic,
HandleValue lhs, HandleObject rhs, bool* attached);
};
} // namespace jit
} // namespace js

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

@ -4335,7 +4335,7 @@ LIRGenerator::visitInstanceOf(MInstanceOf* ins)
}
void
LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins)
LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins)
{
MDefinition* lhs = ins->lhs();
MDefinition* rhs = ins->rhs();
@ -4343,9 +4343,9 @@ LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins)
MOZ_ASSERT(lhs->type() == MIRType::Value);
MOZ_ASSERT(rhs->type() == MIRType::Object);
LCallInstanceOf* lir = new(alloc()) LCallInstanceOf(useBoxAtStart(lhs),
useRegisterAtStart(rhs));
defineReturn(lir, ins);
LInstanceOfCache* lir = new(alloc()) LInstanceOfCache(useBox(lhs),
useRegister(rhs));
define(lir, ins);
assignSafepoint(lir, ins);
}

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

@ -294,7 +294,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitInArray(MInArray* ins) override;
void visitHasOwnCache(MHasOwnCache* ins) override;
void visitInstanceOf(MInstanceOf* ins) override;
void visitCallInstanceOf(MCallInstanceOf* ins) override;
void visitInstanceOfCache(MInstanceOfCache* ins) override;
void visitIsCallable(MIsCallable* ins) override;
void visitIsConstructor(MIsConstructor* ins) override;
void visitIsArray(MIsArray* ins) override;

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

@ -12923,18 +12923,18 @@ class MInstanceOf
};
// Implementation for instanceof operator with unknown rhs.
class MCallInstanceOf
class MInstanceOfCache
: public MBinaryInstruction,
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
{
MCallInstanceOf(MDefinition* obj, MDefinition* proto)
MInstanceOfCache(MDefinition* obj, MDefinition* proto)
: MBinaryInstruction(classOpcode, obj, proto)
{
setResultType(MIRType::Boolean);
}
public:
INSTRUCTION_HEADER(CallInstanceOf)
INSTRUCTION_HEADER(InstanceOfCache)
TRIVIAL_NEW_WRAPPERS
};

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

@ -275,7 +275,7 @@ namespace jit {
_(InCache) \
_(HasOwnCache) \
_(InstanceOf) \
_(CallInstanceOf) \
_(InstanceOfCache) \
_(InterruptCheck) \
_(GetDOMProperty) \
_(GetDOMMember) \

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

@ -875,6 +875,8 @@ MacroAssembler::allocateObject(Register result, Register temp, gc::AllocKind all
if (!nDynamicSlots)
return freeListAllocate(result, temp, allocKind, fail);
// Only NativeObject can have nDynamicSlots > 0 and reach here.
callMallocStub(nDynamicSlots * sizeof(GCPtrValue), temp, fail);
Label failAlloc;
@ -1205,8 +1207,8 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
storePtr(ImmGCPtr(templateObj->group()), Address(obj, JSObject::offsetOfGroup()));
if (Shape* shape = templateObj->maybeShape())
storePtr(ImmGCPtr(shape), Address(obj, ShapedObject::offsetOfShape()));
if (templateObj->is<ShapedObject>())
storePtr(ImmGCPtr(templateObj->maybeShape()), Address(obj, ShapedObject::offsetOfShape()));
MOZ_ASSERT_IF(convertDoubleElements, templateObj->is<ArrayObject>());
@ -1284,7 +1286,8 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
offset += sizeof(uintptr_t);
}
} else if (templateObj->is<UnboxedPlainObject>()) {
storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando()));
MOZ_ASSERT(!templateObj->as<UnboxedPlainObject>().maybeExpando());
storePtr(ImmPtr(nullptr), Address(obj, UnboxedPlainObject::offsetOfExpando()));
if (initContents)
initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>());
} else {

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

@ -297,12 +297,6 @@ ICStub::trace(JSTracer* trc)
TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
break;
}
case ICStub::InstanceOf_Function: {
ICInstanceOf_Function* instanceofStub = toInstanceOf_Function();
TraceEdge(trc, &instanceofStub->shape(), "baseline-instanceof-fun-shape");
TraceEdge(trc, &instanceofStub->prototypeObject(), "baseline-instanceof-fun-prototype");
break;
}
case ICStub::NewArray_Fallback: {
ICNewArray_Fallback* stub = toNewArray_Fallback();
TraceNullableEdge(trc, &stub->templateObject(), "baseline-newarray-template");

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

@ -328,9 +328,16 @@ template <typename L>
void
MacroAssemblerMIPSShared::ma_addTestCarry(Register rd, Register rs, Register rt, L overflow)
{
as_addu(rd, rs, rt);
as_sltu(SecondScratchReg, rd, rs);
ma_b(SecondScratchReg, SecondScratchReg, overflow, Assembler::NonZero);
if (rd != rs) {
as_addu(rd, rs, rt);
as_sltu(SecondScratchReg, rd, rs);
ma_b(SecondScratchReg, SecondScratchReg, overflow, Assembler::NonZero);
} else {
ma_move(SecondScratchReg, rs);
as_addu(rd, rs, rt);
as_sltu(SecondScratchReg, rd, SecondScratchReg);
ma_b(SecondScratchReg, SecondScratchReg, overflow, Assembler::NonZero);
}
}
template void
@ -709,7 +716,7 @@ MacroAssemblerMIPSShared::ma_store_unaligned(const wasm::MemoryAccessDesc& acces
int16_t lowOffset, hiOffset;
Register base;
asMasm().computeEffectiveAddress(dest, SecondScratchReg);
asMasm().computeScaledAddress(dest, SecondScratchReg);
if (Imm16::IsInSignedRange(dest.offset) && Imm16::IsInSignedRange(dest.offset + size / 8 - 1)) {
base = SecondScratchReg;

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

@ -65,8 +65,6 @@ struct EnterJITRegs
static void
GenerateReturn(MacroAssembler& masm, int returnCode)
{
MOZ_ASSERT(masm.framePushed() == sizeof(EnterJITRegs));
if (isLoongson()) {
// Restore non-volatile registers
masm.as_ld(s0, StackPointer, offsetof(EnterJITRegs, s0));

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

@ -8016,11 +8016,11 @@ class LInstanceOfV : public LInstructionHelper<1, BOX_PIECES, 0>
static const size_t LHS = 0;
};
class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
class LInstanceOfCache : public LInstructionHelper<1, BOX_PIECES+1, 0>
{
public:
LIR_HEADER(CallInstanceOf)
LCallInstanceOf(const LBoxAllocation& lhs, const LAllocation& rhs) {
LIR_HEADER(InstanceOfCache)
LInstanceOfCache(const LBoxAllocation& lhs, const LAllocation& rhs) {
setBoxOperand(LHS, lhs);
setOperand(RHS, rhs);
}

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

@ -383,7 +383,7 @@
_(HasOwnCache) \
_(InstanceOfO) \
_(InstanceOfV) \
_(CallInstanceOf) \
_(InstanceOfCache) \
_(InterruptCheck) \
_(Rotate) \
_(RotateI64) \

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

@ -3991,6 +3991,7 @@ JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOp
canLazilyParse = rhs.canLazilyParse;
strictOption = rhs.strictOption;
extraWarningsOption = rhs.extraWarningsOption;
expressionClosuresOption = rhs.expressionClosuresOption;
werrorOption = rhs.werrorOption;
asmJSOption = rhs.asmJSOption;
throwOnAsmJSValidationFailureOption = rhs.throwOnAsmJSValidationFailureOption;
@ -4112,6 +4113,7 @@ JS::CompileOptions::CompileOptions(JSContext* cx)
{
strictOption = cx->options().strictMode();
extraWarningsOption = cx->compartment()->behaviors().extraWarnings(cx);
expressionClosuresOption = cx->options().expressionClosures();
isProbablySystemOrAddonCode = cx->compartment()->isProbablySystemOrAddonCode();
werrorOption = cx->options().werror();
if (!cx->options().asmJS())

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

@ -1117,6 +1117,7 @@ class JS_PUBLIC_API(ContextOptions) {
#ifdef FUZZING
, fuzzing_(false)
#endif
, expressionClosures_(false)
{
}
@ -1272,6 +1273,12 @@ class JS_PUBLIC_API(ContextOptions) {
}
#endif
bool expressionClosures() const { return expressionClosures_; }
ContextOptions& setExpressionClosures(bool flag) {
expressionClosures_ = flag;
return *this;
}
void disableOptionsForSafeMode() {
setBaseline(false);
setIon(false);
@ -1302,6 +1309,7 @@ class JS_PUBLIC_API(ContextOptions) {
#ifdef FUZZING
bool fuzzing_ : 1;
#endif
bool expressionClosures_ : 1;
};
@ -3668,6 +3676,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
canLazilyParse(true),
strictOption(false),
extraWarningsOption(false),
expressionClosuresOption(false),
werrorOption(false),
asmJSOption(AsmJSOption::Disabled),
throwOnAsmJSValidationFailureOption(false),
@ -3702,6 +3711,7 @@ class JS_FRIEND_API(TransitiveCompileOptions)
bool canLazilyParse;
bool strictOption;
bool extraWarningsOption;
bool expressionClosuresOption;
bool werrorOption;
AsmJSOption asmJSOption;
bool throwOnAsmJSValidationFailureOption;

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

@ -132,7 +132,7 @@ class PropertyIteratorObject : public NativeObject
static void finalize(FreeOp* fop, JSObject* obj);
};
class ArrayIteratorObject : public JSObject
class ArrayIteratorObject : public NativeObject
{
public:
static const Class class_;
@ -141,7 +141,7 @@ class ArrayIteratorObject : public JSObject
ArrayIteratorObject*
NewArrayIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
class StringIteratorObject : public JSObject
class StringIteratorObject : public NativeObject
{
public:
static const Class class_;

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

@ -128,6 +128,10 @@ class JSObject : public js::gc::Cell
return group_;
}
void initGroup(js::ObjectGroup* group) {
group_.init(group);
}
/*
* Whether this is the only object which has its specified group. This
* object will have its group constructed lazily as needed by analysis.
@ -150,13 +154,6 @@ class JSObject : public js::gc::Cell
inline js::Shape* maybeShape() const;
inline js::Shape* ensureShape(JSContext* cx);
// Set the initial slots and elements of an object. These pointers are only
// valid for native objects, but during initialization are set for all
// objects. For non-native objects, these must not be dynamically allocated
// pointers which leak when the non-native object finishes initialization.
inline void setInitialSlotsMaybeNonNative(js::HeapSlot* slots);
inline void setInitialElementsMaybeNonNative(js::HeapSlot* elements);
enum GenerateShape {
GENERATE_NONE,
GENERATE_SHAPE

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

@ -397,18 +397,6 @@ SetNewObjectMetadata(JSContext* cx, T* obj)
} // namespace js
inline void
JSObject::setInitialSlotsMaybeNonNative(js::HeapSlot* slots)
{
static_cast<js::NativeObject*>(this)->slots_ = slots;
}
inline void
JSObject::setInitialElementsMaybeNonNative(js::HeapSlot* elements)
{
static_cast<js::NativeObject*>(this)->elements_ = elements;
}
inline js::GlobalObject&
JSObject::global() const
{

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

@ -14,10 +14,6 @@
#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */
#ifndef NIGHTLY_BUILD
#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */
#endif
/*
* Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support;
* support likely to be made opt-in at some future time.

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

@ -394,7 +394,8 @@ RCFile::release()
return true;
}
class FileObject : public JSObject {
class FileObject : public NativeObject
{
enum : uint32_t {
FILE_SLOT = 0,
NUM_SLOTS

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

@ -259,9 +259,6 @@ class JitTest:
elif name == 'test-also-wasm-tiering':
if options.wasm_enabled:
test.test_also.append(['--test-wasm-await-tier2'])
elif name == 'test-also-wasm-check-bce':
if options.wasm_enabled:
test.test_also.append(['--wasm-check-bce'])
elif name.startswith('test-also='):
test.test_also.append([name[len('test-also='):]])
elif name.startswith('test-join='):

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

@ -1,4 +1,4 @@
// |reftest| skip-if(!xulRuntime.shell) -- needs getBuildConfiguration
// |reftest| skip-if(!xulRuntime.shell)
/* 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/. */
@ -8,34 +8,33 @@
// closures, where subsequent token-examination must use the Operand modifier
// to avoid an assertion.
if (getBuildConfiguration().release_or_beta)
{
eval(`
var ec1 = function() 0 ? 1 : a => {};
assertEq(typeof ec1, "function");
assertEq(typeof ec1(), "function");
assertEq(ec1()(), undefined);
var ec2 = function() 0 ? 1 : a => {} // deliberately exercise ASI here
assertEq(typeof ec2, "function");
assertEq(typeof ec2(), "function");
assertEq(ec2()(), undefined);
enableExpressionClosures();
eval(`
var ec1 = function() 0 ? 1 : a => {};
assertEq(typeof ec1, "function");
assertEq(typeof ec1(), "function");
assertEq(ec1()(), undefined);
function ec3() 0 ? 1 : a => {} // exercise ASI here
assertEq(typeof ec3(), "function");
var ec2 = function() 0 ? 1 : a => {} // deliberately exercise ASI here
assertEq(typeof ec2, "function");
assertEq(typeof ec2(), "function");
assertEq(ec2()(), undefined);
function ec4() 0 ? 1 : a => {};
assertEq(typeof ec4(), "function");
function ec3() 0 ? 1 : a => {} // exercise ASI here
assertEq(typeof ec3(), "function");
var needle = "@";
var x = 42;
var g = { test() { assertEq(true, false, "shouldn't be called"); } };
function ec4() 0 ? 1 : a => {};
assertEq(typeof ec4(), "function");
function ec5() 0 ? 1 : a => {} // ASI
/x/g.test((needle = "x"));
assertEq(needle, "x");
`);
}
var needle = "@";
var x = 42;
var g = { test() { assertEq(true, false, "shouldn't be called"); } };
function ec5() 0 ? 1 : a => {} // ASI
/x/g.test((needle = "x"));
assertEq(needle, "x");
`);
if (typeof reportCompare === "function")
reportCompare(true, true);

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

@ -1,4 +1,4 @@
// |reftest| skip-if(!release_or_beta)
// |reftest| skip-if(!xulRuntime.shell)
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/*
* Any copyright is dedicated to the Public Domain.
@ -8,6 +8,9 @@
var summary = "Flat expression closure source coordinate fencepost test";
enableExpressionClosures();
eval(`
function f(a) {
if (a) {
let b = 42;
@ -20,5 +23,6 @@ function f(a) {
var expect = 44;
var actual = f(1)();
`);
reportCompare(expect, actual, summary);

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

@ -1,4 +1,4 @@
// |reftest| skip-if(!release_or_beta)
// |reftest| skip-if(!xulRuntime.shell)
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/*
* Any copyright is dedicated to the Public Domain.
@ -8,6 +8,9 @@
var summary = "Partial flat expression closure upvar order test";
enableExpressionClosures();
eval(`
function f(a) {
if (a) {
let b = 42;
@ -20,5 +23,6 @@ function f(a) {
var expect = 44;
var actual = f(1)();
`);
reportCompare(expect, actual, summary);

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

@ -1,8 +1,10 @@
// |reftest| skip-if(!xulRuntime.shell||!release_or_beta)
// |reftest| skip-if(!xulRuntime.shell)
function test() {
// expression closures
enableExpressionClosures();
assertDecl("function inc(x) (x + 1)", funDecl(ident("inc"), [ident("x")], binExpr("+", ident("x"), lit(1))));
assertExpr("(function(x) (x+1))", funExpr(null, [ident("x")], binExpr("+", ident("x"), lit(1))));

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

@ -1,4 +1,4 @@
// |reftest| skip-if(!release_or_beta)
// |reftest| skip-if(!xulRuntime.shell)
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -20,6 +20,8 @@ function test()
printBugNumber(BUGNUMBER);
printStatus (summary);
enableExpressionClosures();
expect = 'SyntaxError: unexpected token: identifier';
try
{

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

@ -435,7 +435,7 @@ bool CreateWasmBuffer(JSContext* cx, const wasm::Limits& memory,
* Common definitions shared by all array buffer views.
*/
class ArrayBufferViewObject : public JSObject
class ArrayBufferViewObject : public NativeObject
{
public:
static ArrayBufferObjectMaybeShared* bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*> obj);

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

@ -37,29 +37,34 @@ ArrayObject::createArrayInternal(JSContext* cx, gc::AllocKind kind, gc::InitialH
HandleShape shape, HandleObjectGroup group,
AutoSetNewObjectMetadata&)
{
// Create a new array and initialize everything except for its elements.
const js::Class* clasp = group->clasp();
MOZ_ASSERT(shape && group);
MOZ_ASSERT(group->clasp() == shape->getObjectClass());
MOZ_ASSERT(group->clasp() == &ArrayObject::class_);
MOZ_ASSERT_IF(group->clasp()->hasFinalize(), heap == gc::TenuredHeap);
MOZ_ASSERT(clasp == shape->getObjectClass());
MOZ_ASSERT(clasp == &ArrayObject::class_);
MOZ_ASSERT_IF(clasp->hasFinalize(), heap == gc::TenuredHeap);
MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
heap == js::gc::TenuredHeap);
MOZ_ASSERT(group->clasp()->shouldDelayMetadataBuilder());
// Arrays can use their fixed slots to store elements, so can't have shapes
// which allow named properties to be stored in the fixed slots.
MOZ_ASSERT(shape->numFixedSlots() == 0);
size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), group->clasp());
JSObject* obj = Allocate<JSObject>(cx, kind, nDynamicSlots, heap, group->clasp());
size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), clasp);
JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
if (!obj)
return nullptr;
static_cast<ArrayObject*>(obj)->shape_.init(shape);
static_cast<ArrayObject*>(obj)->group_.init(group);
ArrayObject* aobj = static_cast<ArrayObject*>(obj);
aobj->initGroup(group);
aobj->initShape(shape);
// NOTE: Dynamic slots are created internally by Allocate<JSObject>.
if (!nDynamicSlots)
aobj->initSlots(nullptr);
cx->compartment()->setObjectPendingMetadata(cx, obj);
return &obj->as<ArrayObject>();
MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
cx->compartment()->setObjectPendingMetadata(cx, aobj);
return aobj;
}
/* static */ inline ArrayObject*

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

@ -60,7 +60,8 @@ NewObjectCache::newObjectFromHit(JSContext* cx, EntryIndex entryIndex, gc::Initi
if (cx->runtime()->gc.upcomingZealousGC())
return nullptr;
NativeObject* obj = static_cast<NativeObject*>(Allocate<JSObject, NoGC>(cx, entry->kind, 0,
NativeObject* obj = static_cast<NativeObject*>(Allocate<JSObject, NoGC>(cx, entry->kind,
/* nDynamicSlots = */ 0,
heap, group->clasp()));
if (!obj)
return nullptr;

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

@ -17,6 +17,7 @@
#include "gc/Tracer.h"
#include "js/RootingAPI.h"
#include "js/UniquePtr.h"
#include "vm/ArrayObject.h"
#include "vm/NativeObject.h"
namespace js {
@ -200,6 +201,9 @@ class NewObjectCache
MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
Entry* entry = &entries[entry_];
MOZ_ASSERT(!obj->hasDynamicSlots());
MOZ_ASSERT(obj->hasEmptyElements() || obj->is<ArrayObject>());
entry->clasp = clasp;
entry->key = key;
entry->kind = kind;

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

@ -542,14 +542,15 @@ NativeObject::create(JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap
return cx->alreadyReportedOOM();
NativeObject* nobj = static_cast<NativeObject*>(obj);
nobj->group_.init(group);
nobj->initGroup(group);
nobj->initShape(shape);
// Note: slots are created and assigned internally by Allocate<JSObject>.
nobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
// NOTE: Dynamic slots are created internally by Allocate<JSObject>.
if (!nDynamicSlots)
nobj->initSlots(nullptr);
nobj->setEmptyElements();
if (clasp->hasPrivate())
nobj->privateRef(shape->numFixedSlots()) = nullptr;
nobj->initPrivate(nullptr);
if (size_t span = shape->slotSpan())
nobj->initializeSlotRange(0, span);

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

@ -680,6 +680,12 @@ class NativeObject : public ShapedObject
}
public:
/* Object allocation may directly initialize slots so this is public. */
void initSlots(HeapSlot* slots) {
slots_ = slots;
}
static MOZ_MUST_USE bool generateOwnShape(JSContext* cx, HandleNativeObject obj,
Shape* newShape = nullptr)
{
@ -1322,6 +1328,10 @@ class NativeObject : public ShapedObject
bool canHaveNonEmptyElements();
#endif
void setEmptyElements() {
elements_ = emptyObjectElements;
}
void setFixedElements(uint32_t numShifted = 0) {
MOZ_ASSERT(canHaveNonEmptyElements());
elements_ = fixedElements() + numShifted;

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

@ -182,12 +182,12 @@ ProxyObject::create(JSContext* cx, const Class* clasp, Handle<TaggedProto> proto
gc::InitialHeap heap = GetInitialHeap(newKind, clasp);
debugCheckNewObject(group, shape, allocKind, heap);
JSObject* obj = js::Allocate<JSObject>(cx, allocKind, /* numDynamicSlots = */ 0, heap, clasp);
JSObject* obj = js::Allocate<JSObject>(cx, allocKind, /* nDynamicSlots = */ 0, heap, clasp);
if (!obj)
return cx->alreadyReportedOOM();
ProxyObject* pobj = static_cast<ProxyObject*>(obj);
pobj->group_.init(group);
pobj->initGroup(group);
pobj->initShape(shape);
MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());

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

@ -627,12 +627,10 @@ UnboxedObject::createInternal(JSContext* cx, js::gc::AllocKind kind, js::gc::Ini
return cx->alreadyReportedOOM();
UnboxedObject* uobj = static_cast<UnboxedObject*>(obj);
uobj->group_.init(group);
uobj->initGroup(group);
if (clasp->shouldDelayMetadataBuilder())
cx->compartment()->setObjectPendingMetadata(cx, uobj);
else
uobj = SetNewObjectMetadata(cx, uobj);
MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
cx->compartment()->setObjectPendingMetadata(cx, uobj);
js::gc::TraceCreateObject(uobj);
@ -651,18 +649,17 @@ UnboxedPlainObject::create(JSContext* cx, HandleObjectGroup group, NewObjectKind
MOZ_ASSERT(newKind != SingletonObject);
UnboxedObject* res_;
JS_TRY_VAR_OR_RETURN_NULL(cx, res_, createInternal(cx, allocKind, heap, group));
UnboxedPlainObject* res = &res_->as<UnboxedPlainObject>();
JSObject* obj;
JS_TRY_VAR_OR_RETURN_NULL(cx, obj, createInternal(cx, allocKind, heap, group));
// Overwrite the dummy shape which was written to the object's expando field.
res->initExpando();
UnboxedPlainObject* uobj = static_cast<UnboxedPlainObject*>(obj);
uobj->initExpando();
// Initialize reference fields of the object. All fields in the object will
// be overwritten shortly, but references need to be safe for the GC.
const int32_t* list = res->layout().traceList();
const int32_t* list = uobj->layout().traceList();
if (list) {
uint8_t* data = res->data();
uint8_t* data = uobj->data();
while (*list != -1) {
GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list);
heap->init(cx->names().empty);
@ -678,7 +675,7 @@ UnboxedPlainObject::create(JSContext* cx, HandleObjectGroup group, NewObjectKind
MOZ_ASSERT(*(list + 1) == -1);
}
return res;
return uobj;
}
/* static */ JSObject*

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

@ -14,6 +14,7 @@
#include "brotli/decode.h"
#include "zlib.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/Unused.h"
namespace mozilla {
namespace dom {
@ -189,8 +190,19 @@ InspectorFontFace::GetMetadata(nsAString& aMetadata)
}
}
// Append an OpenType tag to a string as a 4-ASCII-character code.
static void
AppendTagAsASCII(nsAString& aString, uint32_t aTag)
{
aString.AppendPrintf("%c%c%c%c", (aTag >> 24) & 0xff,
(aTag >> 16) & 0xff,
(aTag >> 8) & 0xff,
aTag & 0xff);
}
void
InspectorFontFace::GetVariationAxes(nsTArray<InspectorVariationAxis>& aResult)
InspectorFontFace::GetVariationAxes(nsTArray<InspectorVariationAxis>& aResult,
ErrorResult& aRV)
{
if (!mFontEntry->HasVariations()) {
return;
@ -198,15 +210,13 @@ InspectorFontFace::GetVariationAxes(nsTArray<InspectorVariationAxis>& aResult)
AutoTArray<gfxFontVariationAxis,4> axes;
mFontEntry->GetVariationAxes(axes);
MOZ_ASSERT(!axes.IsEmpty());
if (!aResult.SetCapacity(axes.Length(), mozilla::fallible)) {
aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
for (auto a : axes) {
// Turn the uint32_t OpenType tag into a 4-ASCII-character string
nsAutoStringN<4> tag;
tag.AppendPrintf("%c%c%c%c", (a.mTag >> 24) & 0xff,
(a.mTag >> 16) & 0xff,
(a.mTag >> 8) & 0xff,
a.mTag & 0xff);
InspectorVariationAxis& axis = *aResult.AppendElement();
axis.mTag = tag;
AppendTagAsASCII(axis.mTag, a.mTag);
axis.mName = a.mName;
axis.mMinValue = a.mMinValue;
axis.mMaxValue = a.mMaxValue;
@ -214,5 +224,40 @@ InspectorFontFace::GetVariationAxes(nsTArray<InspectorVariationAxis>& aResult)
}
}
void
InspectorFontFace::GetVariationInstances(
nsTArray<InspectorVariationInstance>& aResult,
ErrorResult& aRV)
{
if (!mFontEntry->HasVariations()) {
return;
}
AutoTArray<gfxFontVariationInstance,16> instances;
mFontEntry->GetVariationInstances(instances);
if (!aResult.SetCapacity(instances.Length(), mozilla::fallible)) {
aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
for (auto i : instances) {
InspectorVariationInstance& inst = *aResult.AppendElement();
inst.mName = i.mName;
// inst.mValues is a webidl sequence<>, which is a fallible array,
// so we are required to use fallible SetCapacity and AppendElement calls,
// and check the result. In practice we don't expect failure here; the
// list of values cannot get huge because of limits in the font format.
if (!inst.mValues.SetCapacity(i.mValues.Length(), mozilla::fallible)) {
aRV.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
for (auto v : i.mValues) {
InspectorVariationValue value;
AppendTagAsASCII(value.mAxis, v.mAxis);
value.mValue = v.mValue;
// This won't fail, because of SetCapacity above.
Unused << inst.mValues.AppendElement(value, mozilla::fallible);
}
}
}
} // namespace dom
} // namespace mozilla

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

@ -55,7 +55,10 @@ public:
void GetFormat(nsAString& aFormat);
void GetMetadata(nsAString& aMetadata);
void GetVariationAxes(nsTArray<InspectorVariationAxis>& aResult);
void GetVariationAxes(nsTArray<InspectorVariationAxis>& aResult,
ErrorResult& aRV);
void GetVariationInstances(nsTArray<InspectorVariationInstance>& aResult,
ErrorResult& aRV);
bool WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto,

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

@ -12,6 +12,103 @@
SimpleTest.waitForExplicitFinish();
// Which platform are we on?
const kIsLinux = navigator.platform.indexOf("Linux") == 0;
const kIsMac = navigator.platform.indexOf("Mac") == 0;
const kIsWin = navigator.platform.indexOf("Win") == 0;
// If it's an older macOS version (pre-Sierra), we don't expect the
// @font-face examples to work, so just skip them.
const kIsOldMac = navigator.oscpu.substr(navigator.oscpu.lastIndexOf(".") + 1) < 12;
// We allow for some "fuzz" on axis values, given the conversions between
// fixed-point and floating-point representations.
const kEpsilon = 0.001;
const LibreFranklinAxes = [
{ tag: "wght", name: "Weight", minValue: 40, maxValue: 200, defaultValue: 40 },
];
const GinghamAxes = [
{ tag: "wght", name: "Weight", minValue: 300, maxValue: 700, defaultValue: 300 },
{ tag: "wdth", name: "Width", minValue: 1, maxValue: 150, defaultValue: 1 },
];
const SkiaAxes = [
{ tag: "wght", name: "Weight", minValue: 0.48, maxValue: 3.2, defaultValue: 1.0 },
{ tag: "wdth", name: "Width", minValue: 0.62, maxValue: 1.3, defaultValue: 1.0 },
];
function checkAxes(axes, reference) {
is(axes.length, reference.length, "number of variation axes");
for (var i = 0; i < Math.min(axes.length, reference.length); ++i) {
var v = axes[i];
var ref = reference[i];
is(v.tag, ref.tag, "axis tag");
is(v.name, ref.name, "axis name");
isfuzzy(v.minValue, ref.minValue, kEpsilon, "minimum value");
isfuzzy(v.maxValue, ref.maxValue, kEpsilon, "maximum value");
is(v.defaultValue, ref.defaultValue, "default value");
}
}
// Expected variation instances for each of our test fonts, sorted by name
const LibreFranklinInstances = [
{ name: "Black", values: [ { axis: "wght", value: 200 } ] },
{ name: "Bold", values: [ { axis: "wght", value: 154 } ] },
{ name: "ExtraBold", values: [ { axis: "wght", value: 178 } ] },
{ name: "ExtraLight", values: [ { axis: "wght", value: 50 } ] },
{ name: "Light", values: [ { axis: "wght", value: 66 } ] },
{ name: "Medium", values: [ { axis: "wght", value: 106 } ] },
{ name: "Regular", values: [ { axis: "wght", value: 84 } ] },
{ name: "SemiBold", values: [ { axis: "wght", value: 130 } ] },
{ name: "Thin", values: [ { axis: "wght", value: 40 } ] },
];
const GinghamInstances = [
{ name: "Bold", values: [ { axis: "wght", value: 700 }, { axis: "wdth", value: 100 } ] },
{ name: "Condensed Bold", values: [ { axis: "wght", value: 700 }, { axis: "wdth", value: 1 } ] },
{ name: "Condensed Light", values: [ { axis: "wght", value: 300 }, { axis: "wdth", value: 1 } ] },
{ name: "Condensed Regular", values: [ { axis: "wght", value: 400 }, { axis: "wdth", value: 1 } ] },
{ name: "Light", values: [ { axis: "wght", value: 300 }, { axis: "wdth", value: 100 } ] },
{ name: "Regular", values: [ { axis: "wght", value: 400 }, { axis: "wdth", value: 100 } ] },
{ name: "Wide Bold", values: [ { axis: "wght", value: 700 }, { axis: "wdth", value: 150 } ] },
{ name: "Wide Light", values: [ { axis: "wght", value: 300 }, { axis: "wdth", value: 150 } ] },
{ name: "Wide Regular", values: [ { axis: "wght", value: 400 }, { axis: "wdth", value: 150 } ] },
];
const SkiaInstances = [
{ name: "Black", values: [ { axis: "wght", value: 3.2 }, { axis: "wdth", value: 1 } ] },
{ name: "Black Condensed", values: [ { axis: "wght", value: 3 }, { axis: "wdth", value: 0.7 } ] },
{ name: "Black Extended", values: [ { axis: "wght", value: 3.2 }, { axis: "wdth", value: 1.3 } ] },
{ name: "Bold", values: [ { axis: "wght", value: 1.95 }, { axis: "wdth", value: 1 } ] },
{ name: "Condensed", values: [ { axis: "wght", value: 1 }, { axis: "wdth", value: 0.62 } ] },
{ name: "Extended", values: [ { axis: "wght", value: 1 }, { axis: "wdth", value: 1.3 } ] },
{ name: "Light", values: [ { axis: "wght", value: 0.48 }, { axis: "wdth", value: 1 } ] },
{ name: "Light Condensed", values: [ { axis: "wght", value: 0.48 }, { axis: "wdth", value: 0.7 } ] },
{ name: "Light Extended", values: [ { axis: "wght", value: 0.48 }, { axis: "wdth", value: 1.3 } ] },
{ name: "Regular", values: [ { axis: "wght", value: 1 }, { axis: "wdth", value: 1 } ] },
];
function checkInstances(instances, reference) {
is(instances.length, reference.length, "number of variation instances");
instances.sort(function (a, b) {
return a.name.localeCompare(b.name, "en-US");
});
for (var i = 0; i < Math.min(instances.length, reference.length); ++i) {
var ref = reference[i];
var inst = instances[i];
is(inst.name, ref.name, "instance name");
is(inst.values.length, ref.values.length, "number of values");
for (var j = 0; j < Math.min(inst.values.length, ref.values.length); ++j) {
var v = inst.values[j];
is(v.axis, ref.values[j].axis, "axis");
isfuzzy(v.value, ref.values[j].value, kEpsilon, "value");
}
}
}
function RunTest() {
// Ensure we're running with font-variations enabled
SpecialPowers.pushPrefEnv(
@ -19,33 +116,17 @@ function RunTest() {
['gfx.downloadable_fonts.keep_variation_tables', true],
['gfx.downloadable_fonts.otl_validation', false]]},
function() {
// Which platform are we on?
const kIsLinux = navigator.platform.indexOf("Linux") == 0;
const kIsMac = navigator.platform.indexOf("Mac") == 0;
const kIsWin = navigator.platform.indexOf("Win") == 0;
// Until bug 1433098 is fixed, Windows fails to return axis names
const nameTest = kIsWin ? todo : is;
// If it's an older macOS version (pre-Sierra), we don't expect the
// @font-face examples to work, so just skip them.
const kIsOldMac = navigator.oscpu.substr(navigator.oscpu.lastIndexOf(".") + 1) < 12;
var rng = document.createRange();
var elem, fonts, f;
// We allow for some "fuzz" on non-integer axis values, given the
// conversions between fixed-point and floating-point representations.
const kEpsilon = 0.001;
// First test element uses Arial, which has no variations
// First test element uses Arial (or a substitute), which has no variations
elem = document.getElementById("test1");
rng.selectNode(elem);
fonts = InspectorUtils.getUsedFontFaces(rng);
is(fonts.length, 1, "number of fonts: " + fonts.length);
is(fonts.length, 1, "number of fonts");
f = fonts[0];
var axes = f.getVariationAxes();
is(axes.length, 0, "no variations");
is(f.getVariationAxes().length, 0, "no variations");
is(f.getVariationInstances().length, 0, "no instances");
if (!(kIsMac && kIsOldMac)) {
// Libre Franklin font should have a single axis: Weight.
@ -53,25 +134,11 @@ function RunTest() {
elem.style.display = "block";
rng.selectNode(elem);
fonts = InspectorUtils.getUsedFontFaces(rng);
is(fonts.length, 1, "number of fonts: " + fonts.length);
is(fonts.length, 1, "number of fonts");
f = fonts[0];
is(f.name, "Libre Franklin", "font name: " + f.name);
axes = f.getVariationAxes();
is(axes.length, 1, "number of variation axes: " + axes.length);
for (var i = 0; i < axes.length; ++i) {
var v = axes[i];
switch (v.tag) {
case "wght":
nameTest(v.name, "Weight", "name of wght axis: " + v.name);
is(v.minValue, 40, "minimum weight: " + v.minValue);
is(v.maxValue, 200, "maximum weight: " + v.maxValue);
is(v.defaultValue, 40, "default weight: " + v.defaultValue);
break;
default:
ok(false, "unexpected axis: " + v.tag);
break;
}
}
is(f.name, "Libre Franklin", "font name");
checkAxes(f.getVariationAxes(), LibreFranklinAxes);
checkInstances(f.getVariationInstances(), LibreFranklinInstances);
// Gingham font should have two axes: Weight and Width.
elem = document.getElementById("test3");
@ -80,29 +147,9 @@ function RunTest() {
fonts = InspectorUtils.getUsedFontFaces(rng);
is(fonts.length, 1, "number of fonts");
f = fonts[0];
is(f.name, "Gingham Regular", "font name: " + f.name);
axes = f.getVariationAxes();
is(axes.length, 2, "number of variation axes");
for (var i = 0; i < axes.length; ++i) {
var v = axes[i];
switch (v.tag) {
case "wght":
nameTest(v.name, "Weight", "name of wght axis: " + v.name);
is(v.minValue, 300, "minimum weight: " + v.minValue);
is(v.maxValue, 700, "maximum weight: " + v.maxValue);
is(v.defaultValue, 300, "default weight: " + v.defaultValue);
break;
case "wdth":
nameTest(v.name, "Width", "name of wdth axis: " + v.name);
is(v.minValue, 1, "minimum width: " + v.minValue);
is(v.maxValue, 150, "maximum width: " + v.maxValue);
is(v.defaultValue, 1, "default width: " + v.defaultValue);
break;
default:
ok(false, "unexpected axis: " + v.tag);
break;
}
}
is(f.name, "Gingham Regular", "font name");
checkAxes(f.getVariationAxes(), GinghamAxes);
checkInstances(f.getVariationInstances(), GinghamInstances);
}
if (kIsMac) {
@ -111,31 +158,11 @@ function RunTest() {
elem = document.getElementById("test4");
rng.selectNode(elem);
fonts = InspectorUtils.getUsedFontFaces(rng);
is(fonts.length, 1, "number of fonts: " + fonts.length);
is(fonts.length, 1, "number of fonts");
f = fonts[0];
is(f.name, "Skia", "font name: " + f.name);
axes = f.getVariationAxes();
is(axes.length, 2, "number of variation axes: " + axes.length);
for (var i = 0; i < axes.length; ++i) {
var v = axes[i];
switch (v.tag) {
case "wght":
is(v.name, "Weight", "name of wght axis: " + v.name);
isfuzzy(v.minValue, 0.48, kEpsilon, "minimum weight: " + v.minValue);
isfuzzy(v.maxValue, 3.20, kEpsilon, "maximum weight: " + v.maxValue);
is(v.defaultValue, 1.0, "default weight: " + v.defaultValue);
break;
case "wdth":
is(v.name, "Width", "name of wdth axis: " + v.name);
isfuzzy(v.minValue, 0.62, kEpsilon, "minimum width: " + v.minValue);
isfuzzy(v.maxValue, 1.30, kEpsilon, "maximum width: " + v.maxValue);
is(v.defaultValue, 1.0, "default width: " + v.defaultValue);
break;
default:
ok(false, "unexpected axis: " + v.tag);
break;
}
}
is(f.name, "Skia", "font name");
checkAxes(f.getVariationAxes(), SkiaAxes);
checkInstances(f.getVariationInstances(), SkiaInstances);
}
SimpleTest.finish();

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше