gecko/gfx/layers/basic/BasicImageLayer.cpp
Nicholas Cameron 30a1afa9de Bug 862106. Use Create*Client directly. r=nical
--HG--
extra : rebase_source : d903db2fcb68bbccff9548dfbcd215d9a25ba41c
2013-04-17 09:36:06 +12:00

303 lines
8.1 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 "mozilla/layers/PLayersParent.h"
#include "BasicLayersImpl.h"
#include "SharedTextureImage.h"
#include "gfxUtils.h"
#include "gfxSharedImageSurface.h"
#include "mozilla/layers/ImageClient.h"
#include "mozilla/layers/TextureClient.h"
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
#endif
using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
class BasicImageLayer : public ImageLayer, public BasicImplData {
public:
BasicImageLayer(BasicLayerManager* aLayerManager) :
ImageLayer(aLayerManager, static_cast<BasicImplData*>(this)),
mSize(-1, -1)
{
MOZ_COUNT_CTOR(BasicImageLayer);
}
virtual ~BasicImageLayer()
{
MOZ_COUNT_DTOR(BasicImageLayer);
}
virtual void SetVisibleRegion(const nsIntRegion& aRegion)
{
NS_ASSERTION(BasicManager()->InConstruction(),
"Can only set properties in construction phase");
ImageLayer::SetVisibleRegion(aRegion);
}
virtual void Paint(gfxContext* aContext, Layer* aMaskLayer);
virtual bool GetAsSurface(gfxASurface** aSurface,
SurfaceDescriptor* aDescriptor);
protected:
BasicLayerManager* BasicManager()
{
return static_cast<BasicLayerManager*>(mManager);
}
// only paints the image if aContext is non-null
already_AddRefed<gfxPattern>
GetAndPaintCurrentImage(gfxContext* aContext,
float aOpacity,
Layer* aMaskLayer);
gfxIntSize mSize;
};
void
BasicImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
{
if (IsHidden())
return;
nsRefPtr<gfxPattern> dontcare =
GetAndPaintCurrentImage(aContext, GetEffectiveOpacity(), aMaskLayer);
}
already_AddRefed<gfxPattern>
BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
float aOpacity,
Layer* aMaskLayer)
{
if (!mContainer)
return nullptr;
mContainer->SetImageFactory(mManager->IsCompositingCheap() ? nullptr : BasicManager()->GetImageFactory());
nsRefPtr<gfxASurface> surface;
AutoLockImage autoLock(mContainer, getter_AddRefs(surface));
Image *image = autoLock.GetImage();
gfxIntSize size = mSize = autoLock.GetSize();
if (!surface || surface->CairoStatus()) {
return nullptr;
}
nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
if (!pat) {
return nullptr;
}
pat->SetFilter(mFilter);
// The visible region can extend outside the image, so just draw
// within the image bounds.
if (aContext) {
AutoSetOperator setOperator(aContext, GetOperator());
PaintContext(pat,
nsIntRegion(nsIntRect(0, 0, size.width, size.height)),
aOpacity, aContext, aMaskLayer);
GetContainer()->NotifyPaintedImage(image);
}
return pat.forget();
}
void
PaintContext(gfxPattern* aPattern,
const nsIntRegion& aVisible,
float aOpacity,
gfxContext* aContext,
Layer* aMaskLayer)
{
// Set PAD mode so that when the video is being scaled, we do not sample
// outside the bounds of the video image.
gfxPattern::GraphicsExtend extend = gfxPattern::EXTEND_PAD;
#ifdef MOZ_X11
// PAD is slow with cairo and old X11 servers, so prefer speed over
// correctness and use NONE.
if (aContext->IsCairo()) {
nsRefPtr<gfxASurface> target = aContext->CurrentSurface();
if (target->GetType() == gfxASurface::SurfaceTypeXlib &&
static_cast<gfxXlibSurface*>(target.get())->IsPadSlow()) {
extend = gfxPattern::EXTEND_NONE;
}
}
#endif
aContext->NewPath();
// No need to snap here; our transform has already taken care of it.
// XXX true for arbitrary regions? Don't care yet though
gfxUtils::PathFromRegion(aContext, aVisible);
aPattern->SetExtend(extend);
aContext->SetPattern(aPattern);
FillWithMask(aContext, aOpacity, aMaskLayer);
// Reset extend mode for callers that need to reuse the pattern
aPattern->SetExtend(extend);
}
bool
BasicImageLayer::GetAsSurface(gfxASurface** aSurface,
SurfaceDescriptor* aDescriptor)
{
if (!mContainer) {
return false;
}
gfxIntSize dontCare;
nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&dontCare);
*aSurface = surface.forget().get();
return true;
}
class BasicShadowableImageLayer : public BasicImageLayer,
public BasicShadowableLayer
{
public:
BasicShadowableImageLayer(BasicShadowLayerManager* aManager) :
BasicImageLayer(aManager),
mImageClient(nullptr),
mImageClientTypeContainer(BUFFER_UNKNOWN)
{
MOZ_COUNT_CTOR(BasicShadowableImageLayer);
}
virtual ~BasicShadowableImageLayer()
{
DestroyBackBuffer();
MOZ_COUNT_DTOR(BasicShadowableImageLayer);
}
virtual void SetContainer(ImageContainer* aContainer) MOZ_OVERRIDE
{
ImageLayer::SetContainer(aContainer);
mImageClientTypeContainer = BUFFER_UNKNOWN;
}
virtual void Paint(gfxContext* aContext, Layer* aMaskLayer);
virtual void ClearCachedResources() MOZ_OVERRIDE
{
DestroyBackBuffer();
}
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{
aAttrs = ImageLayerAttributes(mFilter);
}
virtual Layer* AsLayer() { return this; }
virtual ShadowableLayer* AsShadowableLayer() { return this; }
virtual void Disconnect()
{
DestroyBackBuffer();
BasicShadowableLayer::Disconnect();
}
void DestroyBackBuffer()
{
mImageClient = nullptr;
}
virtual CompositableClient* GetCompositableClient() MOZ_OVERRIDE
{
return mImageClient;
}
private:
BasicShadowLayerManager* BasicManager()
{
return static_cast<BasicShadowLayerManager*>(mManager);
}
CompositableType GetImageClientType()
{
if (mImageClientTypeContainer != BUFFER_UNKNOWN) {
return mImageClientTypeContainer;
}
if (mContainer->IsAsync()) {
mImageClientTypeContainer = BUFFER_BRIDGE;
return mImageClientTypeContainer;
}
nsRefPtr<gfxASurface> surface;
AutoLockImage autoLock(mContainer, getter_AddRefs(surface));
mImageClientTypeContainer = autoLock.GetImage() ?
BUFFER_IMAGE_SINGLE : BUFFER_UNKNOWN;
return mImageClientTypeContainer;
}
RefPtr<ImageClient> mImageClient;
CompositableType mImageClientTypeContainer;
};
void
BasicShadowableImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
{
if (!HasShadow()) {
BasicImageLayer::Paint(aContext, aMaskLayer);
return;
}
if (aMaskLayer) {
static_cast<BasicImplData*>(aMaskLayer->ImplData())
->Paint(aContext, nullptr);
}
if (!mContainer) {
return;
}
if (!mImageClient ||
!mImageClient->UpdateImage(mContainer, GetContentFlags())) {
mImageClient = ImageClient::CreateImageClient(GetImageClientType(),
BasicManager(),
mForceSingleTile
? ForceSingleTile
: 0);
if (GetImageClientType() == BUFFER_BRIDGE) {
static_cast<ImageClientBridge*>(mImageClient.get())->SetLayer(this);
}
if (!mImageClient) {
return;
}
if (HasShadow() && !mContainer->IsAsync()) {
mImageClient->Connect();
BasicManager()->Attach(mImageClient, this);
}
if (!mImageClient->UpdateImage(mContainer, GetContentFlags())) {
return;
}
}
BasicManager()->Hold(this);
}
already_AddRefed<ImageLayer>
BasicLayerManager::CreateImageLayer()
{
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
nsRefPtr<ImageLayer> layer = new BasicImageLayer(this);
return layer.forget();
}
already_AddRefed<ImageLayer>
BasicShadowLayerManager::CreateImageLayer()
{
NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
nsRefPtr<BasicShadowableImageLayer> layer =
new BasicShadowableImageLayer(this);
MAYBE_CREATE_SHADOW(Image);
return layer.forget();
}
}
}