gecko-dev/gfx/layers/wr/WebRenderImageLayer.cpp
Kartikaya Gupta 60385dfbe4 Bug 1372603 - Move the clip rect for async images outside the iframe item. r=jrmuizel,sotaro
The async images codepath is a bit different in that it pushes an iframe
item to the WR display list and updates it asynchronously. However in
this case it still makes sense to push the layer's local clip
outside the iframe, and just populate the iframe with the image and not
worry about clips inside the iframe. As mentioned in part 1 of this
patchset, this will be needed to properly handle async scrolling.

This patch makes the necessary changes to push the clip outside the
iframe and simplifies what happens in WebRenderCompositableHolder to
generate the display list for the iframe itself.

MozReview-Commit-ID: DeZElH4p4rc

--HG--
extra : rebase_source : 3f3458a6c2607b8290dc2174a248f3d7bd33a3a9
2017-06-14 15:43:16 -04:00

289 lines
9.3 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 "WebRenderImageLayer.h"
#include "gfxPrefs.h"
#include "LayersLogging.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ImageClient.h"
#include "mozilla/layers/ScrollingLayersHelper.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "mozilla/layers/TextureWrapperImage.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/webrender/WebRenderTypes.h"
namespace mozilla {
namespace layers {
using namespace gfx;
WebRenderImageLayer::WebRenderImageLayer(WebRenderLayerManager* aLayerManager)
: ImageLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
, mImageClientContainerType(CompositableType::UNKNOWN)
{
MOZ_COUNT_CTOR(WebRenderImageLayer);
}
WebRenderImageLayer::~WebRenderImageLayer()
{
MOZ_COUNT_DTOR(WebRenderImageLayer);
if (mKey.isSome()) {
WrManager()->AddImageKeyForDiscard(mKey.value());
}
if (mExternalImageId.isSome()) {
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
}
if (mPipelineId.isSome()) {
WrBridge()->RemovePipelineIdForAsyncCompositable(mPipelineId.ref());
}
}
CompositableType
WebRenderImageLayer::GetImageClientType()
{
if (mImageClientContainerType != CompositableType::UNKNOWN) {
return mImageClientContainerType;
}
if (mContainer->IsAsync()) {
mImageClientContainerType = CompositableType::IMAGE_BRIDGE;
return mImageClientContainerType;
}
AutoLockImage autoLock(mContainer);
mImageClientContainerType = autoLock.HasImage()
? CompositableType::IMAGE : CompositableType::UNKNOWN;
return mImageClientContainerType;
}
already_AddRefed<gfx::SourceSurface>
WebRenderImageLayer::GetAsSourceSurface()
{
if (!mContainer) {
return nullptr;
}
AutoLockImage autoLock(mContainer);
Image *image = autoLock.GetImage();
if (!image) {
return nullptr;
}
RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
if (!surface || !surface->IsValid()) {
return nullptr;
}
return surface.forget();
}
void
WebRenderImageLayer::ClearCachedResources()
{
if (mImageClient) {
mImageClient->ClearCachedResources();
}
}
bool
WebRenderImageLayer::SupportsAsyncUpdate()
{
if (GetImageClientType() == CompositableType::IMAGE_BRIDGE &&
mPipelineId.isSome()) {
return true;
}
return false;
}
void
WebRenderImageLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc)
{
if (!mContainer) {
return;
}
CompositableType type = GetImageClientType();
if (type == CompositableType::UNKNOWN) {
return;
}
MOZ_ASSERT(GetImageClientType() != CompositableType::UNKNOWN);
if (GetImageClientType() == CompositableType::IMAGE && !mImageClient) {
mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
WrBridge(),
TextureFlags::DEFAULT);
if (!mImageClient) {
return;
}
mImageClient->Connect();
}
if (GetImageClientType() == CompositableType::IMAGE_BRIDGE && mPipelineId.isNothing()) {
MOZ_ASSERT(!mImageClient);
// Alloc async image pipeline id.
mPipelineId = Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
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.
// XXX Remove this once partial display list update is supported.
ScrollingLayersHelper scroller(this, aBuilder, aSc);
ParentLayerRect bounds = GetLocalTransformTyped().TransformBounds(Bounds());
// We don't push a stacking context for this async image pipeline here.
// Instead, we do it inside the iframe that hosts the image. As a result,
// a bunch of the calculations normally done as part of that stacking
// context need to be done manually and pushed over to the parent side,
// where it will be done when we build the display list for the iframe.
// That happens in WebRenderCompositableHolder.
LayerRect rect = ViewAs<LayerPixel>(bounds,
PixelCastJustification::MovingDownToChildren);
DumpLayerInfo("Image Layer async", rect);
WrClipRegionToken clipRegion = aBuilder.PushClipRegion(aSc.ToRelativeWrRect(rect));
aBuilder.PushIFrame(aSc.ToRelativeWrRect(rect), clipRegion, mPipelineId.ref());
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());
WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(mPipelineId.value(),
scBounds,
scTransform,
scaleToSize,
filter,
mixBlendMode));
return;
}
MOZ_ASSERT(GetImageClientType() == CompositableType::IMAGE);
MOZ_ASSERT(mImageClient->AsImageClientSingle());
AutoLockImage autoLock(mContainer);
Image* image = autoLock.GetImage();
if (!image) {
return;
}
gfx::IntSize size = image->GetSize();
mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
mContainer,
mKey,
mExternalImageId.ref());
if (mKey.isNothing()) {
return;
}
ScrollingLayersHelper scroller(this, aBuilder, aSc);
StackingContextHelper sc(aSc, aBuilder, this);
LayerRect rect(0, 0, size.width, size.height);
if (mScaleMode != ScaleMode::SCALE_NONE) {
NS_ASSERTION(mScaleMode == ScaleMode::STRETCH,
"No other scalemodes than stretch and none supported yet.");
rect = LayerRect(0, 0, mScaleToSize.width, mScaleToSize.height);
}
WrClipRegionToken clip = aBuilder.PushClipRegion(
sc.ToRelativeWrRect(rect));
wr::ImageRendering filter = wr::ToImageRendering(mSamplingFilter);
DumpLayerInfo("Image Layer", rect);
if (gfxPrefs::LayersDump()) {
printf_stderr("ImageLayer %p texture-filter=%s \n",
GetLayer(),
Stringify(filter).c_str());
}
aBuilder.PushImage(sc.ToRelativeWrRect(rect), clip, filter, mKey.value());
}
Maybe<WrImageMask>
WebRenderImageLayer::RenderMaskLayer(const StackingContextHelper& aSc,
const gfx::Matrix4x4& aTransform)
{
if (!mContainer) {
return Nothing();
}
CompositableType type = GetImageClientType();
if (type == CompositableType::UNKNOWN) {
return Nothing();
}
MOZ_ASSERT(GetImageClientType() == CompositableType::IMAGE);
if (GetImageClientType() != CompositableType::IMAGE) {
return Nothing();
}
if (!mImageClient) {
mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
WrBridge(),
TextureFlags::DEFAULT);
if (!mImageClient) {
return Nothing();
}
mImageClient->Connect();
}
if (mExternalImageId.isNothing()) {
mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
}
AutoLockImage autoLock(mContainer);
Image* image = autoLock.GetImage();
if (!image) {
return Nothing();
}
MOZ_ASSERT(mImageClient->AsImageClientSingle());
mKey = UpdateImageKey(mImageClient->AsImageClientSingle(),
mContainer,
mKey,
mExternalImageId.ref());
if (mKey.isNothing()) {
return Nothing();
}
gfx::IntSize size = image->GetSize();
WrImageMask imageMask;
imageMask.image = mKey.value();
Rect maskRect = aTransform.TransformBounds(Rect(0, 0, size.width, size.height));
imageMask.rect = aSc.ToRelativeWrRect(ViewAs<LayerPixel>(maskRect));
imageMask.repeat = false;
return Some(imageMask);
}
} // namespace layers
} // namespace mozilla