forked from mirrors/gecko-dev
Previously we needed to pass by value and that was causing us to clear out our prebuilt display list when we actually wanted to keep it around. The rust code ended up doing a bit of a silly dance but that's better than copying the display list around.
158 lines
5.5 KiB
C++
158 lines
5.5 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "WebRenderDisplayItemLayer.h"
|
|
|
|
#include "LayersLogging.h"
|
|
#include "mozilla/webrender/webrender_ffi.h"
|
|
#include "mozilla/webrender/WebRenderTypes.h"
|
|
#include "mozilla/layers/ScrollingLayersHelper.h"
|
|
#include "mozilla/layers/StackingContextHelper.h"
|
|
#include "mozilla/layers/WebRenderBridgeChild.h"
|
|
#include "nsDisplayList.h"
|
|
#include "mozilla/gfx/DrawEventRecorder.h"
|
|
#include "mozilla/gfx/Matrix.h"
|
|
#include "UnitTransforms.h"
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
WebRenderDisplayItemLayer::~WebRenderDisplayItemLayer()
|
|
{
|
|
MOZ_COUNT_DTOR(WebRenderDisplayItemLayer);
|
|
if (mKey.isSome()) {
|
|
WrManager()->AddImageKeyForDiscard(mKey.value());
|
|
}
|
|
if (mExternalImageId.isSome()) {
|
|
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
|
|
}
|
|
}
|
|
|
|
void
|
|
WebRenderDisplayItemLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|
const StackingContextHelper& aSc)
|
|
{
|
|
if (mVisibleRegion.IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
|
|
|
if (mItem) {
|
|
WrSize contentSize; // this won't actually be used by anything
|
|
wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize);
|
|
// We might have recycled this layer. Throw away the old commands.
|
|
mParentCommands.Clear();
|
|
mItem->CreateWebRenderCommands(builder, aSc, mParentCommands, this);
|
|
builder.Finalize(contentSize, mBuiltDisplayList);
|
|
} else {
|
|
// else we have an empty transaction and just use the
|
|
// old commands.
|
|
WebRenderLayerManager* manager = WrManager();
|
|
MOZ_ASSERT(manager);
|
|
|
|
// Since our recording relies on our parent layer's transform and stacking context
|
|
// If this layer or our parent changed, this empty transaction won't work.
|
|
if (manager->IsMutatedLayer(this) || manager->IsMutatedLayer(GetParent())) {
|
|
manager->SetTransactionIncomplete();
|
|
return;
|
|
}
|
|
}
|
|
|
|
aBuilder.PushBuiltDisplayList(mBuiltDisplayList);
|
|
WrBridge()->AddWebRenderParentCommands(mParentCommands);
|
|
}
|
|
|
|
Maybe<wr::ImageKey>
|
|
WebRenderDisplayItemLayer::SendImageContainer(ImageContainer* aContainer,
|
|
nsTArray<layers::WebRenderParentCommand>& aParentCommands)
|
|
{
|
|
MOZ_ASSERT(aContainer);
|
|
|
|
if (mImageContainer != aContainer) {
|
|
AutoLockImage autoLock(aContainer);
|
|
Image* image = autoLock.GetImage();
|
|
if (!image) {
|
|
return Nothing();
|
|
}
|
|
|
|
if (!mImageClient) {
|
|
mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
|
|
WrBridge(),
|
|
TextureFlags::DEFAULT);
|
|
if (!mImageClient) {
|
|
return Nothing();
|
|
}
|
|
mImageClient->Connect();
|
|
}
|
|
|
|
if (mExternalImageId.isNothing()) {
|
|
MOZ_ASSERT(mImageClient);
|
|
mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
|
|
}
|
|
MOZ_ASSERT(mExternalImageId.isSome());
|
|
MOZ_ASSERT(mImageClient->AsImageClientSingle());
|
|
|
|
mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
|
|
aContainer,
|
|
mKey,
|
|
mExternalImageId.ref());
|
|
|
|
mImageContainer = aContainer;
|
|
}
|
|
|
|
return mKey;
|
|
}
|
|
|
|
bool
|
|
WebRenderDisplayItemLayer::PushItemAsBlobImage(wr::DisplayListBuilder& aBuilder,
|
|
const StackingContextHelper& aSc)
|
|
{
|
|
const int32_t appUnitsPerDevPixel = mItem->Frame()->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
bool snap;
|
|
LayerRect bounds = ViewAs<LayerPixel>(
|
|
LayoutDeviceRect::FromAppUnits(mItem->GetBounds(mBuilder, &snap), appUnitsPerDevPixel),
|
|
PixelCastJustification::WebRenderHasUnitResolution);
|
|
LayerIntSize imageSize = RoundedToInt(bounds.Size());
|
|
LayerRect imageRect;
|
|
imageRect.SizeTo(LayerSize(imageSize));
|
|
|
|
RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
|
|
RefPtr<gfx::DrawTarget> dummyDt =
|
|
gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, imageSize.ToUnknownSize(), gfx::SurfaceFormat::B8G8R8X8);
|
|
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize());
|
|
LayerPoint offset = ViewAs<LayerPixel>(
|
|
LayoutDevicePoint::FromAppUnits(mItem->ToReferenceFrame(), appUnitsPerDevPixel),
|
|
PixelCastJustification::WebRenderHasUnitResolution);
|
|
|
|
{
|
|
dt->ClearRect(imageRect.ToUnknownRect());
|
|
RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt, offset.ToUnknownPoint());
|
|
MOZ_ASSERT(context);
|
|
|
|
mItem->Paint(mBuilder, context);
|
|
}
|
|
|
|
wr::ByteBuffer bytes;
|
|
bytes.Allocate(recorder->RecordingSize());
|
|
DebugOnly<bool> ok = recorder->CopyRecording((char*)bytes.AsSlice().begin().get(), bytes.AsSlice().length());
|
|
MOZ_ASSERT(ok);
|
|
|
|
WrRect dest = aSc.ToRelativeWrRect(imageRect + offset);
|
|
WrClipRegionToken clipRegion = aBuilder.PushClipRegion(dest);
|
|
WrImageKey key = GetImageKey();
|
|
WrBridge()->SendAddBlobImage(key, imageSize.ToUnknownSize(), imageSize.width * 4, dt->GetFormat(), bytes);
|
|
WrManager()->AddImageKeyForDiscard(key);
|
|
|
|
aBuilder.PushImage(dest,
|
|
clipRegion,
|
|
wr::ImageRendering::Auto,
|
|
key);
|
|
return true;
|
|
}
|
|
|
|
} // namespace layers
|
|
} // namespace mozilla
|