merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2017-06-02 14:22:17 +02:00
Родитель 7acf8a7afd 064920e81e
Коммит efccdfdb0a
70 изменённых файлов: 1416 добавлений и 638 удалений

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

@ -428,8 +428,8 @@ description#identity-popup-content-verifier,
margin: 0;
width: 16px;
height: 16px;
list-style-image: url(chrome://browser/skin/panel-icons.svg#cancel);
filter: url(chrome://global/skin/filters.svg#fill);
list-style-image: url(chrome://browser/skin/panel-icon-cancel.svg);
-moz-context-properties: fill;
fill: graytext;
}

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

@ -93,7 +93,7 @@
width: 16px;
height: 16px;
margin: 0;
filter: url("chrome://global/skin/filters.svg#fill");
-moz-context-properties: fill;
fill: currentColor;
}
@ -123,19 +123,19 @@
/*** Button icons ***/
.downloadIconCancel > .button-box > .button-icon {
list-style-image: url("chrome://browser/skin/panel-icons.svg#cancel");
list-style-image: url("chrome://browser/skin/panel-icon-cancel.svg");
}
.downloadIconShow > .button-box > .button-icon {
%ifdef XP_MACOSX
list-style-image: url("chrome://browser/skin/panel-icons.svg#magnifier");
list-style-image: url("chrome://browser/skin/panel-icon-magnifier.svg");
%else
list-style-image: url("chrome://browser/skin/panel-icons.svg#folder");
list-style-image: url("chrome://browser/skin/panel-icon-folder.svg");
%endif
}
.downloadIconRetry > .button-box > .button-icon {
list-style-image: url("chrome://browser/skin/panel-icons.svg#retry");
list-style-image: url("chrome://browser/skin/panel-icon-retry.svg");
}
/*** Progressmeter ***/

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

@ -249,7 +249,7 @@ richlistitem[type="download"]:last-child {
width: 16px;
height: 16px;
margin: 1px;
filter: url("chrome://global/skin/filters.svg#fill");
-moz-context-properties: fill;
fill: currentColor;
}
@ -287,27 +287,27 @@ richlistitem[type="download"]:last-child {
/*** Button icons ***/
.downloadIconCancel > .button-box > .button-icon {
list-style-image: url("chrome://browser/skin/panel-icons.svg#cancel");
list-style-image: url("chrome://browser/skin/panel-icon-cancel.svg");
}
.downloadIconShow > .button-box > .button-icon {
%ifdef XP_MACOSX
list-style-image: url("chrome://browser/skin/panel-icons.svg#magnifier");
list-style-image: url("chrome://browser/skin/panel-icon-magnifier.svg");
%else
list-style-image: url("chrome://browser/skin/panel-icons.svg#folder");
list-style-image: url("chrome://browser/skin/panel-icon-folder.svg");
%endif
}
.downloadIconRetry > .button-box > .button-icon {
list-style-image: url("chrome://browser/skin/panel-icons.svg#retry");
list-style-image: url("chrome://browser/skin/panel-icon-retry.svg");
}
.downloadShowBlockedInfo > .button-box > .button-icon {
list-style-image: url("chrome://browser/skin/panel-icons.svg#arrow-right");
list-style-image: url("chrome://browser/skin/panel-icon-arrow-right.svg");
}
.downloadShowBlockedInfo > .button-box > .button-icon:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/panel-icons.svg#arrow-left");
list-style-image: url("chrome://browser/skin/panel-icon-arrow-left.svg");
}
/*** Blocked subview ***/
@ -325,11 +325,11 @@ richlistitem[type="download"]:last-child {
}
#downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack[viewtype="subview"] .download-state[showingsubview] .downloadButton > .button-box > .button-icon {
list-style-image: url("chrome://browser/skin/panel-icons.svg#arrow-left");
list-style-image: url("chrome://browser/skin/panel-icon-arrow-left.svg");
}
#downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack[viewtype="subview"] .download-state[showingsubview] .downloadButton > .button-box > .button-icon:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/panel-icons.svg#arrow-right");
list-style-image: url("chrome://browser/skin/panel-icon-arrow-right.svg");
}
#downloadsPanel-blockedSubview {

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

@ -70,7 +70,15 @@
skin/classic/browser/tracking-protection-16.svg (../shared/identity-block/tracking-protection-16.svg)
skin/classic/browser/newtab/close.png (../shared/newtab/close.png)
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
skin/classic/browser/panel-icons.svg (../shared/panel-icons.svg)
skin/classic/browser/panel-icon-arrow-left.svg (../shared/panel-icon-arrow-left.svg)
skin/classic/browser/panel-icon-arrow-right.svg (../shared/panel-icon-arrow-right.svg)
skin/classic/browser/panel-icon-cancel.svg (../shared/panel-icon-cancel.svg)
#ifndef XP_MACOSX
skin/classic/browser/panel-icon-folder.svg (../shared/panel-icon-folder.svg)
#else
skin/classic/browser/panel-icon-magnifier.svg (../shared/panel-icon-magnifier.svg)
#endif
skin/classic/browser/panel-icon-retry.svg (../shared/panel-icon-retry.svg)
skin/classic/browser/preferences/in-content-new/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content-new/icons.svg (../shared/incontentprefs/icons.svg)
skin/classic/browser/preferences/in-content-new/search.css (../shared/incontentprefs/search.css)

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

@ -0,0 +1,8 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="32" height="32" viewBox="0 0 32 32">
<path fill="context-fill" d="M23.5,25l-9-9l9-9l-3-3l-12,12l12,12L23.5,25z" />
</svg>

После

Ширина:  |  Высота:  |  Размер: 389 B

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

@ -0,0 +1,8 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="32" height="32" viewBox="0 0 32 32">
<path fill="context-fill" d="M11.6,28l12-12l-12-12l-3,3l9,9l-9,9L11.6,28z" />
</svg>

После

Ширина:  |  Высота:  |  Размер: 389 B

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

@ -0,0 +1,8 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="32" height="32" viewBox="0 0 32 32">
<path fill="context-fill" d="m 6,9.5 6.5,6.5 -6.5,6.5 3.5,3.5 6.5,-6.5 6.5,6.5 3.5,-3.5 -6.5,-6.5 6.5,-6.5 -3.5,-3.5 -6.5,6.5 -6.5,-6.5 z" />
</svg>

После

Ширина:  |  Высота:  |  Размер: 453 B

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

@ -0,0 +1,8 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="32" height="32" viewBox="0 0 32 32">
<path fill="context-fill" d="M17.3,9.4c0,0,1.1,0,3.7,0c1.7,0,2,0,5.6,0c0.6,0,0.6,0,1.1,0V9.2c0-1.5-0.9-2.6-2-2.6h-5.8V6.3c0-0.6-1.5-2-2.8-2h-7.1 H7.6H4.9v2.4v2.4v2.2c2.8,0,8.5,0,8.5,0C16.4,11.3,17.3,9.4,17.3,9.4z M29,13c0-0.6-0.6-1.1-1.5-1.7l0,0c-0.2,0-0.6,0-0.9,0 c-2.8,0-3,0-4.8,0c-1.9,0-3.3,0-3.3,0s-1.5,2.4-3.7,2.4c0,0-6.5,0-9.1,0H5.4C3,13.7,3,15.9,3,15.9l1.1,9.7C4.1,27.1,5,28,6.5,28 h19.1c1.5,0,2.4-0.9,2.4-2.4L29,13.7l0,0l0,0C29,13.7,29,13,29,13z" />
</svg>

После

Ширина:  |  Высота:  |  Размер: 769 B

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

@ -0,0 +1,8 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="32" height="32" viewBox="0 0 32 32">
<path fill="context-fill" d="M12.9,2c6,0,11,5,11,11c0,2.2-0.6,4.2-1.8,6l7.2,7c0.8,0.8,0.8,2.4,0,3.2c-0.6,0.6-1.2,0.8-1.6,0.8s-1.2-0.2-1.6-0.6l-7-7 c-1.8,1.2-3.8,1.8-6,1.8c-6,0-11-5-11-11C2.1,7.2,6.9,2,12.9,2z M12.9,20c3.8,0,7-3.2,7-7s-3.2-7-7-7s-7,3.2-7,7S9.1,20,12.9,20z" />
</svg>

После

Ширина:  |  Высота:  |  Размер: 587 B

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

@ -0,0 +1,8 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="32" height="32" viewBox="0 0 32 32">
<path fill="context-fill" d="M28,16.5v-14l-5,4.8c-1.8-1.4-4.4-2.4-7-2.4c-6.4,0-11.8,5.2-11.8,11.8c0,6.4,5.2,11.8,11.8,11.8c3.4,0,6.2-1.4,8.2-3.6 l-3.4-3.4c-1.2,1.2-3,1.8-5,1.8c-3.6,0.2-6.8-2.8-6.8-6.8c0-3.8,3-7.2,7-7.2c1.4,0,2.6,0.4,3.6,1l-6,6.2H28z"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 564 B

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

@ -1,18 +0,0 @@
<?xml version="1.0"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="32" height="32" viewBox="0 0 32 32">
<style>
path:not(:target) {
display: none;
}
</style>
<path id="cancel" d="m 6,9.5 6.5,6.5 -6.5,6.5 3.5,3.5 6.5,-6.5 6.5,6.5 3.5,-3.5 -6.5,-6.5 6.5,-6.5 -3.5,-3.5 -6.5,6.5 -6.5,-6.5 z" />
<path id="folder" d="M17.3,9.4c0,0,1.1,0,3.7,0c1.7,0,2,0,5.6,0c0.6,0,0.6,0,1.1,0V9.2c0-1.5-0.9-2.6-2-2.6h-5.8V6.3c0-0.6-1.5-2-2.8-2h-7.1 H7.6H4.9v2.4v2.4v2.2c2.8,0,8.5,0,8.5,0C16.4,11.3,17.3,9.4,17.3,9.4z M29,13c0-0.6-0.6-1.1-1.5-1.7l0,0c-0.2,0-0.6,0-0.9,0 c-2.8,0-3,0-4.8,0c-1.9,0-3.3,0-3.3,0s-1.5,2.4-3.7,2.4c0,0-6.5,0-9.1,0H5.4C3,13.7,3,15.9,3,15.9l1.1,9.7C4.1,27.1,5,28,6.5,28 h19.1c1.5,0,2.4-0.9,2.4-2.4L29,13.7l0,0l0,0C29,13.7,29,13,29,13z" />
<path id="magnifier" d="M12.9,2c6,0,11,5,11,11c0,2.2-0.6,4.2-1.8,6l7.2,7c0.8,0.8,0.8,2.4,0,3.2c-0.6,0.6-1.2,0.8-1.6,0.8s-1.2-0.2-1.6-0.6l-7-7 c-1.8,1.2-3.8,1.8-6,1.8c-6,0-11-5-11-11C2.1,7.2,6.9,2,12.9,2z M12.9,20c3.8,0,7-3.2,7-7s-3.2-7-7-7s-7,3.2-7,7S9.1,20,12.9,20z" />
<path id="retry" d="M28,16.5v-14l-5,4.8c-1.8-1.4-4.4-2.4-7-2.4c-6.4,0-11.8,5.2-11.8,11.8c0,6.4,5.2,11.8,11.8,11.8c3.4,0,6.2-1.4,8.2-3.6 l-3.4-3.4c-1.2,1.2-3,1.8-5,1.8c-3.6,0.2-6.8-2.8-6.8-6.8c0-3.8,3-7.2,7-7.2c1.4,0,2.6,0.4,3.6,1l-6,6.2H28z"/>
<path id="arrow-left" d="M23.5,25l-9-9l9-9l-3-3l-12,12l12,12L23.5,25z" />
<path id="arrow-right" d="M11.6,28l12-12l-12-12l-3,3l9,9l-9,9L11.6,28z" />
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.6 KiB

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

@ -14,6 +14,7 @@
#include "BasePoint3D.h"
#include "BasePoint4D.h"
#include "BaseSize.h"
#include "mozilla/Maybe.h"
#include "mozilla/TypeTraits.h"
#include <cmath>
@ -292,6 +293,7 @@ struct IntSizeTyped :
}
};
typedef IntSizeTyped<UnknownUnits> IntSize;
typedef Maybe<IntSize> MaybeIntSize;
template<class units, class F = Float>
struct SizeTyped :

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

@ -10,6 +10,7 @@
#include "Units.h"
#include "mozilla/gfx/Point.h" // for IntPoint
#include "mozilla/Maybe.h"
#include "mozilla/TypedEnumBits.h"
#include "nsRegion.h"
@ -214,6 +215,8 @@ typedef Array<LayerSize, 4> BorderCorners;
typedef Array<LayerCoord, 4> BorderWidths;
typedef Array<uint8_t, 4> BorderStyles;
typedef Maybe<LayerRect> MaybeLayerRect;
// This is used to communicate Layers across IPC channels. The Handle is valid
// for layers in the same PLayerTransaction. Handles are created by ClientLayerManager,
// and are cached in LayerTransactionParent on first use.

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

@ -532,6 +532,11 @@ CompositorBridgeParent::RecvWaitOnTransactionProcessed()
mozilla::ipc::IPCResult
CompositorBridgeParent::RecvFlushRendering()
{
if (gfxVars::UseWebRender()) {
mWrBridge->FlushRendering(/* aSync */ true);
return IPC_OK();
}
if (mCompositorScheduler->NeedsComposite()) {
CancelCurrentCompositeTask();
ForceComposeToTarget(nullptr);
@ -542,6 +547,11 @@ CompositorBridgeParent::RecvFlushRendering()
mozilla::ipc::IPCResult
CompositorBridgeParent::RecvFlushRenderingAsync()
{
if (gfxVars::UseWebRender()) {
mWrBridge->FlushRendering(/* aSync */ false);
return IPC_OK();
}
return RecvFlushRendering();
}

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

@ -21,8 +21,8 @@ using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using WrBuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
using WrSize from "mozilla/webrender/webrender_ffi.h";
using mozilla::layers::WebRenderScrollData from "mozilla/layers/WebRenderScrollData.h";
namespace mozilla {
@ -60,7 +60,8 @@ parent:
WrSize aContentSize, ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc,
WebRenderScrollData aScrollData);
sync DPGetSnapshot(PTexture texture);
async AddExternalImageId(ExternalImageId aImageId, CompositableHandle aHandle);
async AddPipelineIdForAsyncCompositable(PipelineId aImageId, CompositableHandle aHandle);
async RemovePipelineIdForAsyncCompositable(PipelineId aPipelineId);
async AddExternalImageIdForCompositable(ExternalImageId aImageId, CompositableHandle aHandle);
async RemoveExternalImageId(ExternalImageId aImageId);
async SetLayerObserverEpoch(uint64_t layerObserverEpoch);

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

@ -9,8 +9,17 @@ include LayersSurfaces;
include LayersMessages;
include protocol PTexture;
using WrSize from "mozilla/webrender/webrender_ffi.h";
using WrImageRendering from "mozilla/webrender/webrender_ffi.h";
using WrMixBlendMode from "mozilla/webrender/webrender_ffi.h";
using MaybeImageMask from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::gfx::MaybeIntSize from "mozilla/gfx/Point.h";
using mozilla::LayerPoint from "Units.h";
using mozilla::layers::MaybeLayerRect from "mozilla/layers/LayersTypes.h";
using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
@ -31,20 +40,26 @@ struct OpAddExternalImage {
ImageKey key;
};
struct OpAddExternalVideoImage {
ExternalImageId externalImageId;
ImageKey[] keys;
};
struct OpAddCompositorAnimations {
CompositorAnimations data;
OptionalTransform transform;
OptionalOpacity opacity;
};
struct OpUpdateAsyncImagePipeline {
PipelineId pipelineId;
LayerRect scBounds;
Matrix4x4 scTransform;
MaybeIntSize scaleToSize;
MaybeLayerRect clipRect;
MaybeImageMask mask;
WrImageRendering filter;
WrMixBlendMode mixBlendMode;
};
union WebRenderParentCommand {
OpAddExternalImage;
OpAddExternalVideoImage;
OpUpdateAsyncImagePipeline;
CompositableOperation;
OpAddCompositorAnimations;
};

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

@ -120,6 +120,19 @@ WebRenderBridgeChild::DPEnd(wr::DisplayListBuilder &aBuilder,
mIsInTransaction = false;
}
void
WebRenderBridgeChild::AddPipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId,
const CompositableHandle& aHandle)
{
SendAddPipelineIdForAsyncCompositable(aPipelineId, aHandle);
}
void
WebRenderBridgeChild::RemovePipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId)
{
SendRemovePipelineIdForAsyncCompositable(aPipelineId);
}
wr::ExternalImageId
WebRenderBridgeChild::GetNextExternalImageId()
{
@ -128,16 +141,6 @@ WebRenderBridgeChild::GetNextExternalImageId()
return id.value();
}
wr::ExternalImageId
WebRenderBridgeChild::AllocExternalImageId(const CompositableHandle& aHandle)
{
MOZ_ASSERT(!mDestroyed);
wr::ExternalImageId imageId = GetNextExternalImageId();
SendAddExternalImageId(imageId, aHandle);
return imageId;
}
wr::ExternalImageId
WebRenderBridgeChild::AllocExternalImageIdForCompositable(CompositableClient* aCompositable)
{

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

@ -73,7 +73,10 @@ public:
TextureForwarder* GetTextureForwarder() override;
LayersIPCActor* GetLayersIPCActor() override;
wr::ExternalImageId AllocExternalImageId(const CompositableHandle& aHandle);
void AddPipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId,
const CompositableHandle& aHandlee);
void RemovePipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId);
wr::ExternalImageId AllocExternalImageIdForCompositable(CompositableClient* aCompositable);
void DeallocExternalImageId(wr::ExternalImageId& aImageId);

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

@ -123,7 +123,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos
, mIdNameSpace(AllocIdNameSpace())
, mPaused(false)
, mDestroyed(false)
, mIsSnapshotting(false)
, mForceRendering(false)
{
MOZ_ASSERT(mCompositableHolder);
mCompositableHolder->AddPipeline(mPipelineId);
@ -133,6 +133,9 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos
}
}
WebRenderBridgeParent::~WebRenderBridgeParent()
{
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvCreate(const gfx::IntSize& aSize)
@ -454,7 +457,6 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
NS_ERROR("CompositableHost does not exist");
break;
}
// XXX select Texture for video in CompositeToTarget().
TextureHost* texture = host->GetAsTextureHostForComposite();
if (!texture) {
NS_ERROR("TextureHost does not exist");
@ -467,11 +469,13 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
}
RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
if (!dSurf) {
NS_ERROR("TextureHost does not return DataSourceSurface");
break;
}
DataSourceSurface::MappedSurface map;
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
NS_ERROR("DataSourceSurface failed to map");
break;
}
@ -483,49 +487,16 @@ WebRenderBridgeParent::ProcessWebRenderCommands(const gfx::IntSize &aSize,
dSurf->Unmap();
break;
}
case WebRenderParentCommand::TOpAddExternalVideoImage: {
const OpAddExternalVideoImage& op = cmd.get_OpAddExternalVideoImage();
MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get());
MOZ_ASSERT(op.keys().Length() > 0);
Range<const wr::ImageKey> keys(&(op.keys())[0], op.keys().Length());
for (auto key : keys) {
MOZ_ASSERT(!mActiveKeys.Get(wr::AsUint64(key), nullptr));
mActiveKeys.Put(wr::AsUint64(key), key);
}
RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId()));
if (!host) {
NS_ERROR("CompositableHost does not exist");
break;
}
// XXX select Texture for video in CompositeToTarget().
TextureHost* texture = host->GetAsTextureHostForComposite();
if (!texture) {
NS_ERROR("TextureHost does not exist");
break;
}
WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost();
if (wrTexture) {
wrTexture->AddWRImage(mApi, keys, wrTexture->GetExternalImageKey());
break;
}
MOZ_ASSERT(keys.length() == 1);
RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
if (!dSurf) {
break;
}
DataSourceSurface::MappedSurface map;
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
break;
}
IntSize size = dSurf->GetSize();
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
mApi->AddImage(keys[0], descriptor, slice);
dSurf->Unmap();
case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline();
mCompositableHolder->UpdateAsyncImagePipeline(op.pipelineId(),
op.scBounds(),
op.scTransform(),
op.scaleToSize(),
op.clipRect(),
op.mask(),
op.filter(),
op.mixBlendMode());
break;
}
case WebRenderParentCommand::TCompositableOperation: {
@ -618,7 +589,7 @@ WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture)
// Assert the stride of the buffer is what webrender expects
MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
mIsSnapshotting = true;
mForceRendering = true;
if (mCompositorScheduler->NeedsComposite()) {
mCompositorScheduler->CancelCurrentCompositeTask();
@ -627,20 +598,20 @@ WebRenderBridgeParent::RecvDPGetSnapshot(PTextureParent* aTexture)
mApi->Readback(size, buffer, buffer_size);
mIsSnapshotting = false;
mForceRendering = false;
return IPC_OK();
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvAddExternalImageId(const ExternalImageId& aImageId,
WebRenderBridgeParent::RecvAddPipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId,
const CompositableHandle& aHandle)
{
if (mDestroyed) {
return IPC_OK();
}
MOZ_ASSERT(!mExternalImageIds.Get(wr::AsUint64(aImageId)).get());
MOZ_ASSERT(!mAsyncCompositables.Get(wr::AsUint64(aPipelineId)).get());
RefPtr<ImageBridgeParent> imageBridge = ImageBridgeParent::GetInstance(OtherPid());
if (!imageBridge) {
@ -659,11 +630,29 @@ WebRenderBridgeParent::RecvAddExternalImageId(const ExternalImageId& aImageId,
}
wrHost->SetWrBridge(this);
mExternalImageIds.Put(wr::AsUint64(aImageId), wrHost);
mAsyncCompositables.Put(wr::AsUint64(aPipelineId), wrHost);
mCompositableHolder->AddAsyncImagePipeline(aPipelineId, wrHost);
return IPC_OK();
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvRemovePipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId)
{
if (mDestroyed) {
return IPC_OK();
}
MOZ_ASSERT(mAsyncCompositables.Get(wr::AsUint64(aPipelineId)).get());
WebRenderImageHost* wrHost = mAsyncCompositables.Get(wr::AsUint64(aPipelineId)).get();
if (wrHost) {
wrHost->ClearWrBridge();
mCompositableHolder->RemoveAsyncImagePipeline(mApi, aPipelineId);
}
mAsyncCompositables.Remove(wr::AsUint64(aPipelineId));
return IPC_OK();
}
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvAddExternalImageIdForCompositable(const ExternalImageId& aImageId,
const CompositableHandle& aHandle)
@ -822,7 +811,7 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In
const uint32_t maxPendingFrameCount = 2;
if (!mIsSnapshotting &&
if (!mForceRendering &&
wr::RenderThread::Get()->GetPendingFrameCount(mApi->GetId()) > maxPendingFrameCount) {
// Render thread is busy, try next time.
ScheduleComposition();
@ -833,6 +822,9 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In
nsTArray<WrOpacityProperty> opacityArray;
nsTArray<WrTransformProperty> transformArray;
mCompositableHolder->SetCompositionTime(TimeStamp::Now());
mCompositableHolder->ApplyAsyncImages(mApi);
if (gfxPrefs::WebRenderOMTAEnabled()) {
SampleAnimations(opacityArray, transformArray);
@ -851,10 +843,9 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In
mApi->GenerateFrame();
}
// XXX Enable it when async video is supported.
// if (!mCompositableHolder->GetCompositeUntilTime().IsNull()) {
// scheduleComposite = true;
// }
if (!mCompositableHolder->GetCompositeUntilTime().IsNull()) {
scheduleComposite = true;
}
if (scheduleComposite) {
ScheduleComposition();
@ -911,10 +902,6 @@ WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch)
return id;
}
WebRenderBridgeParent::~WebRenderBridgeParent()
{
}
uint64_t
WebRenderBridgeParent::GetLayersId() const
{
@ -938,6 +925,26 @@ WebRenderBridgeParent::ScheduleComposition()
}
}
void
WebRenderBridgeParent::FlushRendering(bool aIsSync)
{
if (mDestroyed) {
return;
}
if (!mCompositorScheduler->NeedsComposite()) {
return;
}
mForceRendering = true;
mCompositorScheduler->CancelCurrentCompositeTask();
mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr);
if (aIsSync) {
mApi->WaitFlushed();
}
mForceRendering = false;
}
void
WebRenderBridgeParent::Pause()
{
@ -988,6 +995,15 @@ WebRenderBridgeParent::ClearResources()
iter.Data()->ClearWrBridge();
}
mExternalImageIds.Clear();
for (auto iter = mAsyncCompositables.Iter(); !iter.Done(); iter.Next()) {
wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
RefPtr<WebRenderImageHost> host = iter.Data();
MOZ_ASSERT(host->GetAsyncRef());
host->ClearWrBridge();
mCompositableHolder->RemoveAsyncImagePipeline(mApi, pipelineId);
}
mAsyncCompositables.Clear();
mCompositableHolder->RemovePipeline(mPipelineId, wr::NewEpoch(mWrEpoch));
if (mWidget) {

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

@ -106,8 +106,10 @@ public:
const WebRenderScrollData& aScrollData) override;
mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
mozilla::ipc::IPCResult RecvAddExternalImageId(const ExternalImageId& aImageId,
mozilla::ipc::IPCResult RecvAddPipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineIds,
const CompositableHandle& aHandle) override;
mozilla::ipc::IPCResult RecvRemovePipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId) override;
mozilla::ipc::IPCResult RecvAddExternalImageIdForCompositable(const ExternalImageId& aImageId,
const CompositableHandle& aHandle) override;
mozilla::ipc::IPCResult RecvRemoveExternalImageId(const ExternalImageId& aImageId) override;
@ -177,6 +179,10 @@ public:
return ++sIdNameSpace;
}
void FlushRendering(bool aIsSync);
void ScheduleComposition();
private:
virtual ~WebRenderBridgeParent();
@ -188,7 +194,6 @@ private:
const WrSize& aContentSize,
const ByteBuffer& dl,
const WrBuiltDisplayListDescriptor& dlDesc);
void ScheduleComposition();
void ClearResources();
uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
bool ShouldParentObserveEpoch();
@ -236,6 +241,7 @@ private:
std::vector<wr::ImageKey> mKeysToDelete;
// XXX How to handle active keys of non-ExternalImages?
nsDataHashtable<nsUint64HashKey, wr::ImageKey> mActiveKeys;
nsDataHashtable<nsUint64HashKey, RefPtr<WebRenderImageHost>> mAsyncCompositables;
nsDataHashtable<nsUint64HashKey, RefPtr<WebRenderImageHost>> mExternalImageIds;
nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
@ -252,7 +258,7 @@ private:
bool mPaused;
bool mDestroyed;
bool mIsSnapshotting;
bool mForceRendering;
// Can only be accessed on the compositor thread.
WebRenderScrollData mScrollData;

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

@ -6,6 +6,7 @@
#include "WebRenderCompositableHolder.h"
#include "CompositableHost.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/WebRenderImageHost.h"
#include "mozilla/layers/WebRenderTextureHost.h"
#include "mozilla/webrender/WebRenderAPI.h"
@ -16,9 +17,18 @@ using namespace gfx;
namespace layers {
WebRenderCompositableHolder::AsyncImagePipelineHolder::AsyncImagePipelineHolder()
: mInitialised(false)
, mIsChanged(false)
, mFilter(WrImageRendering::Auto)
, mMixBlendMode(WrMixBlendMode::Normal)
{}
WebRenderCompositableHolder::WebRenderCompositableHolder(uint32_t aIdNamespace)
: mIdNamespace(aIdNamespace)
, mResourceId(0)
, mAsyncImageEpoch(0)
, mDestroyed(false)
{
MOZ_COUNT_CTOR(WebRenderCompositableHolder);
}
@ -28,9 +38,34 @@ WebRenderCompositableHolder::~WebRenderCompositableHolder()
MOZ_COUNT_DTOR(WebRenderCompositableHolder);
}
void
WebRenderCompositableHolder::Destroy(wr::WebRenderAPI* aApi)
{
DeleteOldAsyncImages(aApi);
mDestroyed = true;
}
bool
WebRenderCompositableHolder::HasKeysToDelete()
{
return !mKeysToDelete.IsEmpty();
}
void
WebRenderCompositableHolder::DeleteOldAsyncImages(wr::WebRenderAPI* aApi)
{
for (wr::ImageKey key : mKeysToDelete) {
aApi->DeleteImage(key);
}
mKeysToDelete.Clear();
}
void
WebRenderCompositableHolder::AddPipeline(const wr::PipelineId& aPipelineId)
{
if (mDestroyed) {
return;
}
uint64_t id = wr::AsUint64(aPipelineId);
MOZ_ASSERT(!mPipelineTexturesHolders.Get(id));
@ -41,6 +76,10 @@ WebRenderCompositableHolder::AddPipeline(const wr::PipelineId& aPipelineId)
void
WebRenderCompositableHolder::RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
{
if (mDestroyed) {
return;
}
PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
MOZ_ASSERT(holder);
if (!holder) {
@ -50,9 +89,313 @@ WebRenderCompositableHolder::RemovePipeline(const wr::PipelineId& aPipelineId, c
holder->mDestroyedEpoch = Some(aEpoch);
}
void
WebRenderCompositableHolder::AddAsyncImagePipeline(const wr::PipelineId& aPipelineId, WebRenderImageHost* aImageHost)
{
if (mDestroyed) {
return;
}
MOZ_ASSERT(aImageHost);
uint64_t id = wr::AsUint64(aPipelineId);
MOZ_ASSERT(!mAsyncImagePipelineHolders.Get(id));
AsyncImagePipelineHolder* holder = new AsyncImagePipelineHolder();
holder->mImageHost = aImageHost;
mAsyncImagePipelineHolders.Put(id, holder);
AddPipeline(aPipelineId);
}
void
WebRenderCompositableHolder::RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId)
{
if (mDestroyed) {
return;
}
uint64_t id = wr::AsUint64(aPipelineId);
AsyncImagePipelineHolder* holder = mAsyncImagePipelineHolders.Get(id);
if (!holder) {
return;
}
++mAsyncImageEpoch; // Update webrender epoch
aApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
for (wr::ImageKey key : holder->mKeys) {
aApi->DeleteImage(key);
}
mAsyncImagePipelineHolders.Remove(id);
RemovePipeline(aPipelineId, wr::NewEpoch(mAsyncImageEpoch));
}
void
WebRenderCompositableHolder::UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
const LayerRect& aScBounds,
const gfx::Matrix4x4& aScTransform,
const gfx::MaybeIntSize& aScaleToSize,
const MaybeLayerRect& aClipRect,
const MaybeImageMask& aMask,
const WrImageRendering& aFilter,
const WrMixBlendMode& aMixBlendMode)
{
if (mDestroyed) {
return;
}
AsyncImagePipelineHolder* holder = mAsyncImagePipelineHolders.Get(wr::AsUint64(aPipelineId));
MOZ_ASSERT(holder);
if (!holder) {
return;
}
holder->mInitialised = true;
holder->mIsChanged = true;
holder->mScBounds = aScBounds;
holder->mScTransform = aScTransform;
holder->mScaleToSize = aScaleToSize;
holder->mClipRect = aClipRect;
holder->mMask = aMask;
holder->mFilter = aFilter;
holder->mMixBlendMode = aMixBlendMode;
}
void
WebRenderCompositableHolder::GetImageKeys(nsTArray<wr::ImageKey>& aKeys, size_t aChannelNumber)
{
MOZ_ASSERT(aChannelNumber > 0);
for (size_t i = 0; i < aChannelNumber; ++i) {
wr::ImageKey key = GetImageKey();
aKeys.AppendElement(key);
}
}
void
WebRenderCompositableHolder::GetImageKeysForExternalImage(nsTArray<wr::ImageKey>& aKeys)
{
MOZ_ASSERT(aKeys.IsEmpty());
// XXX (Jerry): Remove the hardcode image format setting.
#if defined(XP_WIN)
// Use libyuv to convert the buffer to rgba format. So, use 1 image key here.
GetImageKeys(aKeys, 1);
#elif defined(XP_MACOSX)
if (gfxVars::CanUseHardwareVideoDecoding()) {
// Use the hardware MacIOSurface with YCbCr interleaved format. It uses 1
// image key.
GetImageKeys(aKeys, 1);
} else {
// Use libyuv.
GetImageKeys(aKeys, 1);
}
#elif defined(MOZ_WIDGET_GTK)
// Use libyuv.
GetImageKeys(aKeys, 1);
#elif defined(ANDROID)
// Use libyuv.
GetImageKeys(aKeys, 1);
#endif
MOZ_ASSERT(!aKeys.IsEmpty());
}
bool
WebRenderCompositableHolder::GetImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys)
{
MOZ_ASSERT(aKeys.IsEmpty());
MOZ_ASSERT(aTexture);
WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
if (wrTexture) {
GetImageKeysForExternalImage(aKeys);
MOZ_ASSERT(!aKeys.IsEmpty());
Range<const wr::ImageKey> keys(&aKeys[0], aKeys.Length());
wrTexture->AddWRImage(aApi, keys, wrTexture->GetExternalImageKey());
return true;
} else {
RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface();
if (!dSurf) {
NS_ERROR("TextureHost does not return DataSourceSurface");
return false;
}
DataSourceSurface::MappedSurface map;
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
NS_ERROR("DataSourceSurface failed to map");
return false;
}
IntSize size = dSurf->GetSize();
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
wr::ImageKey key = GetImageKey();
aKeys.AppendElement(key);
aApi->AddImage(key, descriptor, slice);
dSurf->Unmap();
}
return false;
}
void
WebRenderCompositableHolder::PushExternalImage(wr::DisplayListBuilder& aBuilder,
const WrRect& aBounds,
const WrClipRegionToken aClip,
wr::ImageRendering aFilter,
nsTArray<wr::ImageKey>& aKeys)
{
// XXX (Jerry): Remove the hardcode image format setting. The format of
// textureClient could change from time to time. So, we just set the most
// usable format here.
#if defined(XP_WIN)
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(aKeys.Length() == 1);
aBuilder.PushImage(aBounds, aClip, aFilter, aKeys[0]);
#elif defined(XP_MACOSX)
if (gfx::gfxVars::CanUseHardwareVideoDecoding()) {
// Use the hardware MacIOSurface with YCbCr interleaved format.
MOZ_ASSERT(aKeys.Length() == 1);
aBuilder.PushYCbCrInterleavedImage(aBounds, aClip, aKeys[0], WrYuvColorSpace::Rec601, aFilter);
} else {
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(aKeys.Length() == 1);
aBuilder.PushImage(aBounds, aClip, aFilter, aKeys[0]);
}
#elif defined(MOZ_WIDGET_GTK)
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(aKeys.Length() == 1);
aBuilder.PushImage(aBounds, aClip, aFilter, aKeys[0]);
#elif defined(ANDROID)
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(aKeys.Length() == 1);
aBuilder.PushImage(aBounds, aClip, aFilter, aKeys[0]);
#endif
}
bool
WebRenderCompositableHolder::UpdateImageKeys(wr::WebRenderAPI* aApi,
bool& aUseExternalImage,
AsyncImagePipelineHolder* aHolder,
nsTArray<wr::ImageKey>& aKeys,
nsTArray<wr::ImageKey>& aKeysToDelete)
{
MOZ_ASSERT(aKeys.IsEmpty());
MOZ_ASSERT(aHolder);
TextureHost* texture = aHolder->mImageHost->GetAsTextureHostForComposite();
if (!aHolder->mInitialised) {
return false;
}
// No change
if (!aHolder->mIsChanged && texture == aHolder->mCurrentTexture) {
// No need to update DisplayList.
return false;
}
aHolder->mIsChanged = false;
if (texture == aHolder->mCurrentTexture) {
// Reuse previous ImageKeys.
aKeys.AppendElements(aHolder->mKeys);
return true;
}
// Delete old ImageKeys
aKeysToDelete.AppendElements(aHolder->mKeys);
aHolder->mKeys.Clear();
aHolder->mCurrentTexture = nullptr;
// No txture to render
if (!texture) {
return true;
}
aUseExternalImage = GetImageKeyForTextureHost(aApi, texture, aKeys);
MOZ_ASSERT(!aKeys.IsEmpty());
aHolder->mKeys.AppendElements(aKeys);
aHolder->mCurrentTexture = texture;
return true;
}
void
WebRenderCompositableHolder::ApplyAsyncImages(wr::WebRenderAPI* aApi)
{
if (mDestroyed || mAsyncImagePipelineHolders.Count() == 0) {
return;
}
++mAsyncImageEpoch; // Update webrender epoch
wr::Epoch epoch = wr::NewEpoch(mAsyncImageEpoch);
nsTArray<wr::ImageKey> keysToDelete;
for (auto iter = mAsyncImagePipelineHolders.Iter(); !iter.Done(); iter.Next()) {
wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
AsyncImagePipelineHolder* holder = iter.Data();
nsTArray<wr::ImageKey> keys;
bool useExternalImage = false;
bool updateDisplayList = UpdateImageKeys(aApi,
useExternalImage,
holder,
keys,
keysToDelete);
if (!updateDisplayList) {
continue;
}
WrSize contentSize { holder->mScBounds.width, holder->mScBounds.height };
wr::DisplayListBuilder builder(pipelineId, contentSize);
if (!keys.IsEmpty()) {
MOZ_ASSERT(holder->mCurrentTexture.get());
float opacity = 1.0f;
builder.PushStackingContext(wr::ToWrRect(holder->mScBounds),
0,
&opacity,
holder->mScTransform.IsIdentity() ? nullptr : &holder->mScTransform,
holder->mMixBlendMode);
LayerRect rect(0, 0, holder->mCurrentTexture->GetSize().width, holder->mCurrentTexture->GetSize().height);
if (holder->mScaleToSize.isSome()) {
rect = LayerRect(0, 0, holder->mScaleToSize.value().width, holder->mScaleToSize.value().height);
}
LayerRect clipRect = holder->mClipRect.valueOr(rect);
WrClipRegionToken clip = builder.PushClipRegion(
wr::ToWrRect(clipRect),
holder->mMask.ptrOr(nullptr));
if (useExternalImage) {
MOZ_ASSERT(holder->mCurrentTexture->AsWebRenderTextureHost());
PushExternalImage(builder,
wr::ToWrRect(rect),
clip,
holder->mFilter,
keys);
HoldExternalImage(pipelineId, epoch, holder->mCurrentTexture->AsWebRenderTextureHost());
} else {
MOZ_ASSERT(keys.Length() == 1);
builder.PushImage(wr::ToWrRect(rect),
clip,
holder->mFilter,
keys[0]);
}
builder.PopStackingContext();
}
wr::BuiltDisplayList dl;
WrSize builderContentSize;
builder.Finalize(builderContentSize, dl);
aApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(holder->mScBounds.width, holder->mScBounds.height),
pipelineId, builderContentSize,
dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length);
}
DeleteOldAsyncImages(aApi);
mKeysToDelete.SwapElements(keysToDelete);
}
void
WebRenderCompositableHolder::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
{
if (mDestroyed) {
return;
}
MOZ_ASSERT(aTexture);
PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
@ -67,6 +410,9 @@ WebRenderCompositableHolder::HoldExternalImage(const wr::PipelineId& aPipelineId
void
WebRenderCompositableHolder::Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
{
if (mDestroyed) {
return;
}
PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
if (!holder) {
return;
@ -74,6 +420,7 @@ WebRenderCompositableHolder::Update(const wr::PipelineId& aPipelineId, const wr:
// Remove Pipeline
if (holder->mDestroyedEpoch.isSome() && holder->mDestroyedEpoch.ref() <= aEpoch) {
mPipelineTexturesHolders.Remove(wr::AsUint64(aPipelineId));
return;
}

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

@ -8,6 +8,7 @@
#include <queue>
#include "mozilla/gfx/Point.h"
#include "mozilla/layers/TextureHost.h"
#include "mozilla/Maybe.h"
#include "mozilla/webrender/WebRenderTypes.h"
@ -16,12 +17,15 @@
namespace mozilla {
namespace wr {
class DisplayListBuilder;
class WebRenderAPI;
}
namespace layers {
class CompositableHost;
class CompositorVsyncScheduler;
class WebRenderImageHost;
class WebRenderTextureHost;
class WebRenderCompositableHolder final
@ -35,8 +39,12 @@ protected:
~WebRenderCompositableHolder();
public:
void Destroy(wr::WebRenderAPI* aApi);
bool HasKeysToDelete();
void AddPipeline(const wr::PipelineId& aPipelineId);
void RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
void Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
@ -60,6 +68,22 @@ public:
return mCompositeUntilTime;
}
void AddAsyncImagePipeline(const wr::PipelineId& aPipelineId, WebRenderImageHost* aImageHost);
void RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId);
void UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
const LayerRect& aScBounds,
const gfx::Matrix4x4& aScTransform,
const gfx::MaybeIntSize& aScaleToSize,
const MaybeLayerRect& aClipRect,
const MaybeImageMask& aMask,
const WrImageRendering& aFilter,
const WrMixBlendMode& aMixBlendMode);
void ApplyAsyncImages(wr::WebRenderAPI* aApi);
private:
void DeleteOldAsyncImages(wr::WebRenderAPI* aApi);
uint32_t GetNextResourceId() { return ++mResourceId; }
uint32_t GetNamespace() { return mIdNamespace; }
wr::ImageKey GetImageKey()
@ -69,8 +93,14 @@ public:
key.mHandle = GetNextResourceId();
return key;
}
private:
void GetImageKeys(nsTArray<wr::ImageKey>& aKeys, size_t aChannelNumber);
void GetImageKeysForExternalImage(nsTArray<wr::ImageKey>& aKeys);
bool GetImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys);
void PushExternalImage(wr::DisplayListBuilder& aBuilder,
const WrRect& aBounds,
const WrClipRegionToken aClip,
wr::ImageRendering aFilter,
nsTArray<wr::ImageKey>& aKeys);
struct ForwardingTextureHost {
ForwardingTextureHost(const wr::Epoch& aEpoch, TextureHost* aTexture)
@ -87,9 +117,37 @@ private:
Maybe<wr::Epoch> mDestroyedEpoch;
};
struct AsyncImagePipelineHolder {
AsyncImagePipelineHolder();
bool mInitialised;
bool mIsChanged;
LayerRect mScBounds;
gfx::Matrix4x4 mScTransform;
gfx::MaybeIntSize mScaleToSize;
MaybeLayerRect mClipRect;
MaybeImageMask mMask;
WrImageRendering mFilter;
WrMixBlendMode mMixBlendMode;
RefPtr<WebRenderImageHost> mImageHost;
CompositableTextureHostRef mCurrentTexture;
nsTArray<wr::ImageKey> mKeys;
};
bool UpdateImageKeys(wr::WebRenderAPI* aApi,
bool& aUseExternalImage,
AsyncImagePipelineHolder* aHolder,
nsTArray<wr::ImageKey>& aKeys,
nsTArray<wr::ImageKey>& aKeysToDelete);
uint32_t mIdNamespace;
uint32_t mResourceId;
nsClassHashtable<nsUint64HashKey, PipelineTexturesHolder> mPipelineTexturesHolders;
nsClassHashtable<nsUint64HashKey, AsyncImagePipelineHolder> mAsyncImagePipelineHolders;
uint32_t mAsyncImageEpoch;
nsTArray<wr::ImageKey> mKeysToDelete;
bool mDestroyed;
// Render time for the current composition.
TimeStamp mCompositionTime;

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

@ -68,6 +68,10 @@ WebRenderImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
mImages.SwapElements(newImages);
newImages.Clear();
if (mWrBridge && GetAsyncRef()) {
mWrBridge->ScheduleComposition();
}
// Video producers generally send replacement images with the same frameID but
// slightly different timestamps in order to sync with the audio clock. This
// means that any CompositeUntil() call we made in Composite() may no longer

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

@ -73,6 +73,8 @@ public:
void ClearWrBridge();
TextureHost* GetCurrentTextureHost() { return mCurrentTextureHost; }
protected:
// ImageComposite
virtual TimeStamp GetCompositionTime() const override;

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

@ -33,9 +33,6 @@ WebRenderImageLayer::~WebRenderImageLayer()
{
MOZ_COUNT_DTOR(WebRenderImageLayer);
for (auto key : mVideoKeys) {
WrManager()->AddImageKeyForDiscard(key);
}
if (mKey.isSome()) {
WrManager()->AddImageKeyForDiscard(mKey.value());
}
@ -43,6 +40,9 @@ WebRenderImageLayer::~WebRenderImageLayer()
if (mExternalImageId.isSome()) {
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
}
if (mPipelineId.isSome()) {
WrBridge()->RemovePipelineIdForAsyncCompositable(mPipelineId.ref());
}
}
CompositableType
@ -90,17 +90,6 @@ WebRenderImageLayer::ClearCachedResources()
}
}
void
WebRenderImageLayer::AddWRVideoImage(size_t aChannelNumber)
{
for (size_t i = 0; i < aChannelNumber; ++i) {
WrImageKey key = GetImageKey();
WrManager()->AddImageKeyForDiscard(key);
mVideoKeys.AppendElement(key);
}
WrBridge()->AddWebRenderParentCommand(OpAddExternalVideoImage(mExternalImageId.value(), mVideoKeys));
}
void
WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc)
@ -126,31 +115,83 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
mImageClient->Connect();
}
if (mExternalImageId.isNothing()) {
if (GetImageClientType() == CompositableType::IMAGE_BRIDGE) {
if (GetImageClientType() == CompositableType::IMAGE_BRIDGE && mPipelineId.isNothing()) {
MOZ_ASSERT(!mImageClient);
mExternalImageId = Some(WrBridge()->AllocExternalImageId(mContainer->GetAsyncContainerHandle()));
// Alloc async image pipeline id.
mPipelineId = Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
} else {
// Handle CompositableType::IMAGE case
WrBridge()->AddPipelineIdForAsyncCompositable(mPipelineId.ref(),
mContainer->GetAsyncContainerHandle());
} else if (GetImageClientType() == CompositableType::IMAGE && mExternalImageId.isNothing()) {
MOZ_ASSERT(mImageClient);
mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
}
}
MOZ_ASSERT(mExternalImageId.isSome());
}
if (GetImageClientType() == CompositableType::IMAGE_BRIDGE) {
MOZ_ASSERT(!mImageClient);
MOZ_ASSERT(mExternalImageId.isNothing());
// Push IFrame for async image pipeline.
ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
// As with WebRenderTextLayer, because we don't push a stacking context for
// this async image pipeline, WR doesn't know about the transform on this layer.
// Therefore we need to apply that transform to the bounds before we pass it on to WR.
// The conversion from ParentLayerPixel to LayerPixel below is a result of
// changing the reference layer from "this layer" to the "the layer that
// created aSc".
LayerRect rect = ViewAs<LayerPixel>(bounds,
PixelCastJustification::MovingDownToChildren);
DumpLayerInfo("Image Layer async", rect);
// XXX Remove IFrame for async image pipeline when partial display list update is supported.
WrClipRegionToken clipRegion = aBuilder.PushClipRegion(aSc.ToRelativeWrRect(rect));
aBuilder.PushIFrame(aSc.ToRelativeWrRect(rect), clipRegion, mPipelineId.ref());
// Prepare data that are necessary for async image pipelin.
// They are used within WebRenderCompositableHolder
gfx::Matrix4x4 scTransform = GetTransform();
// Translate is applied as part of PushIFrame()
scTransform.PostTranslate(-rect.x, -rect.y, 0);
// Adjust transform as to apply origin
LayerPoint scOrigin = Bounds().TopLeft();
scTransform.PreTranslate(-scOrigin.x, -scOrigin.y, 0);
MaybeIntSize scaleToSize;
if (mScaleMode != ScaleMode::SCALE_NONE) {
NS_ASSERTION(mScaleMode == ScaleMode::STRETCH,
"No other scalemodes than stretch and none supported yet.");
scaleToSize = Some(mScaleToSize);
}
LayerRect scBounds = BoundsForStackingContext();
wr::ImageRendering filter = wr::ToImageRendering(mSamplingFilter);
wr::MixBlendMode mixBlendMode = wr::ToWrMixBlendMode(GetMixBlendMode());
StackingContextHelper sc(aSc, aBuilder, this);
Maybe<WrImageMask> mask = BuildWrMaskLayer(&sc);
WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(mPipelineId.value(),
scBounds,
scTransform,
scaleToSize,
ClipRect(),
mask,
filter,
mixBlendMode));
return;
}
MOZ_ASSERT(GetImageClientType() == CompositableType::IMAGE);
MOZ_ASSERT(mImageClient->AsImageClientSingle());
// XXX Not good for async ImageContainer case.
AutoLockImage autoLock(mContainer);
Image* image = autoLock.GetImage();
if (!image) {
return;
}
gfx::IntSize size = image->GetSize();
if (GetImageClientType() != CompositableType::IMAGE_BRIDGE) {
// Handle CompositableType::IMAGE case
MOZ_ASSERT(mImageClient->AsImageClientSingle());
mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
mContainer,
mKey,
@ -158,31 +199,6 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
if (mKey.isNothing()) {
return;
}
} else {
// Always allocate key.
mVideoKeys.Clear();
// XXX (Jerry): Remove the hardcode image format setting.
#if defined(XP_WIN)
// Use libyuv to convert the buffer to rgba format. So, use 1 image key here.
AddWRVideoImage(1);
#elif defined(XP_MACOSX)
if (gfx::gfxVars::CanUseHardwareVideoDecoding()) {
// Use the hardware MacIOSurface with YCbCr interleaved format. It uses 1
// image key.
AddWRVideoImage(1);
} else {
// Use libyuv.
AddWRVideoImage(1);
}
#elif defined(MOZ_WIDGET_GTK)
// Use libyuv.
AddWRVideoImage(1);
#elif defined(ANDROID)
// Use libyuv.
AddWRVideoImage(1);
#endif
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
StackingContextHelper sc(aSc, aBuilder, this);
@ -208,37 +224,7 @@ WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
GetLayer(),
Stringify(filter).c_str());
}
if (GetImageClientType() != CompositableType::IMAGE_BRIDGE) {
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mKey.value());
} else {
// XXX (Jerry): Remove the hardcode image format setting. The format of
// textureClient could change from time to time. So, we just set the most
// usable format here.
#if defined(XP_WIN)
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(mVideoKeys.Length() == 1);
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
#elif defined(XP_MACOSX)
if (gfx::gfxVars::CanUseHardwareVideoDecoding()) {
// Use the hardware MacIOSurface with YCbCr interleaved format.
MOZ_ASSERT(mVideoKeys.Length() == 1);
aBuilder.PushYCbCrInterleavedImage(sc.ToRelativeWrRect(rect), clip, mVideoKeys[0], WrYuvColorSpace::Rec601, filter);
} else {
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(mVideoKeys.Length() == 1);
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
}
#elif defined(MOZ_WIDGET_GTK)
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(mVideoKeys.Length() == 1);
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
#elif defined(ANDROID)
// Use libyuv to convert the buffer to rgba format.
MOZ_ASSERT(mVideoKeys.Length() == 1);
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mVideoKeys[0]);
#endif
}
}
Maybe<WrImageMask>

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

@ -39,9 +39,6 @@ protected:
void AddWRVideoImage(size_t aChannelNumber);
wr::MaybeExternalImageId mExternalImageId;
// Some video image format contains multiple channel data.
nsTArray<wr::ImageKey> mVideoKeys;
// The regular single channel image.
Maybe<wr::ImageKey> mKey;
RefPtr<ImageClient> mImageClient;
CompositableType mImageClientTypeContainer;

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

@ -464,9 +464,16 @@ WebRenderLayerManager::RemoveDidCompositeObserver(DidCompositeObserver* aObserve
void
WebRenderLayerManager::FlushRendering()
{
CompositorBridgeChild* bridge = GetCompositorBridgeChild();
if (bridge) {
bridge->SendFlushRendering();
CompositorBridgeChild* cBridge = GetCompositorBridgeChild();
if (!cBridge) {
return;
}
MOZ_ASSERT(mWidget);
if (mWidget->SynchronouslyRepaintOnResize() || gfxPrefs::LayersForceSynchronousResize()) {
cBridge->SendFlushRendering();
} else {
cBridge->SendFlushRenderingAsync();
}
}

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

@ -172,6 +172,44 @@ struct ParamTraits<WrPoint>
}
};
template<>
struct ParamTraits<WrImageMask>
{
static void
Write(Message* aMsg, const WrImageMask& aParam)
{
WriteParam(aMsg, aParam.image);
WriteParam(aMsg, aParam.rect);
WriteParam(aMsg, aParam.repeat);
}
static bool
Read(const Message* aMsg, PickleIterator* aIter, WrImageMask* aResult)
{
return ReadParam(aMsg, aIter, &aResult->image)
&& ReadParam(aMsg, aIter, &aResult->rect)
&& ReadParam(aMsg, aIter, &aResult->repeat);
}
};
template<>
struct ParamTraits<WrImageRendering>
: public ContiguousEnumSerializer<
WrImageRendering,
WrImageRendering::Auto,
WrImageRendering::Sentinel>
{
};
template<>
struct ParamTraits<WrMixBlendMode>
: public ContiguousEnumSerializer<
WrMixBlendMode,
WrMixBlendMode::Normal,
WrMixBlendMode::Sentinel>
{
};
template<>
struct ParamTraits<WrBuiltDisplayListDescriptor>
{

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

@ -502,7 +502,7 @@ private:
DECL_OVERRIDE_PREF(Live, "layers.advanced.button-foreground-layers", LayersAllowButtonForegroundLayers, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.canvas-background-color", LayersAllowCanvasBackgroundColorLayers, gfxPrefs::OverrideBase_WebRendest());
DECL_OVERRIDE_PREF(Live, "layers.advanced.caret-layers", LayersAllowCaretLayers, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.columnRule-layers", LayersAllowColumnRuleLayers, gfxPrefs::OverrideBase_WebRendest());
DECL_OVERRIDE_PREF(Live, "layers.advanced.columnRule-layers", LayersAllowColumnRuleLayers, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.displaybuttonborder-layers", LayersAllowDisplayButtonBorder, gfxPrefs::OverrideBase_WebRender());
DECL_OVERRIDE_PREF(Live, "layers.advanced.image-layers", LayersAllowImageLayers, gfxPrefs::OverrideBase_WebRendest());
DECL_OVERRIDE_PREF(Live, "layers.advanced.outline-layers", LayersAllowOutlineLayers, gfxPrefs::OverrideBase_WebRender());

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

@ -23,6 +23,7 @@ class CompositorWidget;
namespace layers {
class CompositorBridgeParentBase;
class WebRenderBridgeParent;
}
namespace wr {
@ -125,6 +126,7 @@ protected:
bool mUseANGLE;
friend class DisplayListBuilder;
friend class layers::WebRenderBridgeParent;
};
/// This is a simple C++ wrapper around WrState defined in the rust bindings.

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

@ -1172,7 +1172,7 @@ pub struct WrState {
#[no_mangle]
pub extern "C" fn wr_state_new(pipeline_id: WrPipelineId,
content_size: WrSize) -> *mut WrState {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
let state = Box::new(WrState {
pipeline_id: pipeline_id,
@ -1186,7 +1186,7 @@ pub extern "C" fn wr_state_new(pipeline_id: WrPipelineId,
/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
#[no_mangle]
pub extern "C" fn wr_state_delete(state: *mut WrState) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
unsafe {
Box::from_raw(state);
@ -1197,7 +1197,7 @@ pub extern "C" fn wr_state_delete(state: *mut WrState) {
pub extern "C" fn wr_dp_begin(state: &mut WrState,
width: u32,
height: u32) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
state.frame_builder.dl_builder.data.clear();
let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0),
@ -1216,7 +1216,7 @@ pub extern "C" fn wr_dp_begin(state: &mut WrState,
#[no_mangle]
pub extern "C" fn wr_dp_end(state: &mut WrState) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
state.frame_builder.dl_builder.pop_stacking_context();
}
@ -1227,7 +1227,7 @@ pub extern "C" fn wr_dp_push_clip_region(state: &mut WrState,
complex_count: usize,
image_mask: *const WrImageMask)
-> WrClipRegionToken {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
let main = main.into();
let complex_slice = make_slice(complex, complex_count);
@ -1246,7 +1246,7 @@ pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
opacity: *const f32,
transform: *const WrMatrix,
mix_blend_mode: WrMixBlendMode) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
let bounds = bounds.into();
@ -1282,7 +1282,7 @@ pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
#[no_mangle]
pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
state.frame_builder.dl_builder.pop_stacking_context();
}
@ -1299,7 +1299,7 @@ pub extern "C" fn wr_dp_push_clip(state: &mut WrState,
#[no_mangle]
pub extern "C" fn wr_dp_pop_clip(state: &mut WrState) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
state.frame_builder.dl_builder.pop_clip_node();
}
@ -1353,7 +1353,7 @@ pub extern "C" fn wr_dp_push_rect(state: &mut WrState,
rect: WrRect,
clip: WrClipRegionToken,
color: WrColor) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
state.frame_builder.dl_builder.push_rect(rect.into(), clip.into(), color.into());
}
@ -1366,7 +1366,7 @@ pub extern "C" fn wr_dp_push_image(state: &mut WrState,
tile_spacing: WrSize,
image_rendering: WrImageRendering,
key: WrImageKey) {
assert!(unsafe { is_in_main_thread() });
assert!(unsafe { !is_in_render_thread() });
state.frame_builder
.dl_builder

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

@ -507,8 +507,7 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
// Step 15.
RootedValue tag(cx);
RootedId toStringTagId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
if (!GetProperty(cx, obj, obj, toStringTagId, &tag))
if (!GetInterestingSymbolProperty(cx, obj, cx->wellKnownSymbols().toStringTag, &tag))
return false;
// Step 16.

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

@ -1,4 +1,4 @@
// |jit-test| error:overflow
// |jit-test| error:overflow; allow-oom
if (getBuildConfiguration().debug === true)
throw "overflow";
function f(){};

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

@ -3200,9 +3200,8 @@ js::ToPrimitiveSlow(JSContext* cx, JSType preferredType, MutableHandleValue vp)
RootedObject obj(cx, &vp.toObject());
// Steps 4-5.
RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toPrimitive));
RootedValue method(cx);
if (!GetProperty(cx, obj, obj, id, &method))
if (!GetInterestingSymbolProperty(cx, obj, cx->wellKnownSymbols().toPrimitive, &method))
return false;
// Step 6.
@ -3564,6 +3563,7 @@ JSObject::dump(FILE* fp) const
if (obj->isDelegate()) fprintf(fp, " delegate");
if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) fprintf(fp, " not_extensible");
if (obj->isIndexed()) fprintf(fp, " indexed");
if (obj->maybeHasInterestingSymbolProperty()) fprintf(fp, " maybe_has_interesting_symbol");
if (obj->isBoundFunction()) fprintf(fp, " bound_function");
if (obj->isQualifiedVarObj()) fprintf(fp, " varobj");
if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj");

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

@ -274,6 +274,13 @@ class JSObject : public js::gc::Cell
*/
inline bool isIndexed() const;
/*
* Whether there may be "interesting symbol" properties on this object. An
* interesting symbol is a symbol for which symbol->isInterestingSymbol()
* returns true.
*/
MOZ_ALWAYS_INLINE bool maybeHasInterestingSymbolProperty() const;
/*
* If this object was instantiated with `new Ctor`, return the constructor's
* display atom. Otherwise, return nullptr.
@ -897,6 +904,18 @@ GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t ind
inline bool
GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp);
// Returns whether |obj| or an object on its proto chain may have an interesting
// symbol property (see JSObject::hasInterestingSymbolProperty). If it returns
// true, *holder is set to the object that may have this property.
MOZ_ALWAYS_INLINE bool
MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, Symbol* symbol,
JSObject** holder = nullptr);
// Like GetProperty but optimized for interesting symbol properties like
// @@toStringTag.
MOZ_ALWAYS_INLINE bool
GetInterestingSymbolProperty(JSContext* cx, HandleObject obj, Symbol* sym, MutableHandleValue vp);
/*
* ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
*

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

@ -45,6 +45,28 @@ MaybeConvertUnboxedObjectToNative(JSContext* cx, JSObject* obj)
return true;
}
static MOZ_ALWAYS_INLINE bool
ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
{
MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp);
if (!clasp->getResolve()) {
// Sanity check: we should only have a mayResolve hook if we have a
// resolve hook.
MOZ_ASSERT(!clasp->getMayResolve(), "Class with mayResolve hook but no resolve hook");
return false;
}
if (JSMayResolveOp mayResolve = clasp->getMayResolve()) {
// Tell the analysis our mayResolve hooks won't trigger GC.
JS::AutoSuppressGCAnalysis nogc;
if (!mayResolve(names, id, maybeObj))
return false;
}
return true;
}
} // namespace js
inline js::Shape*
@ -242,6 +264,50 @@ js::DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResul
return DeleteProperty(cx, obj, id, result);
}
MOZ_ALWAYS_INLINE bool
js::MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, Symbol* symbol,
JSObject** holder)
{
MOZ_ASSERT(symbol->isInterestingSymbol());
jsid id = SYMBOL_TO_JSID(symbol);
do {
if (obj->maybeHasInterestingSymbolProperty() ||
obj->hasDynamicPrototype() ||
MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj) ||
obj->getClass()->getGetProperty()))
{
if (holder)
*holder = obj;
return true;
}
obj = obj->staticPrototype();
} while (obj);
return false;
}
MOZ_ALWAYS_INLINE bool
js::GetInterestingSymbolProperty(JSContext* cx, HandleObject obj, Symbol* sym, MutableHandleValue vp)
{
JSObject* holder;
if (!MaybeHasInterestingSymbolProperty(cx, obj, sym, &holder)) {
#ifdef DEBUG
RootedValue receiver(cx, ObjectValue(*obj));
RootedId id(cx, SYMBOL_TO_JSID(sym));
if (!GetProperty(cx, obj, receiver, id, vp))
return false;
MOZ_ASSERT(vp.isUndefined());
#endif
vp.setUndefined();
return true;
}
RootedObject holderRoot(cx, holder);
RootedValue receiver(cx, ObjectValue(*obj));
RootedId id(cx, SYMBOL_TO_JSID(sym));
return GetProperty(cx, holderRoot, receiver, id, vp);
}
/* * */
@ -411,6 +477,23 @@ JSObject::isIndexed() const
return hasAllFlags(js::BaseShape::INDEXED);
}
MOZ_ALWAYS_INLINE bool
JSObject::maybeHasInterestingSymbolProperty() const
{
const js::NativeObject* nobj;
if (isNative()) {
nobj = &as<js::NativeObject>();
} else if (is<js::UnboxedPlainObject>()) {
nobj = as<js::UnboxedPlainObject>().maybeExpando();
if (!nobj)
return false;
} else {
return true;
}
return nobj->hasAllFlags(js::BaseShape::HAS_INTERESTING_SYMBOL);
}
inline bool
JSObject::staticPrototypeIsImmutable() const
{

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

@ -672,28 +672,6 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id,
return true;
}
static MOZ_ALWAYS_INLINE bool
ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
{
MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp);
if (!clasp->getResolve()) {
// Sanity check: we should only have a mayResolve hook if we have a
// resolve hook.
MOZ_ASSERT(!clasp->getMayResolve(), "Class with mayResolve hook but no resolve hook");
return false;
}
if (JSMayResolveOp mayResolve = clasp->getMayResolve()) {
// Tell the analysis our mayResolve hooks won't trigger GC.
JS::AutoSuppressGCAnalysis nogc;
if (!mayResolve(names, id, maybeObj))
return false;
}
return true;
}
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
LookupOwnPropertyInline(JSContext* cx,

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

@ -445,6 +445,24 @@ ShouldConvertToDictionary(NativeObject* obj)
return obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT;
}
static MOZ_ALWAYS_INLINE UnownedBaseShape*
GetBaseShapeForNewShape(JSContext* cx, HandleShape last, HandleId id)
{
uint32_t index;
bool indexed = IdIsIndex(id, &index);
bool interestingSymbol = JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id)->isInterestingSymbol();
if (MOZ_LIKELY(!indexed && !interestingSymbol))
return last->base()->unowned();
StackBaseShape base(last->base());
if (indexed)
base.flags |= BaseShape::INDEXED;
else if (interestingSymbol)
base.flags |= BaseShape::HAS_INTERESTING_SYMBOL;
return BaseShape::getUnowned(cx, base);
}
/* static */ Shape*
NativeObject::addPropertyInternal(JSContext* cx,
HandleNativeObject obj, HandleId id,
@ -497,20 +515,9 @@ NativeObject::addPropertyInternal(JSContext* cx,
RootedShape shape(cx);
{
RootedShape last(cx, obj->lastProperty());
uint32_t index;
bool indexed = IdIsIndex(id, &index);
Rooted<UnownedBaseShape*> nbase(cx);
if (!indexed) {
nbase = last->base()->unowned();
} else {
StackBaseShape base(last->base());
base.flags |= BaseShape::INDEXED;
nbase = BaseShape::getUnowned(cx, base);
Rooted<UnownedBaseShape*> nbase(cx, GetBaseShapeForNewShape(cx, last, id));
if (!nbase)
return nullptr;
}
Rooted<StackShape> child(cx, StackShape(nbase, id, slot, attrs, flags));
child.updateGetterSetter(getter, setter);
@ -569,17 +576,9 @@ js::ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto,
for (unsigned i = 0; i < ids.length(); i++) {
id = ids[i];
uint32_t index;
bool indexed = IdIsIndex(id, &index);
Rooted<UnownedBaseShape*> nbase(cx, newShape->base()->unowned());
if (indexed) {
StackBaseShape base(nbase);
base.flags |= BaseShape::INDEXED;
nbase = BaseShape::getUnowned(cx, base);
Rooted<UnownedBaseShape*> nbase(cx, GetBaseShapeForNewShape(cx, newShape, id));
if (!nbase)
return nullptr;
}
Rooted<StackShape> child(cx, StackShape(nbase, id, i, JSPROP_ENUMERATE, 0));
newShape = cx->zone()->propertyTree().getChild(cx, newShape, child);
@ -684,12 +683,8 @@ NativeObject::putProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
Rooted<UnownedBaseShape*> nbase(cx);
{
uint32_t index;
bool indexed = IdIsIndex(id, &index);
StackBaseShape base(obj->lastProperty()->base());
if (indexed)
base.flags |= BaseShape::INDEXED;
nbase = BaseShape::getUnowned(cx, base);
RootedShape shape(cx, obj->lastProperty());
nbase = GetBaseShapeForNewShape(cx, shape, id);
if (!nbase)
return nullptr;
}

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

@ -389,7 +389,7 @@ class BaseShape : public gc::TenuredCell
DELEGATE = 0x8,
NOT_EXTENSIBLE = 0x10,
INDEXED = 0x20,
/* (0x40 is unused) */
HAS_INTERESTING_SYMBOL = 0x40,
HAD_ELEMENTS_ACCESS = 0x80,
WATCHED = 0x100,
ITERATED_SINGLETON = 0x200,

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

@ -68,6 +68,15 @@ class Symbol : public js::gc::TenuredCell
bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }
// An "interesting symbol" is a well-known symbol, like @@toStringTag,
// that's often looked up on random objects but is usually not present. We
// optimize this by setting a flag on the object's BaseShape when such
// symbol properties are added, so we can optimize lookups on objects that
// don't have the BaseShape flag.
bool isInterestingSymbol() const {
return code_ == SymbolCode::toStringTag || code_ == SymbolCode::toPrimitive;
}
static const JS::TraceKind TraceKind = JS::TraceKind::Symbol;
inline void traceChildren(JSTracer* trc) {
if (description_)

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

@ -10,7 +10,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=533845
onload="doTest()">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<panel id="panel" width="50" height="50" onpopupshown="continueTest()">
<panel id="panel" width="50" height="50">
<iframe type="content" id="contentFrame" src="data:text/html,&lt;html&gt;&lt;body onclick='document.body.textContent=1'&gt;This is a panel!&lt;/body&gt;&lt;/html&gt;" width="500" height="500"/>
</panel>
<body xmlns="http://www.w3.org/1999/xhtml">
@ -23,7 +23,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=533845
SimpleTest.waitForExplicitFinish();
function doTest() {
document.getElementById('panel').showPopup();
let panel = document.getElementById("panel");
panel.addEventListener("popupshown", function onpopupshown() {
panel.removeEventListener("popupshown", onpopupshown);
continueTest();
panel.addEventListener("popuphidden", function onpopuphidden() {
panel.removeEventListener("popuphidden", onpopuphidden);
SimpleTest.finish();
});
panel.hidePopup();
});
panel.openPopup();
}
function continueTest() {
@ -37,7 +47,6 @@ function continueTest() {
utils.sendMouseEvent("mousedown", x, y, 0, 1, 0);
utils.sendMouseEvent("mouseup", x, y, 0, 1, 0);
is(ifrwindow.document.body.textContent, "1", "Should have got a click event!");
SimpleTest.finish();
}
]]></script>

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

@ -183,6 +183,21 @@ public:
nsLayoutUtils::GetTextShadowRectsUnion(mRect, mFrame);
return mRect.Union(shadowRect);
}
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override
{
if (gfxPlatform::GetPlatform()->RespectsFontStyleSmoothing()) {
// On OS X, web authors can turn off subpixel text rendering using the
// CSS property -moz-osx-font-smoothing. If they do that, we don't need
// to use component alpha layers for the affected text.
if (mFrame->StyleFont()->mFont.smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
return nsRect();
}
}
bool snap;
return GetBounds(aBuilder, &snap);
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) override;

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

@ -87,6 +87,12 @@ nsDisplayColumnRule::GetLayerState(nsDisplayListBuilder* aBuilder,
return LAYER_NONE;
}
for (auto iter = mBorderRenderers.begin(); iter != mBorderRenderers.end(); iter++) {
if (!iter->CanCreateWebRenderCommands()) {
return LAYER_NONE;
}
}
return LAYER_ACTIVE;
}

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

@ -4904,9 +4904,7 @@ public:
// On OS X, web authors can turn off subpixel text rendering using the
// CSS property -moz-osx-font-smoothing. If they do that, we don't need
// to use component alpha layers for the affected text.
nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
const nsStyleFont* fontStyle = f->StyleFont();
if (fontStyle->mFont.smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
if (mFrame->StyleFont()->mFont.smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
return nsRect();
}
}

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

@ -276,18 +276,6 @@ nsMathMLFrame::ParseNumericValue(const nsString& aString,
aFontSizeInflation);
}
// ================
// Utils to map attributes into CSS rules (work-around to bug 69409 which
// is not scheduled to be fixed anytime soon)
//
struct
nsCSSMapping {
int32_t compatibility;
const nsIAtom* attrAtom;
const char* cssProperty;
};
#if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
class nsDisplayMathMLBoundingMetrics : public nsDisplayItem {
public:

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

@ -5,7 +5,7 @@
== min-width-1a.html pref-width-1-ref.html
== min-width-1b.html min-width-1-ref.html
== min-width-1c.html min-width-1-ref.html
== min-width-2.html min-width-2-ref.html
fuzzy-if(webrender,255,2) == min-width-2.html min-width-2-ref.html
== column-balancing-overflow-000.html column-balancing-overflow-000.ref.html
== column-balancing-overflow-001.html column-balancing-overflow-000.ref.html
== column-balancing-overflow-002.html column-balancing-overflow-002.ref.html

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

@ -131,23 +131,31 @@ fuzzy(106,354) == css-multicol-1/multicol-rule-double-000.xht css-multicol-1/mul
fails-if(OSX||winWidget) == css-multicol-1/multicol-rule-fraction-001.xht css-multicol-1/multicol-rule-fraction-001-ref.xht
fails-if(OSX||winWidget) == css-multicol-1/multicol-rule-fraction-002.xht css-multicol-1/multicol-rule-fraction-002-ref.xht
fails-if(!styloVsGecko) == css-multicol-1/multicol-rule-fraction-003.xht css-multicol-1/multicol-rule-fraction-3-ref.xht
fuzzy(106,354) == css-multicol-1/multicol-rule-groove-000.xht css-multicol-1/multicol-rule-groove-000-ref.xht
fuzzy(106,354) fails-if(webrender) == css-multicol-1/multicol-rule-groove-000.xht css-multicol-1/multicol-rule-groove-000-ref.xht
skip-if(!webrender) pref(layers.advanced.border-layers,1) == css-multicol-1/multicol-rule-groove-000.xht css-multicol-1/multicol-rule-groove-000-ref.xht
fuzzy(94,256) == css-multicol-1/multicol-rule-hidden-000.xht css-multicol-1/multicol-rule-hidden-000-ref.xht
fuzzy(106,354) == css-multicol-1/multicol-rule-inset-000.xht css-multicol-1/multicol-rule-ridge-000-ref.xht
fuzzy(106,354) fails-if(webrender) == css-multicol-1/multicol-rule-inset-000.xht css-multicol-1/multicol-rule-ridge-000-ref.xht
skip-if(!webrender) pref(layers.advanced.border-layers,1) == css-multicol-1/multicol-rule-inset-000.xht css-multicol-1/multicol-rule-ridge-000-ref.xht
fuzzy(255,2808) == css-multicol-1/multicol-rule-large-001.xht css-multicol-1/multicol-rule-large-001-ref.xht
fuzzy(94,256) == css-multicol-1/multicol-rule-none-000.xht css-multicol-1/multicol-rule-hidden-000-ref.xht
fuzzy(106,354) == css-multicol-1/multicol-rule-outset-000.xht css-multicol-1/multicol-rule-groove-000-ref.xht
fuzzy(106,354) fails-if(webrender) == css-multicol-1/multicol-rule-outset-000.xht css-multicol-1/multicol-rule-groove-000-ref.xht
skip-if(!webrender) pref(layers.advanced.border-layers,1) == css-multicol-1/multicol-rule-outset-000.xht css-multicol-1/multicol-rule-groove-000-ref.xht
== css-multicol-1/multicol-rule-percent-001.xht css-multicol-1/multicol-containing-002-ref.xht
fails-if(!styloVsGecko) == css-multicol-1/multicol-rule-px-001.xht css-multicol-1/multicol-rule-ref.xht
fuzzy(106,354) == css-multicol-1/multicol-rule-ridge-000.xht css-multicol-1/multicol-rule-ridge-000-ref.xht
fuzzy(106,354) fails-if(webrender) == css-multicol-1/multicol-rule-ridge-000.xht css-multicol-1/multicol-rule-ridge-000-ref.xht
skip-if(!webrender) pref(layers.advanced.border-layers,1) == css-multicol-1/multicol-rule-ridge-000.xht css-multicol-1/multicol-rule-ridge-000-ref.xht
== css-multicol-1/multicol-rule-samelength-001.xht css-multicol-1/multicol-rule-samelength-001-ref.xht
== css-multicol-1/multicol-rule-shorthand-001.xht css-multicol-1/multicol-rule-samelength-001-ref.xht
fuzzy(106,354) == css-multicol-1/multicol-rule-solid-000.xht css-multicol-1/multicol-rule-solid-000-ref.xht
fails-if(!styloVsGecko) == css-multicol-1/multicol-rule-stacking-001.xht css-multicol-1/multicol-rule-stacking-ref.xht
== css-multicol-1/multicol-rule-style-groove-001.xht css-multicol-1/multicol-rule-style-groove-001-ref.xht
== css-multicol-1/multicol-rule-style-inset-001.xht css-multicol-1/multicol-rule-style-ridge-001-ref.xht
== css-multicol-1/multicol-rule-style-outset-001.xht css-multicol-1/multicol-rule-style-groove-001-ref.xht
== css-multicol-1/multicol-rule-style-ridge-001.xht css-multicol-1/multicol-rule-style-ridge-001-ref.xht
fails-if(webrender) == css-multicol-1/multicol-rule-style-groove-001.xht css-multicol-1/multicol-rule-style-groove-001-ref.xht
skip-if(!webrender) pref(layers.advanced.table,1) == css-multicol-1/multicol-rule-style-groove-001.xht css-multicol-1/multicol-rule-style-groove-001-ref.xht
fails-if(webrender) == css-multicol-1/multicol-rule-style-inset-001.xht css-multicol-1/multicol-rule-style-ridge-001-ref.xht
skip-if(!webrender) pref(layers.advanced.table,1) == css-multicol-1/multicol-rule-style-inset-001.xht css-multicol-1/multicol-rule-style-ridge-001-ref.xht
fails-if(webrender) == css-multicol-1/multicol-rule-style-outset-001.xht css-multicol-1/multicol-rule-style-groove-001-ref.xht
skip-if(!webrender) pref(layers.advanced.table,1) == css-multicol-1/multicol-rule-style-outset-001.xht css-multicol-1/multicol-rule-style-groove-001-ref.xht
fails-if(webrender) == css-multicol-1/multicol-rule-style-ridge-001.xht css-multicol-1/multicol-rule-style-ridge-001-ref.xht
skip-if(!webrender) pref(layers.advanced.table,1) == css-multicol-1/multicol-rule-style-ridge-001.xht css-multicol-1/multicol-rule-style-ridge-001-ref.xht
fails-if(!styloVsGecko) == css-multicol-1/multicol-shorthand-001.xht css-multicol-1/multicol-rule-ref.xht
fails-if(!styloVsGecko) == css-multicol-1/multicol-span-000.xht css-multicol-1/multicol-span-000-ref.xht
fails-if(!styloVsGecko) == css-multicol-1/multicol-span-all-001.xht css-multicol-1/multicol-span-all-001-ref.xht

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

@ -1724,7 +1724,7 @@ CSS_PROP_SVG(
FillOpacity,
CSS_PROPERTY_PARSE_VALUE,
"",
VARIANT_HN | VARIANT_OPENTYPE_SVG_KEYWORD,
VARIANT_HN | VARIANT_KEYWORD,
kContextOpacityKTable,
offsetof(nsStyleSVG, mFillOpacity),
eStyleAnimType_float)
@ -3869,7 +3869,7 @@ CSS_PROP_SVG(
StrokeOpacity,
CSS_PROPERTY_PARSE_VALUE,
"",
VARIANT_HN | VARIANT_OPENTYPE_SVG_KEYWORD,
VARIANT_HN | VARIANT_KEYWORD,
kContextOpacityKTable,
offsetof(nsStyleSVG, mStrokeOpacity),
eStyleAnimType_float)

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

@ -9649,6 +9649,10 @@ nsRuleNode::ComputeSVGData(void* aStartStruct,
svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_FILL;
} else if (atom == nsGkAtoms::stroke) {
svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_STROKE;
} else if (atom == nsGkAtoms::fill_opacity) {
svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY;
} else if (atom == nsGkAtoms::stroke_opacity) {
svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY;
}
}
break;

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

@ -1062,6 +1062,8 @@ enum class StyleWhiteSpace : uint8_t {
// -moz-context-properties
#define NS_STYLE_CONTEXT_PROPERTY_FILL (1 << 0)
#define NS_STYLE_CONTEXT_PROPERTY_STROKE (1 << 1)
#define NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY (1 << 2)
#define NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY (1 << 3)
/*
* -moz-window-shadow

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

@ -80,7 +80,7 @@ to mochitest command.
* Unsupported values
* SVG-in-OpenType values not supported servo/servo#15211 bug 1355412
* test_value_storage.html `context-` [7]
* test_bug798843_pref.html [5]
* test_bug798843_pref.html [3]
* Incorrect parsing
* different parsing bug 1364260
* test_supports_rules.html [6]

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

@ -13,8 +13,6 @@
<script>
var props = {
"fillOpacity" : "context-stroke-opacity",
"strokeOpacity" : "context-fill-opacity",
"strokeDasharray" : "context-value",
"strokeDashoffset" : "context-value",
"strokeWidth" : "context-value"

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

@ -395,6 +395,14 @@ SVGEmbeddingContextPaint::Hash() const
hash = HashGeneric(hash, mStroke->ToABGR());
}
if (mFillOpacity != 1.0f) {
hash = HashGeneric(hash, mFillOpacity);
}
if (mStrokeOpacity != 1.0f) {
hash = HashGeneric(hash, mStrokeOpacity);
}
return hash;
}

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

@ -251,7 +251,10 @@ class SVGEmbeddingContextPaint : public SVGContextPaint
typedef gfx::Color Color;
public:
SVGEmbeddingContextPaint() {}
SVGEmbeddingContextPaint()
: mFillOpacity(1.0f)
, mStrokeOpacity(1.0f)
{}
bool operator==(const SVGEmbeddingContextPaint& aOther) const {
MOZ_ASSERT(GetStrokeWidth() == aOther.GetStrokeWidth() &&
@ -259,7 +262,10 @@ public:
GetStrokeDashArray() == aOther.GetStrokeDashArray(),
"We don't currently include these in the context information "
"from an embedding element");
return mFill == aOther.mFill && mStroke == aOther.mStroke;
return mFill == aOther.mFill &&
mStroke == aOther.mStroke &&
mFillOpacity == aOther.mFillOpacity &&
mStrokeOpacity == aOther.mStrokeOpacity;
}
void SetFill(nscolor aFill) {
@ -283,14 +289,18 @@ public:
GetStrokePattern(const DrawTarget* aDrawTarget, float aStrokeOpacity,
const gfxMatrix& aCTM, imgDrawingParams& aImgParams) override;
void SetFillOpacity(float aOpacity) {
mFillOpacity = aOpacity;
}
float GetFillOpacity() const override {
// Always 1.0f since we don't currently allow 'context-fill-opacity'
return 1.0f;
return mFillOpacity;
};
void SetStrokeOpacity(float aOpacity) {
mStrokeOpacity = aOpacity;
}
float GetStrokeOpacity() const override {
// Always 1.0f since we don't currently allow 'context-stroke-opacity'
return 1.0f;
return mStrokeOpacity;
};
uint32_t Hash() const override;
@ -298,6 +308,8 @@ public:
private:
Maybe<Color> mFill;
Maybe<Color> mStroke;
float mFillOpacity;
float mStrokeOpacity;
};
} // namespace mozilla

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

@ -49,6 +49,14 @@ SVGImageContext::MaybeStoreContextPaint(Maybe<SVGImageContext>& aContext,
haveContextPaint = true;
contextPaint->SetStroke(style->mStroke.GetColor());
}
if (style->mContextPropsBits & NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY) {
haveContextPaint = true;
contextPaint->SetFillOpacity(style->mFillOpacity);
}
if (style->mContextPropsBits & NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY) {
haveContextPaint = true;
contextPaint->SetStrokeOpacity(style->mStrokeOpacity);
}
if (haveContextPaint) {
if (!aContext) {

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

@ -567,6 +567,8 @@ class AvailableEvent final : public Runnable
: mStream(stream)
, mCallback(callback)
, mDoingCallback(false)
, mSize(0)
, mResultForCallback(NS_OK)
{
mCallbackTarget = NS_GetCurrentThread();
}

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

@ -24,8 +24,13 @@ EXPORTS += [
'CacheStorageService.h',
]
UNIFIED_SOURCES += [
SOURCES += [
'AppCacheStorage.cpp',
'CacheStorage.cpp',
]
UNIFIED_SOURCES += [
'CacheEntry.cpp',
'CacheFile.cpp',
'CacheFileChunk.cpp',
@ -42,7 +47,6 @@ UNIFIED_SOURCES += [
'CacheIOThread.cpp',
'CacheLog.cpp',
'CacheObserver.cpp',
'CacheStorage.cpp',
'CacheStorageService.cpp',
'OldWrappers.cpp',
]

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

@ -335,7 +335,8 @@ class Bootstrapper(object):
print(STYLO_REQUIRES_CLONE)
sys.exit(1)
self.instance.stylo = True
self.instance.stylo = wants_stylo
if wants_stylo:
self.instance.state_dir = state_dir
self.instance.ensure_stylo_packages(state_dir, checkout_root)

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

@ -494,6 +494,52 @@ uint32_t ActivePS::sNextGeneration = 0;
// The mutex that guards accesses to CorePS and ActivePS.
static PSMutex gPSMutex;
// The preferred way to check profiler activeness and features is via
// ActivePS(). However, that requires locking gPSMutex. There are some hot
// operations where absolute precision isn't required, so we duplicate the
// activeness/feature state in a lock-free manner in this class.
class RacyFeatures
{
public:
static void SetActive(uint32_t aFeatures)
{
sActiveAndFeatures = Active | aFeatures;
}
static void SetInactive() { sActiveAndFeatures = 0; }
static bool IsActive() { return uint32_t(sActiveAndFeatures) & Active; }
static bool IsActiveWithFeature(uint32_t aFeature)
{
uint32_t af = sActiveAndFeatures; // copy it first
return (af & Active) && (af & aFeature);
}
static bool IsActiveWithoutPrivacy()
{
uint32_t af = sActiveAndFeatures; // copy it first
return (af & Active) && !(af & ProfilerFeature::Privacy);
}
private:
static const uint32_t Active = 1u << 31;
// Ensure Active doesn't overlap with any of the feature bits.
#define NO_OVERLAP(n_, str_, Name_) \
static_assert(ProfilerFeature::Name_ != Active, "bad Active value");
PROFILER_FOR_EACH_FEATURE(NO_OVERLAP);
#undef NO_OVERLAP
// We combine the active bit with the feature bits so they can be read or
// written in a single atomic operation.
static Atomic<uint32_t> sActiveAndFeatures;
};
Atomic<uint32_t> RacyFeatures::sActiveAndFeatures(0);
// Each live thread has a ThreadInfo, and we store a reference to it in TLS.
// This class encapsulates that TLS.
class TLSInfo
@ -2410,6 +2456,9 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
mozilla::java::GeckoJavaSampler::Start(javaInterval, 1000);
}
#endif
// At the very end, set up RacyFeatures.
RacyFeatures::SetActive(ActivePS::Features(aLock));
}
void
@ -2455,6 +2504,9 @@ locked_profiler_stop(PSLockRef aLock)
MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
// At the very start, clear RacyFeatures.
RacyFeatures::SetInactive();
#ifdef MOZ_TASK_TRACER
if (ActivePS::FeatureTaskTracer(aLock)) {
mozilla::tasktracer::StopLogging();
@ -2598,13 +2650,8 @@ profiler_feature_active(uint32_t aFeature)
MOZ_RELEASE_ASSERT(CorePS::Exists());
PSAutoLock lock(gPSMutex);
if (!ActivePS::Exists(lock)) {
return false;
}
return !!(ActivePS::Features(lock) & aFeature);
// This function is hot enough that we use RacyFeatures, not ActivePS.
return RacyFeatures::IsActiveWithFeature(aFeature);
}
bool
@ -2614,9 +2661,8 @@ profiler_is_active()
MOZ_RELEASE_ASSERT(CorePS::Exists());
PSAutoLock lock(gPSMutex);
return ActivePS::Exists(lock);
// This function is hot enough that we use RacyFeatures, notActivePS.
return RacyFeatures::IsActive();
}
void
@ -2851,16 +2897,21 @@ profiler_get_backtrace_noalloc(char *output, size_t outputSize)
}
static void
locked_profiler_add_marker(PSLockRef aLock, const char* aMarkerName,
racy_profiler_add_marker(const char* aMarkerName,
ProfilerMarkerPayload* aPayload)
{
MOZ_RELEASE_ASSERT(CorePS::Exists());
MOZ_RELEASE_ASSERT(ActivePS::Exists(aLock) &&
!ActivePS::FeaturePrivacy(aLock));
// aPayload must be freed if we return early.
mozilla::UniquePtr<ProfilerMarkerPayload> payload(aPayload);
// We don't assert that RacyFeatures::IsActiveWithoutPrivacy() is true here,
// because it's possible that the result has changed since we tested it in
// the caller.
//
// Because of this imprecision it's possible to miss a marker or record one
// we shouldn't. Either way is not a big deal.
RacyThreadInfo* racyInfo = TLSInfo::RacyInfo();
if (!racyInfo) {
return;
@ -2879,16 +2930,15 @@ profiler_add_marker(const char* aMarkerName, ProfilerMarkerPayload* aPayload)
{
MOZ_RELEASE_ASSERT(CorePS::Exists());
PSAutoLock lock(gPSMutex);
// aPayload must be freed if we return early.
mozilla::UniquePtr<ProfilerMarkerPayload> payload(aPayload);
if (!ActivePS::Exists(lock) || ActivePS::FeaturePrivacy(lock)) {
// This function is hot enough that we use RacyFeatures, notActivePS.
if (!RacyFeatures::IsActiveWithoutPrivacy()) {
return;
}
locked_profiler_add_marker(lock, aMarkerName, payload.release());
racy_profiler_add_marker(aMarkerName, payload.release());
}
void
@ -2897,14 +2947,13 @@ profiler_tracing(const char* aCategory, const char* aMarkerName,
{
MOZ_RELEASE_ASSERT(CorePS::Exists());
PSAutoLock lock(gPSMutex);
if (!ActivePS::Exists(lock) || ActivePS::FeaturePrivacy(lock)) {
// This function is hot enough that we use RacyFeatures, notActivePS.
if (!RacyFeatures::IsActiveWithoutPrivacy()) {
return;
}
auto payload = new ProfilerMarkerTracing(aCategory, aKind);
locked_profiler_add_marker(lock, aMarkerName, payload);
racy_profiler_add_marker(aMarkerName, payload);
}
void
@ -2913,15 +2962,14 @@ profiler_tracing(const char* aCategory, const char* aMarkerName,
{
MOZ_RELEASE_ASSERT(CorePS::Exists());
PSAutoLock lock(gPSMutex);
if (!ActivePS::Exists(lock) || ActivePS::FeaturePrivacy(lock)) {
// This function is hot enough that we use RacyFeatures, notActivePS.
if (!RacyFeatures::IsActiveWithoutPrivacy()) {
return;
}
auto payload =
new ProfilerMarkerTracing(aCategory, aKind, mozilla::Move(aCause));
locked_profiler_add_marker(lock, aMarkerName, payload);
racy_profiler_add_marker(aMarkerName, payload);
}
void

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

@ -1,187 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ProfileGatherer.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
namespace mozilla {
/**
* When a subprocess exits before we've gathered profiles, we'll
* store profiles for those processes until gathering starts. We'll
* only store up to MAX_SUBPROCESS_EXIT_PROFILES. The buffer is
* circular, so as soon as we receive another exit profile, we'll
* bump the oldest one out of the buffer.
*/
static const uint32_t MAX_SUBPROCESS_EXIT_PROFILES = 5;
NS_IMPL_ISUPPORTS0(ProfileGatherer)
ProfileGatherer::ProfileGatherer()
: mPendingProfiles(0)
, mGathering(false)
{
}
ProfileGatherer::~ProfileGatherer()
{
Cancel();
}
void
ProfileGatherer::GatheredOOPProfile(const nsACString& aProfile)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!mGathering) {
// If we're not actively gathering, then we don't actually
// care that we gathered a profile here. This can happen for
// processes that exit while profiling.
return;
}
MOZ_RELEASE_ASSERT(mWriter.isSome(), "Should always have a writer if mGathering is true");
if (!aProfile.IsEmpty()) {
mWriter->Splice(PromiseFlatCString(aProfile).get());
}
mPendingProfiles--;
if (mPendingProfiles == 0) {
// We've got all of the async profiles now. Let's
// finish off the profile and resolve the Promise.
Finish();
}
}
RefPtr<ProfileGatherer::ProfileGatherPromise>
ProfileGatherer::Start(double aSinceTime)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (mGathering) {
// If we're already gathering, return a rejected promise - this isn't
// going to end well.
return ProfileGatherPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
}
mGathering = true;
// Request profiles from the other processes. This will trigger
// asynchronous calls to ProfileGatherer::GatheredOOPProfile as the
// profiles arrive.
// Do this before the call to profiler_stream_json_for_this_process because
// that call is slow and we want to let the other processes grab their
// profiles as soon as possible.
nsTArray<RefPtr<ProfilerParent::SingleProcessProfilePromise>> profiles =
ProfilerParent::GatherProfiles();
mWriter.emplace();
// Start building up the JSON result and grab the profile from this process.
mWriter->Start(SpliceableJSONWriter::SingleLineStyle);
if (!profiler_stream_json_for_this_process(*mWriter, aSinceTime)) {
// The profiler is inactive. This either means that it was inactive even
// at the time that ProfileGatherer::Start() was called, or that it was
// stopped on a different thread since that call. Either way, we need to
// reject the promise and stop gathering.
return ProfileGatherPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
}
mWriter->StartArrayProperty("processes");
// If we have any process exit profiles, add them immediately, and clear
// mExitProfiles.
for (size_t i = 0; i < mExitProfiles.Length(); ++i) {
if (!mExitProfiles[i].IsEmpty()) {
mWriter->Splice(mExitProfiles[i].get());
}
}
mExitProfiles.Clear();
mPromiseHolder.emplace();
RefPtr<ProfileGatherPromise> promise = mPromiseHolder->Ensure(__func__);
// Keep the array property "processes" and the root object in mWriter open
// until Finish() is called. As profiles from the other processes come in,
// they will be inserted and end up in the right spot. Finish() will close
// the array and the root object.
mPendingProfiles = profiles.Length();
RefPtr<ProfileGatherer> self = this;
for (auto profile : profiles) {
profile->Then(AbstractThread::MainThread(), __func__,
[self](const nsCString& aResult) {
self->GatheredOOPProfile(aResult);
},
[self](PromiseRejectReason aReason) {
self->GatheredOOPProfile(NS_LITERAL_CSTRING(""));
});
}
if (!mPendingProfiles) {
Finish();
}
return promise;
}
void
ProfileGatherer::Finish()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mWriter.isSome());
MOZ_RELEASE_ASSERT(mPromiseHolder.isSome());
// Close the "processes" array property.
mWriter->EndArray();
// Close the root object of the generated JSON.
mWriter->End();
UniquePtr<char[]> buf = mWriter->WriteFunc()->CopyData();
nsCString result(buf.get());
mPromiseHolder->Resolve(result, __func__);
Reset();
}
void
ProfileGatherer::Reset()
{
mPromiseHolder.reset();
mPendingProfiles = 0;
mGathering = false;
mWriter.reset();
}
void
ProfileGatherer::Cancel()
{
// If we have a Promise in flight, we should reject it.
if (mPromiseHolder.isSome()) {
mPromiseHolder->RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__);
}
Reset();
}
void
ProfileGatherer::OOPExitProfile(const nsACString& aProfile)
{
// Append the exit profile to mExitProfiles so that it can be picked up the
// next time a profile is requested. If we're currently gathering a profile,
// do not add this exit profile to it; chances are that we already have a
// profile from the exiting process and we don't want another one.
// We only keep around at most MAX_SUBPROCESS_EXIT_PROFILES exit profiles.
if (mExitProfiles.Length() >= MAX_SUBPROCESS_EXIT_PROFILES) {
mExitProfiles.RemoveElementAt(0);
}
mExitProfiles.AppendElement(aProfile);
}
} // namespace mozilla

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

@ -1,42 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZ_PROFILE_GATHERER_H
#define MOZ_PROFILE_GATHERER_H
#include "nsIFile.h"
#include "ProfileJSONWriter.h"
#include "mozilla/MozPromise.h"
namespace mozilla {
// This class holds the state for an async profile-gathering request.
class ProfileGatherer final : public nsISupports
{
public:
NS_DECL_ISUPPORTS
typedef MozPromise<nsCString, nsresult, false> ProfileGatherPromise;
explicit ProfileGatherer();
void GatheredOOPProfile(const nsACString& aProfile);
RefPtr<ProfileGatherPromise> Start(double aSinceTime);
void OOPExitProfile(const nsACString& aProfile);
private:
~ProfileGatherer();
void Cancel();
void Finish();
void Reset();
nsTArray<nsCString> mExitProfiles;
Maybe<MozPromiseHolder<ProfileGatherPromise>> mPromiseHolder;
Maybe<SpliceableChunkedJSONWriter> mWriter;
uint32_t mPendingProfiles;
bool mGathering;
};
} // namespace mozilla
#endif

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

@ -23,8 +23,8 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/TypedArray.h"
#include "ProfileGatherer.h"
#include "nsLocalFile.h"
#include "ProfilerParent.h"
#include "platform.h"
using namespace mozilla;
@ -37,13 +37,9 @@ NS_IMPL_ISUPPORTS(nsProfiler, nsIProfiler)
nsProfiler::nsProfiler()
: mLockedForPrivateBrowsing(false)
, mPendingProfiles(0)
, mGathering(false)
{
// If MOZ_PROFILER_STARTUP is set, the profiler will already be running. We
// need to create a ProfileGatherer in that case.
// XXX: this is probably not the best approach. See bug 1356694 for details.
if (profiler_is_active()) {
mGatherer = new ProfileGatherer();
}
}
nsProfiler::~nsProfiler()
@ -125,10 +121,9 @@ nsProfiler::StartProfiler(uint32_t aEntries, double aInterval,
#undef ADD_FEATURE_BIT
profiler_start(aEntries, aInterval, features, aFilters, aFilterCount);
ResetGathering();
// Do this after profiler_start().
mGatherer = new ProfileGatherer();
profiler_start(aEntries, aInterval, features, aFilters, aFilterCount);
return NS_OK;
}
@ -136,8 +131,7 @@ nsProfiler::StartProfiler(uint32_t aEntries, double aInterval,
NS_IMETHODIMP
nsProfiler::StopProfiler()
{
// Do this before profiler_stop().
mGatherer = nullptr;
CancelGathering();
profiler_stop();
@ -253,7 +247,7 @@ nsProfiler::GetProfileDataAsync(double aSinceTime, JSContext* aCx,
{
MOZ_ASSERT(NS_IsMainThread());
if (!mGatherer) {
if (!profiler_is_active()) {
return NS_ERROR_FAILURE;
}
@ -274,7 +268,7 @@ nsProfiler::GetProfileDataAsync(double aSinceTime, JSContext* aCx,
return result.StealNSResult();
}
mGatherer->Start(aSinceTime)->Then(
StartGathering(aSinceTime)->Then(
AbstractThread::MainThread(), __func__,
[promise](nsCString aResult) {
AutoJSAPI jsapi;
@ -321,7 +315,7 @@ nsProfiler::GetProfileDataAsArrayBuffer(double aSinceTime, JSContext* aCx,
{
MOZ_ASSERT(NS_IsMainThread());
if (!mGatherer) {
if (!profiler_is_active()) {
return NS_ERROR_FAILURE;
}
@ -342,7 +336,7 @@ nsProfiler::GetProfileDataAsArrayBuffer(double aSinceTime, JSContext* aCx,
return result.StealNSResult();
}
mGatherer->Start(aSinceTime)->Then(
StartGathering(aSinceTime)->Then(
AbstractThread::MainThread(), __func__,
[promise](nsCString aResult) {
AutoJSAPI jsapi;
@ -377,13 +371,13 @@ nsProfiler::DumpProfileToFileAsync(const nsACString& aFilename,
{
MOZ_ASSERT(NS_IsMainThread());
if (!mGatherer) {
if (!profiler_is_active()) {
return NS_ERROR_FAILURE;
}
nsCString filename(aFilename);
mGatherer->Start(aSinceTime)->Then(
StartGathering(aSinceTime)->Then(
AbstractThread::MainThread(), __func__,
[filename](const nsCString& aResult) {
nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
@ -496,21 +490,166 @@ nsProfiler::GatheredOOPProfile(const nsACString& aProfile)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!mGatherer) {
if (!profiler_is_active()) {
return;
}
mGatherer->GatheredOOPProfile(aProfile);
if (!mGathering) {
// If we're not actively gathering, then we don't actually care that we
// gathered a profile here. This can happen for processes that exit while
// profiling.
return;
}
MOZ_RELEASE_ASSERT(mWriter.isSome(),
"Should always have a writer if mGathering is true");
if (!aProfile.IsEmpty()) {
mWriter->Splice(PromiseFlatCString(aProfile).get());
}
mPendingProfiles--;
if (mPendingProfiles == 0) {
// We've got all of the async profiles now. Let's
// finish off the profile and resolve the Promise.
FinishGathering();
}
}
// When a subprocess exits before we've gathered profiles, we'll store profiles
// for those processes until gathering starts. We'll only store up to
// MAX_SUBPROCESS_EXIT_PROFILES. The buffer is circular, so as soon as we
// receive another exit profile, we'll bump the oldest one out of the buffer.
static const uint32_t MAX_SUBPROCESS_EXIT_PROFILES = 5;
void
nsProfiler::ReceiveShutdownProfile(const nsCString& aProfile)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (!mGatherer) {
if (!profiler_is_active()) {
return;
}
mGatherer->OOPExitProfile(aProfile);
// Append the exit profile to mExitProfiles so that it can be picked up the
// next time a profile is requested. If we're currently gathering a profile,
// do not add this exit profile to it; chances are that we already have a
// profile from the exiting process and we don't want another one.
// We only keep around at most MAX_SUBPROCESS_EXIT_PROFILES exit profiles.
if (mExitProfiles.Length() >= MAX_SUBPROCESS_EXIT_PROFILES) {
mExitProfiles.RemoveElementAt(0);
}
mExitProfiles.AppendElement(aProfile);
}
RefPtr<nsProfiler::GatheringPromise>
nsProfiler::StartGathering(double aSinceTime)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (mGathering) {
// If we're already gathering, return a rejected promise - this isn't
// going to end well.
return GatheringPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
}
mGathering = true;
// Request profiles from the other processes. This will trigger asynchronous
// calls to ProfileGatherer::GatheredOOPProfile as the profiles arrive.
//
// Do this before the call to profiler_stream_json_for_this_process() because
// that call is slow and we want to let the other processes grab their
// profiles as soon as possible.
nsTArray<RefPtr<ProfilerParent::SingleProcessProfilePromise>> profiles =
ProfilerParent::GatherProfiles();
mWriter.emplace();
// Start building up the JSON result and grab the profile from this process.
mWriter->Start(SpliceableJSONWriter::SingleLineStyle);
if (!profiler_stream_json_for_this_process(*mWriter, aSinceTime)) {
// The profiler is inactive. This either means that it was inactive even
// at the time that ProfileGatherer::Start() was called, or that it was
// stopped on a different thread since that call. Either way, we need to
// reject the promise and stop gathering.
return GatheringPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
}
mWriter->StartArrayProperty("processes");
// If we have any process exit profiles, add them immediately, and clear
// mExitProfiles.
for (size_t i = 0; i < mExitProfiles.Length(); ++i) {
if (!mExitProfiles[i].IsEmpty()) {
mWriter->Splice(mExitProfiles[i].get());
}
}
mExitProfiles.Clear();
mPromiseHolder.emplace();
RefPtr<GatheringPromise> promise = mPromiseHolder->Ensure(__func__);
// Keep the array property "processes" and the root object in mWriter open
// until FinishGathering() is called. As profiles from the other processes
// come in, they will be inserted and end up in the right spot.
// FinishGathering() will close the array and the root object.
mPendingProfiles = profiles.Length();
RefPtr<nsProfiler> self = this;
for (auto profile : profiles) {
profile->Then(AbstractThread::MainThread(), __func__,
[self](const nsCString& aResult) {
self->GatheredOOPProfile(aResult);
},
[self](ipc::PromiseRejectReason aReason) {
self->GatheredOOPProfile(NS_LITERAL_CSTRING(""));
});
}
if (!mPendingProfiles) {
FinishGathering();
}
return promise;
}
void
nsProfiler::CancelGathering()
{
// If we have a Promise in flight, we should reject it.
if (mPromiseHolder.isSome()) {
mPromiseHolder->RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__);
}
ResetGathering();
}
void
nsProfiler::FinishGathering()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mWriter.isSome());
MOZ_RELEASE_ASSERT(mPromiseHolder.isSome());
// Close the "processes" array property.
mWriter->EndArray();
// Close the root object of the generated JSON.
mWriter->End();
UniquePtr<char[]> buf = mWriter->WriteFunc()->CopyData();
nsCString result(buf.get());
mPromiseHolder->Resolve(result, __func__);
ResetGathering();
}
void
nsProfiler::ResetGathering()
{
mPromiseHolder.reset();
mPendingProfiles = 0;
mGathering = false;
mWriter.reset();
}

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

@ -1,19 +1,19 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _NSPROFILER_H_
#define _NSPROFILER_H_
#ifndef nsProfiler_h
#define nsProfiler_h
#include "nsIProfiler.h"
#include "nsIObserver.h"
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
class ProfileGatherer;
}
#include "ProfileJSONWriter.h"
class nsProfiler final : public nsIProfiler, public nsIObserver
{
@ -38,9 +38,22 @@ public:
private:
~nsProfiler();
RefPtr<mozilla::ProfileGatherer> mGatherer;
typedef mozilla::MozPromise<nsCString, nsresult, false> GatheringPromise;
RefPtr<GatheringPromise> StartGathering(double aSinceTime);
void CancelGathering();
void FinishGathering();
void ResetGathering();
bool mLockedForPrivateBrowsing;
// These fields are all related to profile gathering.
nsTArray<nsCString> mExitProfiles;
mozilla::Maybe<mozilla::MozPromiseHolder<GatheringPromise>> mPromiseHolder;
mozilla::Maybe<SpliceableChunkedJSONWriter> mWriter;
uint32_t mPendingProfiles;
bool mGathering;
};
#endif /* _NSPROFILER_H_ */
#endif // nsProfiler_h

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

@ -28,7 +28,6 @@ if CONFIG['MOZ_GECKO_PROFILER']:
'gecko/ChildProfilerController.cpp',
'gecko/nsProfilerFactory.cpp',
'gecko/nsProfilerStartParams.cpp',
'gecko/ProfileGatherer.cpp',
'gecko/ProfilerChild.cpp',
'gecko/ProfilerIOInterposeObserver.cpp',
'gecko/ProfilerParent.cpp',

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

@ -290,7 +290,9 @@ ProfilerBacktraceDestructor::operator()(ProfilerBacktrace* aBacktrace) {}
PROFILER_FUNC(bool profiler_is_active(), false)
// Check if a profiler feature (specified via the ProfilerFeature type) is
// active. Returns false if the profiler is inactive.
// active. Returns false if the profiler is inactive. Note: the return value
// can become immediately out-of-date, much like the return value of
// profiler_is_active().
PROFILER_FUNC(bool profiler_feature_active(uint32_t aFeature), false)
// Get the profile encoded as a JSON string. A no-op (returning nullptr) if the

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

@ -30,7 +30,7 @@ using namespace mozilla;
typedef Vector<const char*> StrVec;
void
static void
InactiveFeaturesAndParamsCheck()
{
int entries;
@ -51,7 +51,7 @@ InactiveFeaturesAndParamsCheck()
ASSERT_TRUE(filters.empty());
}
void
static void
ActiveParamsCheck(int aEntries, double aInterval, uint32_t aFeatures,
const char** aFilters, size_t aFiltersLen)
{
@ -320,6 +320,45 @@ TEST(GeckoProfiler, Pause)
ASSERT_TRUE(!profiler_is_paused());
}
// A class that keeps track of how many instances have been created, streamed,
// and destroyed.
class GTestPayload : public ProfilerMarkerPayload
{
public:
explicit GTestPayload(int aN)
: mN(aN)
{
sNumCreated++;
}
virtual ~GTestPayload() { sNumDestroyed++; }
virtual void StreamPayload(SpliceableJSONWriter& aWriter,
const mozilla::TimeStamp& aStartTime,
UniqueStacks& aUniqueStacks) override
{
streamCommonProps("gtest", aWriter, aStartTime, aUniqueStacks);
char buf[64];
SprintfLiteral(buf, "gtest-%d", mN);
aWriter.IntProperty(buf, mN);
sNumStreamed++;
}
private:
int mN;
public:
// The number of GTestPayload instances that have been created, streamed, and
// destroyed.
static int sNumCreated;
static int sNumStreamed;
static int sNumDestroyed;
};
int GTestPayload::sNumCreated = 0;
int GTestPayload::sNumStreamed = 0;
int GTestPayload::sNumDestroyed = 0;
TEST(GeckoProfiler, Markers)
{
uint32_t features = ProfilerFeature::StackWalk;
@ -349,7 +388,50 @@ TEST(GeckoProfiler, Markers)
"M4", new ProfilerMarkerTracing("C", TRACING_EVENT,
profiler_get_backtrace()));
for (int i = 0; i < 10; i++) {
PROFILER_MARKER_PAYLOAD("M5", new GTestPayload(i));
}
// Sleep briefly to ensure a sample is taken and the pending markers are
// processed.
PR_Sleep(PR_MillisecondsToInterval(500));
SpliceableChunkedJSONWriter w;
ASSERT_TRUE(profiler_stream_json_for_this_process(w));
UniquePtr<char[]> profile = w.WriteFunc()->CopyData();
// The GTestPayloads should have been created and streamed, but not yet
// destroyed.
ASSERT_TRUE(GTestPayload::sNumCreated == 10);
ASSERT_TRUE(GTestPayload::sNumStreamed == 10);
ASSERT_TRUE(GTestPayload::sNumDestroyed == 0);
for (int i = 0; i < 10; i++) {
char buf[64];
SprintfLiteral(buf, "\"gtest-%d\"", i);
ASSERT_TRUE(strstr(profile.get(), buf));
}
profiler_stop();
// The GTestPayloads should have been destroyed.
ASSERT_TRUE(GTestPayload::sNumDestroyed == 10);
for (int i = 0; i < 10; i++) {
PROFILER_MARKER_PAYLOAD("M5", new GTestPayload(i));
}
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
features, filters, MOZ_ARRAY_LENGTH(filters));
ASSERT_TRUE(profiler_stream_json_for_this_process(w));
profiler_stop();
// The second set of GTestPayloads should not have been streamed.
ASSERT_TRUE(GTestPayload::sNumCreated == 20);
ASSERT_TRUE(GTestPayload::sNumStreamed == 10);
ASSERT_TRUE(GTestPayload::sNumDestroyed == 20);
}
TEST(GeckoProfiler, Time)
@ -394,6 +476,29 @@ TEST(GeckoProfiler, GetProfile)
ASSERT_TRUE(!profiler_get_profile());
}
static void
JSONOutputCheck(const char* aOutput)
{
// Check that various expected strings are in the JSON.
ASSERT_TRUE(aOutput);
ASSERT_TRUE(aOutput[0] == '{');
ASSERT_TRUE(strstr(aOutput, "\"libs\""));
ASSERT_TRUE(strstr(aOutput, "\"meta\""));
ASSERT_TRUE(strstr(aOutput, "\"version\""));
ASSERT_TRUE(strstr(aOutput, "\"startTime\""));
ASSERT_TRUE(strstr(aOutput, "\"threads\""));
ASSERT_TRUE(strstr(aOutput, "\"GeckoMain\""));
ASSERT_TRUE(strstr(aOutput, "\"samples\""));
ASSERT_TRUE(strstr(aOutput, "\"markers\""));
ASSERT_TRUE(strstr(aOutput, "\"stackTable\""));
ASSERT_TRUE(strstr(aOutput, "\"frameTable\""));
ASSERT_TRUE(strstr(aOutput, "\"stringTable\""));
}
TEST(GeckoProfiler, StreamJSONForThisProcess)
{
uint32_t features = ProfilerFeature::StackWalk;
@ -410,7 +515,8 @@ TEST(GeckoProfiler, StreamJSONForThisProcess)
w.End();
UniquePtr<char[]> profile = w.WriteFunc()->CopyData();
ASSERT_TRUE(profile && profile[0] == '{');
JSONOutputCheck(profile.get());
profiler_stop();
@ -442,7 +548,8 @@ TEST(GeckoProfiler, StreamJSONForThisProcessThreaded)
}), NS_DISPATCH_SYNC);
UniquePtr<char[]> profile = w.WriteFunc()->CopyData();
ASSERT_TRUE(profile && profile[0] == '{');
JSONOutputCheck(profile.get());
// Stop the profiler and call profiler_stream_json_for_this_process on a
// background thread.

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

@ -7,6 +7,9 @@
with Files("**"):
BUG_COMPONENT = ("Core", "Widget: Android")
with Files("*CompositorWidget*"):
BUG_COMPONENT = ("Core", "Graphics")
DIRS += [
'bindings',
'fennec',

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

@ -7,6 +7,12 @@
with Files("**"):
BUG_COMPONENT = ("Core", "Widget: Gtk")
with Files("*CompositorWidget*"):
BUG_COMPONENT = ("Core", "Graphics")
with Files("*WindowSurface*"):
BUG_COMPONENT = ("Core", "Graphics")
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':
DIRS += ['mozgtk']

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

@ -25,6 +25,9 @@ with Files("reftests/*fallback*"):
with Files("*CompositorWidget*"):
BUG_COMPONENT = ("Core", "Graphics")
with Files("*WindowSurface*"):
BUG_COMPONENT = ("Core", "Graphics")
with Files("*FontRange*"):
BUG_COMPONENT = ("Core", "Widget: Cocoa")

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

@ -7,6 +7,9 @@
with Files("**"):
BUG_COMPONENT = ("Core", "Widget: Win32")
with Files("*CompositorWidget*"):
BUG_COMPONENT = ("Core", "Graphics")
TEST_DIRS += ['tests']
EXPORTS += [