mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 782372 - Splits ImageLayers.h into ImageLayers.h ImageContainer.h and ImageTypes.h, r=bgirard
This commit is contained in:
parent
54f5995338
commit
75542595f3
@ -12,6 +12,7 @@
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "Layers.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAString.h"
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "BasicLayers.h"
|
||||
#include "imgIEncoder.h"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#ifndef VIDEOFRAMECONTAINER_H_
|
||||
#define VIDEOFRAMECONTAINER_H_
|
||||
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define MOZILLA_VIDEOSEGMENT_H_
|
||||
|
||||
#include "MediaSegment.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -195,11 +195,16 @@ destroying the nsBuiltinDecoder object.
|
||||
#include "nsMediaDecoder.h"
|
||||
#include "nsHTMLMediaElement.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "ImageLayers.h"
|
||||
class nsAudioStream;
|
||||
|
||||
typedef mozilla::layers::Image Image;
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class Image;
|
||||
} //namespace
|
||||
} //namespace
|
||||
|
||||
typedef mozilla::layers::Image Image;
|
||||
|
||||
class nsAudioStream;
|
||||
|
||||
static inline bool IsCurrentThread(nsIThread* aThread) {
|
||||
return NS_GetCurrentThread() == aThread;
|
||||
|
@ -148,12 +148,12 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
|
||||
aInfo.mDisplay));
|
||||
// Currently our decoder only knows how to output to PLANAR_YCBCR
|
||||
// format.
|
||||
Image::Format format = Image::PLANAR_YCBCR;
|
||||
ImageFormat format = ImageFormat::PLANAR_YCBCR;
|
||||
v->mImage = aContainer->CreateImage(&format, 1);
|
||||
if (!v->mImage) {
|
||||
return nullptr;
|
||||
}
|
||||
NS_ASSERTION(v->mImage->GetFormat() == Image::PLANAR_YCBCR,
|
||||
NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::PLANAR_YCBCR,
|
||||
"Wrong format?");
|
||||
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
|
||||
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
: mAudioRate(44100),
|
||||
mAudioChannels(2),
|
||||
mDisplay(0,0),
|
||||
mStereoMode(mozilla::layers::STEREO_MODE_MONO),
|
||||
mStereoMode(mozilla::STEREO_MODE_MONO),
|
||||
mHasAudio(false),
|
||||
mHasVideo(false)
|
||||
{}
|
||||
@ -43,7 +43,7 @@ public:
|
||||
nsIntSize mDisplay;
|
||||
|
||||
// Indicates the frame layout for single track stereo videos.
|
||||
mozilla::layers::StereoMode mStereoMode;
|
||||
mozilla::StereoMode mStereoMode;
|
||||
|
||||
// True if we have an active audio bitstream.
|
||||
bool mHasAudio;
|
||||
@ -462,7 +462,7 @@ public:
|
||||
if (!v->mImage) {
|
||||
return nullptr;
|
||||
}
|
||||
NS_ASSERTION(v->mImage->GetFormat() == mozilla::layers::Image::PLANAR_YCBCR,
|
||||
NS_ASSERTION(v->mImage->GetFormat() == mozilla::ImageFormat::PLANAR_YCBCR,
|
||||
"Wrong format?");
|
||||
mozilla::layers::PlanarYCbCrImage* vi = static_cast<mozilla::layers::PlanarYCbCrImage*>(v->mImage.get());
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "VideoFrameContainer.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
class nsHTMLMediaElement;
|
||||
class nsIStreamListener;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "Layers.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include "AndroidBridge.h"
|
||||
@ -94,7 +95,7 @@ MediaEngineDefaultVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
|
||||
mSource = aStream;
|
||||
|
||||
// Allocate a single blank Image
|
||||
layers::Image::Format format = layers::Image::PLANAR_YCBCR;
|
||||
ImageFormat format = ImageFormat::PLANAR_YCBCR;
|
||||
mImageContainer = layers::LayerManager::CreateImageContainer();
|
||||
|
||||
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&format, 1);
|
||||
@ -118,7 +119,7 @@ MediaEngineDefaultVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
|
||||
data.mPicX = 0;
|
||||
data.mPicY = 0;
|
||||
data.mPicSize = gfxIntSize(WIDTH, HEIGHT);
|
||||
data.mStereoMode = layers::STEREO_MODE_MONO;
|
||||
data.mStereoMode = STEREO_MODE_MONO;
|
||||
|
||||
// SetData copies data, so we can free the frame
|
||||
mImage->SetData(data);
|
||||
|
@ -3,6 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaEngineWebRTC.h"
|
||||
#include "Layers.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -47,7 +48,7 @@ MediaEngineWebRTCVideoSource::DeliverFrame(
|
||||
}
|
||||
|
||||
// Create a video frame and append it to the track.
|
||||
layers::Image::Format format = layers::Image::PLANAR_YCBCR;
|
||||
ImageFormat format = ImageFormat::PLANAR_YCBCR;
|
||||
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&format, 1);
|
||||
|
||||
layers::PlanarYCbCrImage* videoImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
|
||||
@ -67,7 +68,7 @@ MediaEngineWebRTCVideoSource::DeliverFrame(
|
||||
data.mPicX = 0;
|
||||
data.mPicY = 0;
|
||||
data.mPicSize = gfxIntSize(mWidth, mHeight);
|
||||
data.mStereoMode = layers::STEREO_MODE_MONO;
|
||||
data.mStereoMode = STEREO_MODE_MONO;
|
||||
|
||||
videoImage->SetData(data);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CameraPreview.h"
|
||||
|
||||
#include "Layers.h"
|
||||
#define DOM_CAMERA_LOG_LEVEL 3
|
||||
#include "CameraCommon.h"
|
||||
|
||||
|
@ -33,7 +33,7 @@ GonkCameraPreview::ReceiveFrame(mozilla::layers::GraphicBufferLocked* aBuffer)
|
||||
if (!aBuffer)
|
||||
return;
|
||||
|
||||
Image::Format format = Image::GONK_IO_SURFACE;
|
||||
ImageFormat format = ImageFormat::GONK_IO_SURFACE;
|
||||
nsRefPtr<Image> image = mImageContainer->CreateImage(&format, 1);
|
||||
GonkIOSurfaceImage* videoImage = static_cast<GonkIOSurfaceImage*>(image.get());
|
||||
GonkIOSurfaceImage::Data data;
|
||||
|
@ -59,6 +59,7 @@ using mozilla::DefaultXDisplay;
|
||||
#include "nsIDOMDragEvent.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
#include "nsContentCID.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
@ -177,7 +178,7 @@ nsPluginInstanceOwner::GetImageContainer()
|
||||
|
||||
nsRefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
|
||||
|
||||
Image::Format format = Image::SHARED_TEXTURE;
|
||||
ImageFormat format = ImageFormat::SHARED_TEXTURE;
|
||||
nsRefPtr<Image> img = container->CreateImage(&format, 1);
|
||||
|
||||
SharedTextureImage::Data data;
|
||||
@ -210,7 +211,7 @@ nsPluginInstanceOwner::GetImageContainer()
|
||||
#ifdef XP_MACOSX
|
||||
AutoLockImage autoLock(container);
|
||||
Image* image = autoLock.GetImage();
|
||||
if (image && image->GetFormat() == Image::MAC_IO_SURFACE && mObjectFrame) {
|
||||
if (image && image->GetFormat() == ImageFormat::MAC_IO_SURFACE && mObjectFrame) {
|
||||
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image);
|
||||
NS_ADDREF_THIS();
|
||||
oglImage->SetUpdateCallback(&DrawPlugin, this);
|
||||
@ -1804,7 +1805,7 @@ already_AddRefed<ImageContainer> nsPluginInstanceOwner::GetImageContainerForVide
|
||||
{
|
||||
nsRefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
|
||||
|
||||
Image::Format format = Image::SHARED_TEXTURE;
|
||||
ImageFormat format = ImageFormat::SHARED_TEXTURE;
|
||||
nsRefPtr<Image> img = container->CreateImage(&format, 1);
|
||||
|
||||
SharedTextureImage::Data data;
|
||||
@ -3716,7 +3717,7 @@ void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
|
||||
#ifdef XP_MACOSX
|
||||
AutoLockImage autoLock(container);
|
||||
Image *image = autoLock.GetImage();
|
||||
if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
|
||||
if (image && (image->GetFormat() == ImageFormat::MAC_IO_SURFACE) && mObjectFrame) {
|
||||
// Undo what we did to the current image in SetCurrentImageInTransaction().
|
||||
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image);
|
||||
oglImage->SetUpdateCallback(nullptr, nullptr);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "gfxColor.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "Layers.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windowsx.h>
|
||||
@ -730,10 +731,10 @@ PluginInstanceParent::GetImageContainer(ImageContainer** aContainer)
|
||||
#endif
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
Image::Format format = Image::CAIRO_SURFACE;
|
||||
ImageFormat format = ImageFormat::CAIRO_SURFACE;
|
||||
#ifdef XP_MACOSX
|
||||
if (ioSurface) {
|
||||
format = Image::MAC_IO_SURFACE;
|
||||
format = ImageFormat::MAC_IO_SURFACE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -757,7 +758,7 @@ PluginInstanceParent::GetImageContainer(ImageContainer** aContainer)
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (ioSurface) {
|
||||
NS_ASSERTION(image->GetFormat() == Image::MAC_IO_SURFACE, "Wrong format?");
|
||||
NS_ASSERTION(image->GetFormat() == ImageFormat::MAC_IO_SURFACE, "Wrong format?");
|
||||
MacIOSurfaceImage* ioImage = static_cast<MacIOSurfaceImage*>(image.get());
|
||||
MacIOSurfaceImage::Data ioData;
|
||||
ioData.mIOSurface = ioSurface;
|
||||
@ -770,7 +771,7 @@ PluginInstanceParent::GetImageContainer(ImageContainer** aContainer)
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(image->GetFormat() == Image::CAIRO_SURFACE, "Wrong format?");
|
||||
NS_ASSERTION(image->GetFormat() == ImageFormat::CAIRO_SURFACE, "Wrong format?");
|
||||
CairoImage* pluginImage = static_cast<CairoImage*>(image.get());
|
||||
CairoImage::Data cairoData;
|
||||
cairoData.mSurface = mFrontSurface;
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsRect.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "ImageLayers.h"
|
||||
|
||||
#ifdef MOZ_X11
|
||||
class gfxXlibSurface;
|
||||
#endif
|
||||
@ -32,6 +32,10 @@ class gfxXlibSurface;
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class ImageContainer;
|
||||
class CompositionNotifySink;
|
||||
}
|
||||
namespace plugins {
|
||||
|
||||
class PBrowserStreamParent;
|
||||
|
552
gfx/layers/ImageContainer.cpp
Normal file
552
gfx/layers/ImageContainer.cpp
Normal file
@ -0,0 +1,552 @@
|
||||
/* -*- Mode: C++; tab-width: 20; 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/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/ImageContainerChild.h"
|
||||
|
||||
#include "ImageContainer.h"
|
||||
#include "GonkIOSurfaceImage.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "mozilla/ipc/CrossProcessMutex.h"
|
||||
#include "SharedTextureImage.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxSharedImageSurface.h"
|
||||
#include "yuv_convert.h"
|
||||
#include "gfxUtils.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "mozilla/gfx/QuartzSupport.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "gfxD2DSurface.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include <d3d10_1.h>
|
||||
|
||||
#include "d3d10/ImageLayerD3D10.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using mozilla::gfx::DataSourceSurface;
|
||||
using mozilla::gfx::SourceSurface;
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageFactory::CreateImage(const ImageFormat *aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &,
|
||||
BufferRecycleBin *aRecycleBin)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<Image> img;
|
||||
if (FormatInList(aFormats, aNumFormats, ImageFormat::PLANAR_YCBCR)) {
|
||||
img = new PlanarYCbCrImage(aRecycleBin);
|
||||
} else if (FormatInList(aFormats, aNumFormats, ImageFormat::CAIRO_SURFACE)) {
|
||||
img = new CairoImage();
|
||||
} else if (FormatInList(aFormats, aNumFormats, ImageFormat::SHARED_TEXTURE)) {
|
||||
img = new SharedTextureImage();
|
||||
#ifdef XP_MACOSX
|
||||
} else if (FormatInList(aFormats, aNumFormats, ImageFormat::MAC_IO_SURFACE)) {
|
||||
img = new MacIOSurfaceImage();
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
} else if (FormatInList(aFormats, aNumFormats, ImageFormat::GONK_IO_SURFACE)) {
|
||||
img = new GonkIOSurfaceImage();
|
||||
#endif
|
||||
}
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
BufferRecycleBin::BufferRecycleBin()
|
||||
: mLock("mozilla.layers.BufferRecycleBin.mLock")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BufferRecycleBin::RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) {
|
||||
mRecycledBuffers.Clear();
|
||||
}
|
||||
mRecycledBufferSize = aSize;
|
||||
mRecycledBuffers.AppendElement(aBuffer);
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
BufferRecycleBin::GetBuffer(PRUint32 aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize)
|
||||
return new PRUint8[aSize];
|
||||
|
||||
PRUint32 last = mRecycledBuffers.Length() - 1;
|
||||
PRUint8* result = mRecycledBuffers[last].forget();
|
||||
mRecycledBuffers.RemoveElementAt(last);
|
||||
return result;
|
||||
}
|
||||
|
||||
ImageContainer::ImageContainer(int flag)
|
||||
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
|
||||
mPaintCount(0),
|
||||
mPreviousImagePainted(false),
|
||||
mImageFactory(new ImageFactory()),
|
||||
mRecycleBin(new BufferRecycleBin()),
|
||||
mRemoteData(nullptr),
|
||||
mRemoteDataMutex(nullptr),
|
||||
mCompositionNotifySink(nullptr),
|
||||
mImageContainerChild(nullptr)
|
||||
{
|
||||
if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) {
|
||||
mImageContainerChild =
|
||||
ImageBridgeChild::GetSingleton()->CreateImageContainerChild();
|
||||
}
|
||||
}
|
||||
|
||||
ImageContainer::~ImageContainer()
|
||||
{
|
||||
if (mImageContainerChild) {
|
||||
mImageContainerChild->DispatchStop();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainer::CreateImage(const ImageFormat *aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mImageFactory->CreateImage(aFormats, aNumFormats, mScaleHint, mRecycleBin);
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetCurrentImageInternal(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Lock();
|
||||
// This is important since it ensures we won't change the active image
|
||||
// when we currently have a locked image that depends on mRemoteData.
|
||||
}
|
||||
|
||||
mActiveImage = aImage;
|
||||
CurrentImageChanged();
|
||||
|
||||
if (mRemoteData) {
|
||||
mRemoteDataMutex->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetCurrentImage(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mImageContainerChild) {
|
||||
if (aImage) {
|
||||
mImageContainerChild->SendImageAsync(this, aImage);
|
||||
} else {
|
||||
mImageContainerChild->DispatchSetIdle();
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentImageInternal(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetCurrentImageInTransaction(Image *aImage)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
NS_ASSERTION(!mImageContainerChild, "Should use async image transfer with ImageBridge.");
|
||||
|
||||
SetCurrentImageInternal(aImage);
|
||||
}
|
||||
|
||||
bool ImageContainer::IsAsync() const {
|
||||
return mImageContainerChild != nullptr;
|
||||
}
|
||||
|
||||
PRUint64 ImageContainer::GetAsyncContainerID() const
|
||||
{
|
||||
NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers");
|
||||
if (IsAsync()) {
|
||||
return mImageContainerChild->GetID();
|
||||
} else {
|
||||
return 0; // zero is always an invalid SharedImageID
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ImageContainer::HasCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
|
||||
|
||||
EnsureActiveImage();
|
||||
|
||||
return !!mActiveImage.get();
|
||||
}
|
||||
|
||||
return !!mActiveImage.get();
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainer::LockCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Lock();
|
||||
}
|
||||
|
||||
EnsureActiveImage();
|
||||
|
||||
nsRefPtr<Image> retval = mActiveImage;
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainer::LockCurrentAsSurface(gfxIntSize *aSize, Image** aCurrentImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Lock();
|
||||
|
||||
EnsureActiveImage();
|
||||
|
||||
if (aCurrentImage) {
|
||||
NS_IF_ADDREF(mActiveImage);
|
||||
*aCurrentImage = mActiveImage.get();
|
||||
}
|
||||
|
||||
if (!mActiveImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mActiveImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) {
|
||||
nsRefPtr<gfxImageSurface> newSurf =
|
||||
new gfxImageSurface(mRemoteData->mBitmap.mData, mRemoteData->mSize, mRemoteData->mBitmap.mStride,
|
||||
mRemoteData->mFormat == RemoteImageData::BGRX32 ?
|
||||
gfxASurface::ImageFormatARGB32 :
|
||||
gfxASurface::ImageFormatRGB24);
|
||||
|
||||
*aSize = newSurf->GetSize();
|
||||
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
*aSize = mActiveImage->GetSize();
|
||||
return mActiveImage->GetAsSurface();
|
||||
}
|
||||
|
||||
if (aCurrentImage) {
|
||||
NS_IF_ADDREF(mActiveImage);
|
||||
*aCurrentImage = mActiveImage.get();
|
||||
}
|
||||
|
||||
if (!mActiveImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*aSize = mActiveImage->GetSize();
|
||||
return mActiveImage->GetAsSurface();
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::UnlockCurrentImage()
|
||||
{
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
|
||||
EnsureActiveImage();
|
||||
|
||||
if (!mActiveImage)
|
||||
return nullptr;
|
||||
*aSize = mRemoteData->mSize;
|
||||
} else {
|
||||
if (!mActiveImage)
|
||||
return nullptr;
|
||||
*aSize = mActiveImage->GetSize();
|
||||
}
|
||||
return mActiveImage->GetAsSurface();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
ImageContainer::GetCurrentSize()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
|
||||
|
||||
// We don't need to ensure we have an active image here, as we need to
|
||||
// be in the mutex anyway, and this is easiest to return from there.
|
||||
return mRemoteData->mSize;
|
||||
}
|
||||
|
||||
if (!mActiveImage) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
|
||||
return mActiveImage->GetSize();
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
NS_ASSERTION(!mActiveImage || !aData, "No active image expected when SetRemoteImageData is called with non-NULL aData.");
|
||||
NS_ASSERTION(!mRemoteData || !aData, "No remote data expected when SetRemoteImageData is called with non-NULL aData.");
|
||||
|
||||
mRemoteData = aData;
|
||||
|
||||
if (aData) {
|
||||
memset(aData, 0, sizeof(RemoteImageData));
|
||||
} else {
|
||||
mActiveImage = nullptr;
|
||||
}
|
||||
|
||||
mRemoteDataMutex = aMutex;
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::EnsureActiveImage()
|
||||
{
|
||||
if (mRemoteData) {
|
||||
if (mRemoteData->mWasUpdated) {
|
||||
mActiveImage = nullptr;
|
||||
}
|
||||
|
||||
if (mRemoteData->mType == RemoteImageData::RAW_BITMAP &&
|
||||
mRemoteData->mBitmap.mData && !mActiveImage) {
|
||||
nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage();
|
||||
|
||||
newImg->mFormat = mRemoteData->mFormat;
|
||||
newImg->mData = mRemoteData->mBitmap.mData;
|
||||
newImg->mSize = mRemoteData->mSize;
|
||||
newImg->mStride = mRemoteData->mBitmap.mStride;
|
||||
mRemoteData->mWasUpdated = false;
|
||||
|
||||
mActiveImage = newImg;
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
else if (mRemoteData->mType == RemoteImageData::DXGI_TEXTURE_HANDLE &&
|
||||
mRemoteData->mTextureHandle && !mActiveImage) {
|
||||
nsRefPtr<RemoteDXGITextureImage> newImg = new RemoteDXGITextureImage();
|
||||
newImg->mSize = mRemoteData->mSize;
|
||||
newImg->mHandle = mRemoteData->mTextureHandle;
|
||||
newImg->mFormat = mRemoteData->mFormat;
|
||||
mRemoteData->mWasUpdated = false;
|
||||
|
||||
mActiveImage = newImg;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin)
|
||||
: Image(nullptr, PLANAR_YCBCR)
|
||||
, mBufferSize(0)
|
||||
, mRecycleBin(aRecycleBin)
|
||||
{
|
||||
}
|
||||
|
||||
PlanarYCbCrImage::~PlanarYCbCrImage()
|
||||
{
|
||||
if (mBuffer) {
|
||||
mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
PlanarYCbCrImage::AllocateBuffer(PRUint32 aSize)
|
||||
{
|
||||
return mRecycleBin->GetBuffer(aSize);
|
||||
}
|
||||
|
||||
static void
|
||||
CopyPlane(PRUint8 *aDst, PRUint8 *aSrc,
|
||||
const gfxIntSize &aSize, PRInt32 aStride,
|
||||
PRInt32 aOffset, PRInt32 aSkip)
|
||||
{
|
||||
if (!aOffset && !aSkip) {
|
||||
// Fast path: planar input.
|
||||
memcpy(aDst, aSrc, aSize.height * aStride);
|
||||
} else {
|
||||
PRInt32 height = aSize.height;
|
||||
PRInt32 width = aSize.width;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
PRUint8 *src = aSrc + aOffset;
|
||||
PRUint8 *dst = aDst;
|
||||
if (!aSkip) {
|
||||
// Fast path: offset only, no per-pixel skip.
|
||||
memcpy(dst, src, width);
|
||||
} else {
|
||||
// Slow path
|
||||
for (int x = 0; x < width; ++x) {
|
||||
*dst++ = *src++;
|
||||
src += aSkip;
|
||||
}
|
||||
}
|
||||
aSrc += aStride;
|
||||
aDst += aStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::CopyData(const Data& aData,
|
||||
PRInt32 aYOffset, PRInt32 aYSkip,
|
||||
PRInt32 aCbOffset, PRInt32 aCbSkip,
|
||||
PRInt32 aCrOffset, PRInt32 aCrSkip)
|
||||
{
|
||||
mData = aData;
|
||||
|
||||
// update buffer size
|
||||
mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
|
||||
mData.mYStride * mData.mYSize.height;
|
||||
|
||||
// get new buffer
|
||||
mBuffer = AllocateBuffer(mBufferSize);
|
||||
if (!mBuffer)
|
||||
return;
|
||||
|
||||
mData.mYChannel = mBuffer;
|
||||
mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
|
||||
mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
|
||||
|
||||
CopyPlane(mData.mYChannel, aData.mYChannel,
|
||||
mData.mYSize, mData.mYStride,
|
||||
aYOffset, aYSkip);
|
||||
CopyPlane(mData.mCbChannel, aData.mCbChannel,
|
||||
mData.mCbCrSize, mData.mCbCrStride,
|
||||
aCbOffset, aCbSkip);
|
||||
CopyPlane(mData.mCrChannel, aData.mCrChannel,
|
||||
mData.mCbCrSize, mData.mCbCrStride,
|
||||
aCrOffset, aCrSkip);
|
||||
|
||||
mSize = aData.mPicSize;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::SetData(const Data &aData)
|
||||
{
|
||||
CopyData(aData);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
PlanarYCbCrImage::GetAsSurface()
|
||||
{
|
||||
if (mSurface) {
|
||||
nsRefPtr<gfxASurface> result = mSurface.get();
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
gfxASurface::gfxImageFormat format = GetOffscreenFormat();
|
||||
|
||||
gfxIntSize size(mSize);
|
||||
gfxUtils::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
|
||||
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
|
||||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
|
||||
NS_ERROR("Illegal image dest width or height");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> imageSurface =
|
||||
new gfxImageSurface(mSize, format);
|
||||
|
||||
gfxUtils::ConvertYCbCrToRGB(mData, format, mSize,
|
||||
imageSurface->Data(),
|
||||
imageSurface->Stride());
|
||||
|
||||
mSurface = imageSurface;
|
||||
|
||||
return imageSurface.forget().get();
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
void
|
||||
MacIOSurfaceImage::SetData(const Data& aData)
|
||||
{
|
||||
mIOSurface = MacIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
|
||||
mSize = gfxIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
MacIOSurfaceImage::GetAsSurface()
|
||||
{
|
||||
mIOSurface->Lock();
|
||||
size_t bytesPerRow = mIOSurface->GetBytesPerRow();
|
||||
size_t ioWidth = mIOSurface->GetWidth();
|
||||
size_t ioHeight = mIOSurface->GetHeight();
|
||||
|
||||
unsigned char* ioData = (unsigned char*)mIOSurface->GetBaseAddress();
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface(gfxIntSize(ioWidth, ioHeight), gfxASurface::ImageFormatARGB32);
|
||||
|
||||
for (int i = 0; i < ioHeight; i++) {
|
||||
memcpy(imgSurface->Data() + i * imgSurface->Stride(),
|
||||
ioData + i * bytesPerRow, ioWidth * 4);
|
||||
}
|
||||
|
||||
mIOSurface->Unlock();
|
||||
|
||||
return imgSurface.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceImage::Update(ImageContainer* aContainer)
|
||||
{
|
||||
if (mUpdateCallback) {
|
||||
mUpdateCallback(aContainer, mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
RemoteBitmapImage::GetAsSurface()
|
||||
{
|
||||
nsRefPtr<gfxImageSurface> newSurf =
|
||||
new gfxImageSurface(mSize,
|
||||
mFormat == RemoteImageData::BGRX32 ? gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32);
|
||||
|
||||
for (int y = 0; y < mSize.height; y++) {
|
||||
memcpy(newSurf->Data() + newSurf->Stride() * y,
|
||||
mData + mStride * y,
|
||||
mSize.width * 4);
|
||||
}
|
||||
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
830
gfx/layers/ImageContainer.h
Normal file
830
gfx/layers/ImageContainer.h
Normal file
@ -0,0 +1,830 @@
|
||||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef GFX_IMAGECONTAINER_H
|
||||
#define GFX_IMAGECONTAINER_H
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "gfxASurface.h" // for gfxImageFormat
|
||||
#include "LayersTypes.h" // for LayersBackend
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "ImageTypes.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
struct ID3D10Texture2D;
|
||||
struct ID3D10Device;
|
||||
struct ID3D10ShaderResourceView;
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
# include <ui/GraphicBuffer.h>
|
||||
#endif
|
||||
|
||||
typedef void* HANDLE;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CrossProcessMutex;
|
||||
namespace ipc {
|
||||
class Shmem;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class ImageContainerChild;
|
||||
|
||||
struct ImageBackendData
|
||||
{
|
||||
virtual ~ImageBackendData() {}
|
||||
|
||||
protected:
|
||||
ImageBackendData() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class representing a buffer of pixel data. The data can be in one
|
||||
* of various formats including YCbCr.
|
||||
*
|
||||
* Create an image using an ImageContainer. Fill the image with data, and
|
||||
* then call ImageContainer::SetImage to display it. An image must not be
|
||||
* modified after calling SetImage. Image implementations do not need to
|
||||
* perform locking; when filling an Image, the Image client is responsible
|
||||
* for ensuring only one thread accesses the Image at a time, and after
|
||||
* SetImage the image is immutable.
|
||||
*
|
||||
* When resampling an Image, only pixels within the buffer should be
|
||||
* sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
|
||||
*/
|
||||
class THEBES_API Image {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image)
|
||||
|
||||
public:
|
||||
virtual ~Image() {}
|
||||
|
||||
|
||||
ImageFormat GetFormat() { return mFormat; }
|
||||
void* GetImplData() { return mImplData; }
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
|
||||
virtual gfxIntSize GetSize() = 0;
|
||||
|
||||
ImageBackendData* GetBackendData(LayersBackend aBackend)
|
||||
{ return mBackendData[aBackend]; }
|
||||
void SetBackendData(LayersBackend aBackend, ImageBackendData* aData)
|
||||
{ mBackendData[aBackend] = aData; }
|
||||
|
||||
protected:
|
||||
Image(void* aImplData, ImageFormat aFormat) :
|
||||
mImplData(aImplData),
|
||||
mFormat(aFormat)
|
||||
{}
|
||||
|
||||
nsAutoPtr<ImageBackendData> mBackendData[mozilla::layers::LAYERS_LAST];
|
||||
|
||||
void* mImplData;
|
||||
ImageFormat mFormat;
|
||||
};
|
||||
|
||||
/**
|
||||
* A RecycleBin is owned by an ImageContainer. We store buffers in it that we
|
||||
* want to recycle from one image to the next.It's a separate object from
|
||||
* ImageContainer because images need to store a strong ref to their RecycleBin
|
||||
* and we must avoid creating a reference loop between an ImageContainer and
|
||||
* its active image.
|
||||
*/
|
||||
class BufferRecycleBin {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin)
|
||||
|
||||
//typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
public:
|
||||
BufferRecycleBin();
|
||||
|
||||
void RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize);
|
||||
// Returns a recycled buffer of the right size, or allocates a new buffer.
|
||||
PRUint8* GetBuffer(PRUint32 aSize);
|
||||
|
||||
private:
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
// This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures
|
||||
// and mRecycledTextureSizes
|
||||
Mutex mLock;
|
||||
|
||||
// We should probably do something to prune this list on a timer so we don't
|
||||
// eat excess memory while video is paused...
|
||||
nsTArray<nsAutoArrayPtr<PRUint8> > mRecycledBuffers;
|
||||
// This is only valid if mRecycledBuffers is non-empty
|
||||
PRUint32 mRecycledBufferSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if aFormat is in the given format array.
|
||||
*/
|
||||
static inline bool
|
||||
FormatInList(const ImageFormat* aFormats, PRUint32 aNumFormats,
|
||||
ImageFormat aFormat)
|
||||
{
|
||||
for (PRUint32 i = 0; i < aNumFormats; ++i) {
|
||||
if (aFormats[i] == aFormat) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class CompositionNotifySink
|
||||
{
|
||||
public:
|
||||
virtual void DidComposite() = 0;
|
||||
virtual ~CompositionNotifySink() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that manages Image creation for a LayerManager. The only reason
|
||||
* we need a separate class here is that LayerMananers aren't threadsafe
|
||||
* (because layers can only be used on the main thread) and we want to
|
||||
* be able to create images from any thread, to facilitate video playback
|
||||
* without involving the main thread, for example.
|
||||
* Different layer managers can implement child classes of this making it
|
||||
* possible to create layer manager specific images.
|
||||
* This class is not meant to be used directly but rather can be set on an
|
||||
* image container. This is usually done by the layer system internally and
|
||||
* not explicitly by users. For PlanarYCbCr or Cairo images the default
|
||||
* implementation will creates images whose data lives in system memory, for
|
||||
* MacIOSurfaces the default implementation will be a simple MacIOSurface
|
||||
* wrapper.
|
||||
*/
|
||||
|
||||
class THEBES_API ImageFactory
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory)
|
||||
protected:
|
||||
friend class ImageContainer;
|
||||
|
||||
ImageFactory() {}
|
||||
virtual ~ImageFactory() {}
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(const ImageFormat* aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &aScaleHint,
|
||||
BufferRecycleBin *aRecycleBin);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This struct is used to store RemoteImages, it is meant to be able to live in
|
||||
* shared memory. Therefor it should not contain a vtable pointer. Remote
|
||||
* users can manipulate the data in this structure to specify what image is to
|
||||
* be drawn by the container. When accessing this data users should make sure
|
||||
* the mutex synchronizing access to the structure is held!
|
||||
*/
|
||||
struct RemoteImageData {
|
||||
enum Type {
|
||||
/**
|
||||
* This is a format that uses raw bitmap data.
|
||||
*/
|
||||
RAW_BITMAP,
|
||||
|
||||
/**
|
||||
* This is a format that uses a pointer to a texture do draw directly
|
||||
* from a shared texture. Any process may have created this texture handle,
|
||||
* the process creating the texture handle is responsible for managing it's
|
||||
* lifetime by managing the lifetime of the first D3D texture object this
|
||||
* handle was created for. It must also ensure the handle is not set
|
||||
* current anywhere when the last reference to this object is released.
|
||||
*/
|
||||
DXGI_TEXTURE_HANDLE
|
||||
};
|
||||
/* These formats describe the format in the memory byte-order */
|
||||
enum Format {
|
||||
/* 8 bits per channel */
|
||||
BGRA32,
|
||||
/* 8 bits per channel, alpha channel is ignored */
|
||||
BGRX32
|
||||
};
|
||||
|
||||
// This should be set to true if a change was made so that the ImageContainer
|
||||
// knows to throw out any cached RemoteImage objects.
|
||||
bool mWasUpdated;
|
||||
Type mType;
|
||||
Format mFormat;
|
||||
gfxIntSize mSize;
|
||||
union {
|
||||
struct {
|
||||
/* This pointer is set by a remote process, however it will be set to
|
||||
* the container process' address the memory of the raw bitmap resides
|
||||
* at.
|
||||
*/
|
||||
unsigned char *mData;
|
||||
int mStride;
|
||||
} mBitmap;
|
||||
#ifdef XP_WIN
|
||||
HANDLE mTextureHandle;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that manages Images for an ImageLayer. The only reason
|
||||
* we need a separate class here is that ImageLayers aren't threadsafe
|
||||
* (because layers can only be used on the main thread) and we want to
|
||||
* be able to set the current Image from any thread, to facilitate
|
||||
* video playback without involving the main thread, for example.
|
||||
*
|
||||
* An ImageContainer can operate in one of three modes:
|
||||
* 1) Normal. Triggered by constructing the ImageContainer with
|
||||
* DISABLE_ASYNC or when compositing is happening on the main thread.
|
||||
* SetCurrentImage changes ImageContainer state but nothing is sent to the
|
||||
* compositor until the next layer transaction.
|
||||
* 2) Asynchronous. Initiated by constructing the ImageContainer with
|
||||
* ENABLE_ASYNC when compositing is happening on the main thread.
|
||||
* SetCurrentImage sends a message through the ImageBridge to the compositor
|
||||
* thread to update the image, without going through the main thread or
|
||||
* a layer transaction.
|
||||
* 3) Remote. Initiated by calling SetRemoteImageData on the ImageContainer
|
||||
* before any other activity.
|
||||
* The ImageContainer uses a shared memory block containing a cross-process mutex
|
||||
* to communicate with the compositor thread. SetCurrentImage synchronously
|
||||
* updates the shared state to point to the new image and the old image
|
||||
* is immediately released (not true in Normal or Asynchronous modes).
|
||||
*/
|
||||
class THEBES_API ImageContainer {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
|
||||
public:
|
||||
|
||||
enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
|
||||
|
||||
ImageContainer(int flag = 0);
|
||||
|
||||
~ImageContainer();
|
||||
|
||||
/**
|
||||
* Create an Image in one of the given formats.
|
||||
* Picks the "best" format from the list and creates an Image of that
|
||||
* format.
|
||||
* Returns null if this backend does not support any of the formats.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
already_AddRefed<Image> CreateImage(const ImageFormat* aFormats,
|
||||
PRUint32 aNumFormats);
|
||||
|
||||
/**
|
||||
* Set an Image as the current image to display. The Image must have
|
||||
* been created by this ImageContainer.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* aImage can be null. While it's null, nothing will be painted.
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
* Note that this must not be called if ENABLE_ASYNC has not been set.
|
||||
*
|
||||
* Implementations must call CurrentImageChanged() while holding
|
||||
* mReentrantMonitor.
|
||||
*
|
||||
* If this ImageContainer has an ImageContainerChild for async video:
|
||||
* Schelude a task to send the image to the compositor using the
|
||||
* PImageBridge protcol without using the main thread.
|
||||
*/
|
||||
void SetCurrentImage(Image* aImage);
|
||||
|
||||
/**
|
||||
* Set an Image as the current image to display. The Image must have
|
||||
* been created by this ImageContainer.
|
||||
* Must be called on the main thread, within a layers transaction.
|
||||
*
|
||||
* This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* aImage can be null. While it's null, nothing will be painted.
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
* Note that this must not be called if ENABLE_ASYNC been set.
|
||||
*
|
||||
* Implementations must call CurrentImageChanged() while holding
|
||||
* mReentrantMonitor.
|
||||
*/
|
||||
void SetCurrentImageInTransaction(Image* aImage);
|
||||
|
||||
/**
|
||||
* Returns true if this ImageContainer uses the ImageBridge IPDL protocol.
|
||||
*
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
bool IsAsync() const;
|
||||
|
||||
/**
|
||||
* If this ImageContainer uses ImageBridge, returns the ID associated to
|
||||
* this container, for use in the ImageBridge protocol.
|
||||
* Returns 0 if this ImageContainer does not use ImageBridge. Note that
|
||||
* 0 is always an invalid ID for asynchronous image containers.
|
||||
*
|
||||
* Can be called from ay thread.
|
||||
*/
|
||||
PRUint64 GetAsyncContainerID() const;
|
||||
|
||||
/**
|
||||
* Returns if the container currently has an image.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
bool HasCurrentImage();
|
||||
|
||||
/**
|
||||
* Lock the current Image.
|
||||
* This has to add a reference since otherwise there are race conditions
|
||||
* where the current image is destroyed before the caller can add
|
||||
* a reference. This lock strictly guarantees the underlying image remains
|
||||
* valid, it does not mean the current image cannot change.
|
||||
* Can be called on any thread. This method will lock the cross-process
|
||||
* mutex to ensure remote processes cannot alter underlying data. This call
|
||||
* -must- be balanced by a call to UnlockCurrentImage and users should avoid
|
||||
* holding the image locked for a long time.
|
||||
*/
|
||||
already_AddRefed<Image> LockCurrentImage();
|
||||
|
||||
/**
|
||||
* This call unlocks the image. For remote images releasing the cross-process
|
||||
* mutex.
|
||||
*/
|
||||
void UnlockCurrentImage();
|
||||
|
||||
/**
|
||||
* Get the current image as a gfxASurface. This is useful for fallback
|
||||
* rendering.
|
||||
* This can only be called from the main thread, since cairo objects
|
||||
* can only be used from the main thread.
|
||||
* This is defined here and not on Image because it's possible (likely)
|
||||
* that some backends will make an Image "ready to draw" only when it
|
||||
* becomes the current image for an image container.
|
||||
* Returns null if there is no current image.
|
||||
* Returns the size in aSize.
|
||||
* The returned surface will never be modified. The caller must not
|
||||
* modify it.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* If the current image is a remote image, that is, if it is an image that
|
||||
* may be shared accross processes, calling this function will make
|
||||
* a copy of the image data while holding the mRemoteDataMutex. If possible,
|
||||
* the lock methods should be used to avoid the copy, however this should be
|
||||
* avoided if the surface is required for a long period of time.
|
||||
*/
|
||||
already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult);
|
||||
|
||||
/**
|
||||
* This is similar to GetCurrentAsSurface, however this does not make a copy
|
||||
* of the image data and requires the user to call UnlockCurrentImage when
|
||||
* done with the image data. Once UnlockCurrentImage has been called the
|
||||
* surface returned by this function is no longer valid! This works for any
|
||||
* type of image. Optionally a pointer can be passed to receive the current
|
||||
* image.
|
||||
*/
|
||||
already_AddRefed<gfxASurface> LockCurrentAsSurface(gfxIntSize* aSizeResult,
|
||||
Image** aCurrentImage = nullptr);
|
||||
|
||||
/**
|
||||
* Returns the size of the image in pixels.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor when accessing
|
||||
* thread-shared state.
|
||||
*/
|
||||
gfxIntSize GetCurrentSize();
|
||||
|
||||
/**
|
||||
* Sets a size that the image is expected to be rendered at.
|
||||
* This is a hint for image backends to optimize scaling.
|
||||
* Default implementation in this class is to ignore the hint.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
void SetScaleHint(const gfxIntSize& aScaleHint)
|
||||
{ mScaleHint = aScaleHint; }
|
||||
|
||||
void SetImageFactory(ImageFactory *aFactory)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mImageFactory = aFactory ? aFactory : new ImageFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which the currently contained image was first
|
||||
* painted. This is reset every time a new image is set as the current
|
||||
* image. Note this may return a null timestamp if the current image
|
||||
* has not yet been painted. Can be called from any thread.
|
||||
*/
|
||||
TimeStamp GetPaintTime() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mPaintTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of images which have been contained in this container
|
||||
* and painted at least once. Can be called from any thread.
|
||||
*/
|
||||
PRUint32 GetPaintCount() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mPaintCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments mPaintCount if this is the first time aPainted has been
|
||||
* painted, and sets mPaintTime if the painted image is the current image.
|
||||
* current image. Can be called from any thread.
|
||||
*/
|
||||
void NotifyPaintedImage(Image* aPainted) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
nsRefPtr<Image> current = mActiveImage;
|
||||
if (aPainted == current) {
|
||||
if (mPaintTime.IsNull()) {
|
||||
mPaintTime = TimeStamp::Now();
|
||||
mPaintCount++;
|
||||
}
|
||||
} else if (!mPreviousImagePainted) {
|
||||
// While we were painting this image, the current image changed. We
|
||||
// still must count it as painted, but can't set mPaintTime, since we're
|
||||
// no longer the current image.
|
||||
mPaintCount++;
|
||||
mPreviousImagePainted = true;
|
||||
}
|
||||
|
||||
if (mCompositionNotifySink) {
|
||||
mCompositionNotifySink->DidComposite();
|
||||
}
|
||||
}
|
||||
|
||||
void SetCompositionNotifySink(CompositionNotifySink *aSink) {
|
||||
mCompositionNotifySink = aSink;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called to tell the ImageContainer where the
|
||||
* (cross-process) segment lives where the shared data about possible
|
||||
* remote images are stored. In addition to this a CrossProcessMutex object
|
||||
* is passed telling the container how to synchronize access to this data.
|
||||
* NOTE: This should be called during setup of the container and not after
|
||||
* usage has started.
|
||||
*/
|
||||
void SetRemoteImageData(RemoteImageData *aRemoteData,
|
||||
CrossProcessMutex *aRemoteDataMutex);
|
||||
/**
|
||||
* This can be used to check if the container has RemoteData set.
|
||||
*/
|
||||
RemoteImageData *GetRemoteImageData() { return mRemoteData; }
|
||||
|
||||
protected:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
|
||||
void SetCurrentImageInternal(Image* aImage);
|
||||
|
||||
// This is called to ensure we have an active image, this may not be true
|
||||
// when we're storing image information in a RemoteImageData structure.
|
||||
// NOTE: If we have remote data mRemoteDataMutex should be locked when
|
||||
// calling this function!
|
||||
void EnsureActiveImage();
|
||||
|
||||
// ReentrantMonitor to protect thread safe access to the "current
|
||||
// image", and any other state which is shared between threads.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
// Performs necessary housekeeping to ensure the painted frame statistics
|
||||
// are accurate. Must be called by SetCurrentImage() implementations with
|
||||
// mReentrantMonitor held.
|
||||
void CurrentImageChanged() {
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
mPreviousImagePainted = !mPaintTime.IsNull();
|
||||
mPaintTime = TimeStamp();
|
||||
}
|
||||
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
|
||||
// Number of contained images that have been painted at least once. It's up
|
||||
// to the ImageContainer implementation to ensure accesses to this are
|
||||
// threadsafe.
|
||||
PRUint32 mPaintCount;
|
||||
|
||||
// Time stamp at which the current image was first painted. It's up to the
|
||||
// ImageContainer implementation to ensure accesses to this are threadsafe.
|
||||
TimeStamp mPaintTime;
|
||||
|
||||
// Denotes whether the previous image was painted.
|
||||
bool mPreviousImagePainted;
|
||||
|
||||
// This is the image factory used by this container, layer managers using
|
||||
// this container can set an alternative image factory that will be used to
|
||||
// create images for this container.
|
||||
nsRefPtr<ImageFactory> mImageFactory;
|
||||
|
||||
gfxIntSize mScaleHint;
|
||||
|
||||
nsRefPtr<BufferRecycleBin> mRecycleBin;
|
||||
|
||||
// This contains the remote image data for this container, if this is NULL
|
||||
// that means the container has no other process that may control its active
|
||||
// image.
|
||||
RemoteImageData *mRemoteData;
|
||||
|
||||
// This cross-process mutex is used to synchronise access to mRemoteData.
|
||||
// When this mutex is held, we will always be inside the mReentrantMonitor
|
||||
// however the same is not true vice versa.
|
||||
CrossProcessMutex *mRemoteDataMutex;
|
||||
|
||||
CompositionNotifySink *mCompositionNotifySink;
|
||||
|
||||
// This member points to an ImageContainerChild if this ImageContainer was
|
||||
// sucessfully created with ENABLE_ASYNC, or points to null otherwise.
|
||||
// 'unsuccessful' in this case only means that the ImageContainerChild could not
|
||||
// be created, most likely because off-main-thread compositing is not enabled.
|
||||
// In this case the ImageContainer is perfectly usable, but it will forward
|
||||
// frames to the compositor through transactions in the main thread rather than
|
||||
// asynchronusly using the ImageBridge IPDL protocol.
|
||||
nsRefPtr<ImageContainerChild> mImageContainerChild;
|
||||
};
|
||||
|
||||
class AutoLockImage
|
||||
{
|
||||
public:
|
||||
AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
|
||||
AutoLockImage(ImageContainer *aContainer, gfxASurface **aSurface) : mContainer(aContainer) {
|
||||
*aSurface = mContainer->LockCurrentAsSurface(&mSize, getter_AddRefs(mImage)).get();
|
||||
}
|
||||
~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
|
||||
|
||||
Image* GetImage() { return mImage; }
|
||||
const gfxIntSize &GetSize() { return mSize; }
|
||||
|
||||
void Unlock() {
|
||||
if (mContainer) {
|
||||
mImage = nullptr;
|
||||
mContainer->UnlockCurrentImage();
|
||||
mContainer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Things get a little tricky here, because our underlying image can -still-
|
||||
* change, and OS X requires a complicated callback mechanism to update this
|
||||
* we need to support staying the lock and getting the new image in a proper
|
||||
* way. This method makes any images retrieved with GetImage invalid!
|
||||
*/
|
||||
void Refresh() {
|
||||
if (mContainer) {
|
||||
mContainer->UnlockCurrentImage();
|
||||
mImage = mContainer->LockCurrentImage();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ImageContainer *mContainer;
|
||||
nsRefPtr<Image> mImage;
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
|
||||
/****** Image subtypes for the different formats ******/
|
||||
|
||||
/**
|
||||
* We assume that the image data is in the REC 470M color space (see
|
||||
* Theora specification, section 4.3.1).
|
||||
*
|
||||
* The YCbCr format can be:
|
||||
*
|
||||
* 4:4:4 - CbCr width/height are the same as Y.
|
||||
* 4:2:2 - CbCr width is half that of Y. Height is the same.
|
||||
* 4:2:0 - CbCr width and height is half that of Y.
|
||||
*
|
||||
* The color format is detected based on the height/width ratios
|
||||
* defined above.
|
||||
*
|
||||
* The Image that is rendered is the picture region defined by
|
||||
* mPicX, mPicY and mPicSize. The size of the rendered image is
|
||||
* mPicSize, not mYSize or mCbCrSize.
|
||||
*/
|
||||
class THEBES_API PlanarYCbCrImage : public Image {
|
||||
public:
|
||||
struct Data {
|
||||
// Luminance buffer
|
||||
PRUint8* mYChannel;
|
||||
PRInt32 mYStride;
|
||||
gfxIntSize mYSize;
|
||||
// Chroma buffers
|
||||
PRUint8* mCbChannel;
|
||||
PRUint8* mCrChannel;
|
||||
PRInt32 mCbCrStride;
|
||||
gfxIntSize mCbCrSize;
|
||||
// Picture region
|
||||
PRUint32 mPicX;
|
||||
PRUint32 mPicY;
|
||||
gfxIntSize mPicSize;
|
||||
StereoMode mStereoMode;
|
||||
|
||||
nsIntRect GetPictureRect() const {
|
||||
return nsIntRect(mPicX, mPicY,
|
||||
mPicSize.width,
|
||||
mPicSize.height);
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_DIMENSION = 16384
|
||||
};
|
||||
|
||||
~PlanarYCbCrImage();
|
||||
|
||||
/**
|
||||
* This makes a copy of the data buffers, in order to support functioning
|
||||
* in all different layer managers.
|
||||
*/
|
||||
virtual void SetData(const Data& aData);
|
||||
|
||||
/**
|
||||
* Ask this Image to not convert YUV to RGB during SetData, and make
|
||||
* the original data available through GetData. This is optional,
|
||||
* and not all PlanarYCbCrImages will support it.
|
||||
*/
|
||||
virtual void SetDelayedConversion(bool aDelayed) { }
|
||||
|
||||
/**
|
||||
* Grab the original YUV data. This is optional.
|
||||
*/
|
||||
virtual const Data* GetData() { return &mData; }
|
||||
|
||||
/**
|
||||
* Make a copy of the YCbCr data into local storage.
|
||||
*
|
||||
* @param aData Input image data.
|
||||
* @param aYOffset Pixels to skip between lines in the Y plane.
|
||||
* @param aYSkip Pixels to skip between pixels in the Y plane.
|
||||
* @param aCbOffset Pixels to skip between lines in the Cb plane.
|
||||
* @param aCbSkip Pixels to skip between pixels in the Cb plane.
|
||||
* @param aCrOffset Pixels to skip between lines in the Cr plane.
|
||||
* @param aCrSkip Pixels to skip between pixels in the Cr plane.
|
||||
*/
|
||||
void CopyData(const Data& aData,
|
||||
PRInt32 aYOffset = 0, PRInt32 aYSkip = 0,
|
||||
PRInt32 aCbOffset = 0, PRInt32 aCbSkip = 0,
|
||||
PRInt32 aCrOffset = 0, PRInt32 aCrSkip = 0);
|
||||
|
||||
/**
|
||||
* Return a buffer to store image data in.
|
||||
* The default implementation returns memory that can
|
||||
* be freed wit delete[]
|
||||
*/
|
||||
virtual PRUint8* AllocateBuffer(PRUint32 aSize);
|
||||
|
||||
/**
|
||||
* Return the number of bytes of heap memory used to store this image.
|
||||
*/
|
||||
virtual PRUint32 GetDataSize() { return mBufferSize; }
|
||||
|
||||
already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
virtual gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
void SetOffscreenFormat(gfxASurface::gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
|
||||
gfxASurface::gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
|
||||
|
||||
// XXX - not easy to protect these sadly.
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferSize;
|
||||
Data mData;
|
||||
gfxIntSize mSize;
|
||||
gfxASurface::gfxImageFormat mOffscreenFormat;
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
nsRefPtr<BufferRecycleBin> mRecycleBin;
|
||||
|
||||
PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
|
||||
};
|
||||
|
||||
/**
|
||||
* Currently, the data in a CairoImage surface is treated as being in the
|
||||
* device output color space. This class is very simple as all backends
|
||||
* have to know about how to deal with drawing a cairo image.
|
||||
*/
|
||||
class THEBES_API CairoImage : public Image {
|
||||
public:
|
||||
struct Data {
|
||||
gfxASurface* mSurface;
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* This can only be called on the main thread. It may add a reference
|
||||
* to the surface (which will eventually be released on the main thread).
|
||||
* The surface must not be modified after this call!!!
|
||||
*/
|
||||
void SetData(const Data& aData)
|
||||
{
|
||||
mSurface = aData.mSurface;
|
||||
mSize = aData.mSize;
|
||||
}
|
||||
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
|
||||
nsRefPtr<gfxASurface> surface = mSurface.get();
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
CairoImage() : Image(NULL, CAIRO_SURFACE) {}
|
||||
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
class THEBES_API MacIOSurfaceImage : public Image {
|
||||
public:
|
||||
struct Data {
|
||||
MacIOSurface* mIOSurface;
|
||||
};
|
||||
|
||||
MacIOSurfaceImage()
|
||||
: Image(NULL, MAC_IO_SURFACE)
|
||||
, mSize(0, 0)
|
||||
, mPluginInstanceOwner(NULL)
|
||||
, mUpdateCallback(NULL)
|
||||
, mDestroyCallback(NULL)
|
||||
{}
|
||||
|
||||
virtual ~MacIOSurfaceImage()
|
||||
{
|
||||
if (mDestroyCallback) {
|
||||
mDestroyCallback(mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This can only be called on the main thread. It may add a reference
|
||||
* to the surface (which will eventually be released on the main thread).
|
||||
* The surface must not be modified after this call!!!
|
||||
*/
|
||||
virtual void SetData(const Data& aData);
|
||||
|
||||
/**
|
||||
* Temporary hacks to force plugin drawing during an empty transaction.
|
||||
* This should not be used for anything else, and will be removed
|
||||
* when async plugin rendering is complete.
|
||||
*/
|
||||
typedef void (*UpdateSurfaceCallback)(ImageContainer* aContainer, void* aInstanceOwner);
|
||||
virtual void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aInstanceOwner)
|
||||
{
|
||||
mUpdateCallback = aCallback;
|
||||
mPluginInstanceOwner = aInstanceOwner;
|
||||
}
|
||||
|
||||
typedef void (*DestroyCallback)(void* aInstanceOwner);
|
||||
virtual void SetDestroyCallback(DestroyCallback aCallback)
|
||||
{
|
||||
mDestroyCallback = aCallback;
|
||||
}
|
||||
|
||||
virtual gfxIntSize GetSize()
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
MacIOSurface* GetIOSurface()
|
||||
{
|
||||
return mIOSurface;
|
||||
}
|
||||
|
||||
void Update(ImageContainer* aContainer);
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
private:
|
||||
gfxIntSize mSize;
|
||||
RefPtr<MacIOSurface> mIOSurface;
|
||||
void* mPluginInstanceOwner;
|
||||
UpdateSurfaceCallback mUpdateCallback;
|
||||
DestroyCallback mDestroyCallback;
|
||||
};
|
||||
#endif
|
||||
|
||||
class RemoteBitmapImage : public Image {
|
||||
public:
|
||||
RemoteBitmapImage() : Image(NULL, REMOTE_IMAGE_BITMAP) {}
|
||||
|
||||
already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
unsigned char *mData;
|
||||
int mStride;
|
||||
gfxIntSize mSize;
|
||||
RemoteImageData::Format mFormat;
|
||||
};
|
||||
|
||||
|
||||
} //namespace
|
||||
} //namespace
|
||||
|
||||
#endif
|
@ -3,545 +3,41 @@
|
||||
* 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/ipc/Shmem.h"
|
||||
#include "mozilla/ipc/CrossProcessMutex.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "SharedTextureImage.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxSharedImageSurface.h"
|
||||
#include "yuv_convert.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/ImageContainerChild.h"
|
||||
#include "GonkIOSurfaceImage.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "mozilla/gfx/QuartzSupport.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "gfxD2DSurface.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include <d3d10_1.h>
|
||||
|
||||
#include "d3d10/ImageLayerD3D10.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using mozilla::gfx::DataSourceSurface;
|
||||
using mozilla::gfx::SourceSurface;
|
||||
#include "ImageContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageFactory::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &,
|
||||
BufferRecycleBin *aRecycleBin)
|
||||
ImageLayer::ImageLayer(LayerManager* aManager, void* aImplData)
|
||||
: Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD)
|
||||
, mScaleMode(SCALE_NONE), mForceSingleTile(false)
|
||||
{}
|
||||
|
||||
ImageLayer::~ImageLayer()
|
||||
{}
|
||||
|
||||
void ImageLayer::SetContainer(ImageContainer* aContainer)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nullptr;
|
||||
mContainer = aContainer;
|
||||
}
|
||||
|
||||
void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
{
|
||||
// Snap image edges to pixel boundaries
|
||||
gfxRect snap(0, 0, 0, 0);
|
||||
if (mContainer) {
|
||||
gfxIntSize size = mContainer->GetCurrentSize();
|
||||
snap.SizeTo(gfxSize(size.width, size.height));
|
||||
}
|
||||
nsRefPtr<Image> img;
|
||||
if (FormatInList(aFormats, aNumFormats, Image::PLANAR_YCBCR)) {
|
||||
img = new PlanarYCbCrImage(aRecycleBin);
|
||||
} else if (FormatInList(aFormats, aNumFormats, Image::CAIRO_SURFACE)) {
|
||||
img = new CairoImage();
|
||||
} else if (FormatInList(aFormats, aNumFormats, Image::SHARED_TEXTURE)) {
|
||||
img = new SharedTextureImage();
|
||||
#ifdef XP_MACOSX
|
||||
} else if (FormatInList(aFormats, aNumFormats, Image::MAC_IO_SURFACE)) {
|
||||
img = new MacIOSurfaceImage();
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
} else if (FormatInList(aFormats, aNumFormats, Image::GONK_IO_SURFACE)) {
|
||||
img = new GonkIOSurfaceImage();
|
||||
#endif
|
||||
}
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
BufferRecycleBin::BufferRecycleBin()
|
||||
: mLock("mozilla.layers.BufferRecycleBin.mLock")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BufferRecycleBin::RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) {
|
||||
mRecycledBuffers.Clear();
|
||||
}
|
||||
mRecycledBufferSize = aSize;
|
||||
mRecycledBuffers.AppendElement(aBuffer);
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
BufferRecycleBin::GetBuffer(PRUint32 aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize)
|
||||
return new PRUint8[aSize];
|
||||
|
||||
PRUint32 last = mRecycledBuffers.Length() - 1;
|
||||
PRUint8* result = mRecycledBuffers[last].forget();
|
||||
mRecycledBuffers.RemoveElementAt(last);
|
||||
return result;
|
||||
}
|
||||
|
||||
ImageContainer::ImageContainer(int flag)
|
||||
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
|
||||
mPaintCount(0),
|
||||
mPreviousImagePainted(false),
|
||||
mImageFactory(new ImageFactory()),
|
||||
mRecycleBin(new BufferRecycleBin()),
|
||||
mRemoteData(nullptr),
|
||||
mRemoteDataMutex(nullptr),
|
||||
mCompositionNotifySink(nullptr),
|
||||
mImageContainerChild(nullptr)
|
||||
{
|
||||
if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) {
|
||||
mImageContainerChild =
|
||||
ImageBridgeChild::GetSingleton()->CreateImageContainerChild();
|
||||
}
|
||||
}
|
||||
|
||||
ImageContainer::~ImageContainer()
|
||||
{
|
||||
if (mImageContainerChild) {
|
||||
mImageContainerChild->DispatchStop();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainer::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mImageFactory->CreateImage(aFormats, aNumFormats, mScaleHint, mRecycleBin);
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetCurrentImageInternal(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Lock();
|
||||
// This is important since it ensures we won't change the active image
|
||||
// when we currently have a locked image that depends on mRemoteData.
|
||||
}
|
||||
|
||||
mActiveImage = aImage;
|
||||
CurrentImageChanged();
|
||||
|
||||
if (mRemoteData) {
|
||||
mRemoteDataMutex->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetCurrentImage(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mImageContainerChild) {
|
||||
if (aImage) {
|
||||
mImageContainerChild->SendImageAsync(this, aImage);
|
||||
} else {
|
||||
mImageContainerChild->DispatchSetIdle();
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentImageInternal(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetCurrentImageInTransaction(Image *aImage)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
NS_ASSERTION(!mImageContainerChild, "Should use async image transfer with ImageBridge.");
|
||||
|
||||
SetCurrentImageInternal(aImage);
|
||||
}
|
||||
|
||||
bool ImageContainer::IsAsync() const {
|
||||
return mImageContainerChild != nullptr;
|
||||
}
|
||||
|
||||
PRUint64 ImageContainer::GetAsyncContainerID() const
|
||||
{
|
||||
NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers");
|
||||
if (IsAsync()) {
|
||||
return mImageContainerChild->GetID();
|
||||
} else {
|
||||
return 0; // zero is always an invalid SharedImageID
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ImageContainer::HasCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
|
||||
|
||||
EnsureActiveImage();
|
||||
|
||||
return !!mActiveImage.get();
|
||||
}
|
||||
|
||||
return !!mActiveImage.get();
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainer::LockCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Lock();
|
||||
}
|
||||
|
||||
EnsureActiveImage();
|
||||
|
||||
nsRefPtr<Image> retval = mActiveImage;
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainer::LockCurrentAsSurface(gfxIntSize *aSize, Image** aCurrentImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Lock();
|
||||
|
||||
EnsureActiveImage();
|
||||
|
||||
if (aCurrentImage) {
|
||||
NS_IF_ADDREF(mActiveImage);
|
||||
*aCurrentImage = mActiveImage.get();
|
||||
}
|
||||
|
||||
if (!mActiveImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mActiveImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
|
||||
nsRefPtr<gfxImageSurface> newSurf =
|
||||
new gfxImageSurface(mRemoteData->mBitmap.mData, mRemoteData->mSize, mRemoteData->mBitmap.mStride,
|
||||
mRemoteData->mFormat == RemoteImageData::BGRX32 ?
|
||||
gfxASurface::ImageFormatARGB32 :
|
||||
gfxASurface::ImageFormatRGB24);
|
||||
|
||||
*aSize = newSurf->GetSize();
|
||||
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
*aSize = mActiveImage->GetSize();
|
||||
return mActiveImage->GetAsSurface();
|
||||
}
|
||||
|
||||
if (aCurrentImage) {
|
||||
NS_IF_ADDREF(mActiveImage);
|
||||
*aCurrentImage = mActiveImage.get();
|
||||
}
|
||||
|
||||
if (!mActiveImage) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*aSize = mActiveImage->GetSize();
|
||||
return mActiveImage->GetAsSurface();
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::UnlockCurrentImage()
|
||||
{
|
||||
if (mRemoteData) {
|
||||
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
|
||||
mRemoteDataMutex->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
|
||||
EnsureActiveImage();
|
||||
|
||||
if (!mActiveImage)
|
||||
return nullptr;
|
||||
*aSize = mRemoteData->mSize;
|
||||
} else {
|
||||
if (!mActiveImage)
|
||||
return nullptr;
|
||||
*aSize = mActiveImage->GetSize();
|
||||
}
|
||||
return mActiveImage->GetAsSurface();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
ImageContainer::GetCurrentSize()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mRemoteData) {
|
||||
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
|
||||
|
||||
// We don't need to ensure we have an active image here, as we need to
|
||||
// be in the mutex anyway, and this is easiest to return from there.
|
||||
return mRemoteData->mSize;
|
||||
}
|
||||
|
||||
if (!mActiveImage) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
|
||||
return mActiveImage->GetSize();
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
NS_ASSERTION(!mActiveImage || !aData, "No active image expected when SetRemoteImageData is called with non-NULL aData.");
|
||||
NS_ASSERTION(!mRemoteData || !aData, "No remote data expected when SetRemoteImageData is called with non-NULL aData.");
|
||||
|
||||
mRemoteData = aData;
|
||||
|
||||
if (aData) {
|
||||
memset(aData, 0, sizeof(RemoteImageData));
|
||||
} else {
|
||||
mActiveImage = nullptr;
|
||||
}
|
||||
|
||||
mRemoteDataMutex = aMutex;
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::EnsureActiveImage()
|
||||
{
|
||||
if (mRemoteData) {
|
||||
if (mRemoteData->mWasUpdated) {
|
||||
mActiveImage = nullptr;
|
||||
}
|
||||
|
||||
if (mRemoteData->mType == RemoteImageData::RAW_BITMAP &&
|
||||
mRemoteData->mBitmap.mData && !mActiveImage) {
|
||||
nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage();
|
||||
|
||||
newImg->mFormat = mRemoteData->mFormat;
|
||||
newImg->mData = mRemoteData->mBitmap.mData;
|
||||
newImg->mSize = mRemoteData->mSize;
|
||||
newImg->mStride = mRemoteData->mBitmap.mStride;
|
||||
mRemoteData->mWasUpdated = false;
|
||||
|
||||
mActiveImage = newImg;
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
else if (mRemoteData->mType == RemoteImageData::DXGI_TEXTURE_HANDLE &&
|
||||
mRemoteData->mTextureHandle && !mActiveImage) {
|
||||
nsRefPtr<RemoteDXGITextureImage> newImg = new RemoteDXGITextureImage();
|
||||
newImg->mSize = mRemoteData->mSize;
|
||||
newImg->mHandle = mRemoteData->mTextureHandle;
|
||||
newImg->mFormat = mRemoteData->mFormat;
|
||||
mRemoteData->mWasUpdated = false;
|
||||
|
||||
mActiveImage = newImg;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin)
|
||||
: Image(nullptr, PLANAR_YCBCR)
|
||||
, mBufferSize(0)
|
||||
, mRecycleBin(aRecycleBin)
|
||||
{
|
||||
}
|
||||
|
||||
PlanarYCbCrImage::~PlanarYCbCrImage()
|
||||
{
|
||||
if (mBuffer) {
|
||||
mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
PlanarYCbCrImage::AllocateBuffer(PRUint32 aSize)
|
||||
{
|
||||
return mRecycleBin->GetBuffer(aSize);
|
||||
}
|
||||
|
||||
static void
|
||||
CopyPlane(PRUint8 *aDst, PRUint8 *aSrc,
|
||||
const gfxIntSize &aSize, PRInt32 aStride,
|
||||
PRInt32 aOffset, PRInt32 aSkip)
|
||||
{
|
||||
if (!aOffset && !aSkip) {
|
||||
// Fast path: planar input.
|
||||
memcpy(aDst, aSrc, aSize.height * aStride);
|
||||
} else {
|
||||
PRInt32 height = aSize.height;
|
||||
PRInt32 width = aSize.width;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
PRUint8 *src = aSrc + aOffset;
|
||||
PRUint8 *dst = aDst;
|
||||
if (!aSkip) {
|
||||
// Fast path: offset only, no per-pixel skip.
|
||||
memcpy(dst, src, width);
|
||||
} else {
|
||||
// Slow path
|
||||
for (int x = 0; x < width; ++x) {
|
||||
*dst++ = *src++;
|
||||
src += aSkip;
|
||||
}
|
||||
}
|
||||
aSrc += aStride;
|
||||
aDst += aStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::CopyData(const Data& aData,
|
||||
PRInt32 aYOffset, PRInt32 aYSkip,
|
||||
PRInt32 aCbOffset, PRInt32 aCbSkip,
|
||||
PRInt32 aCrOffset, PRInt32 aCrSkip)
|
||||
{
|
||||
mData = aData;
|
||||
|
||||
// update buffer size
|
||||
mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
|
||||
mData.mYStride * mData.mYSize.height;
|
||||
|
||||
// get new buffer
|
||||
mBuffer = AllocateBuffer(mBufferSize);
|
||||
if (!mBuffer)
|
||||
return;
|
||||
|
||||
mData.mYChannel = mBuffer;
|
||||
mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
|
||||
mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
|
||||
|
||||
CopyPlane(mData.mYChannel, aData.mYChannel,
|
||||
mData.mYSize, mData.mYStride,
|
||||
aYOffset, aYSkip);
|
||||
CopyPlane(mData.mCbChannel, aData.mCbChannel,
|
||||
mData.mCbCrSize, mData.mCbCrStride,
|
||||
aCbOffset, aCbSkip);
|
||||
CopyPlane(mData.mCrChannel, aData.mCrChannel,
|
||||
mData.mCbCrSize, mData.mCbCrStride,
|
||||
aCrOffset, aCrSkip);
|
||||
|
||||
mSize = aData.mPicSize;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::SetData(const Data &aData)
|
||||
{
|
||||
CopyData(aData);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
PlanarYCbCrImage::GetAsSurface()
|
||||
{
|
||||
if (mSurface) {
|
||||
nsRefPtr<gfxASurface> result = mSurface.get();
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
gfxASurface::gfxImageFormat format = GetOffscreenFormat();
|
||||
|
||||
gfxIntSize size(mSize);
|
||||
gfxUtils::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
|
||||
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
|
||||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
|
||||
NS_ERROR("Illegal image dest width or height");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> imageSurface =
|
||||
new gfxImageSurface(mSize, format);
|
||||
|
||||
gfxUtils::ConvertYCbCrToRGB(mData, format, mSize,
|
||||
imageSurface->Data(),
|
||||
imageSurface->Stride());
|
||||
|
||||
mSurface = imageSurface;
|
||||
|
||||
return imageSurface.forget().get();
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
void
|
||||
MacIOSurfaceImage::SetData(const Data& aData)
|
||||
{
|
||||
mIOSurface = MacIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
|
||||
mSize = gfxIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
MacIOSurfaceImage::GetAsSurface()
|
||||
{
|
||||
mIOSurface->Lock();
|
||||
size_t bytesPerRow = mIOSurface->GetBytesPerRow();
|
||||
size_t ioWidth = mIOSurface->GetWidth();
|
||||
size_t ioHeight = mIOSurface->GetHeight();
|
||||
|
||||
unsigned char* ioData = (unsigned char*)mIOSurface->GetBaseAddress();
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface(gfxIntSize(ioWidth, ioHeight), gfxASurface::ImageFormatARGB32);
|
||||
|
||||
for (int i = 0; i < ioHeight; i++) {
|
||||
memcpy(imgSurface->Data() + i * imgSurface->Stride(),
|
||||
ioData + i * bytesPerRow, ioWidth * 4);
|
||||
}
|
||||
|
||||
mIOSurface->Unlock();
|
||||
|
||||
return imgSurface.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceImage::Update(ImageContainer* aContainer)
|
||||
{
|
||||
if (mUpdateCallback) {
|
||||
mUpdateCallback(aContainer, mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
RemoteBitmapImage::GetAsSurface()
|
||||
{
|
||||
nsRefPtr<gfxImageSurface> newSurf =
|
||||
new gfxImageSurface(mSize,
|
||||
mFormat == RemoteImageData::BGRX32 ? gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32);
|
||||
|
||||
for (int y = 0; y < mSize.height; y++) {
|
||||
memcpy(newSurf->Data() + newSurf->Stride() * y,
|
||||
mData + mStride * y,
|
||||
mSize.width * 4);
|
||||
}
|
||||
|
||||
return newSurf.forget();
|
||||
// Snap our local transform first, and snap the inherited transform as well.
|
||||
// This makes our snapping equivalent to what would happen if our content
|
||||
// was drawn into a ThebesLayer (gfxContext would snap using the local
|
||||
// transform, then we'd snap again when compositing the ThebesLayer).
|
||||
mEffectiveTransform =
|
||||
SnapTransform(GetLocalTransform(), snap, nullptr)*
|
||||
SnapTransform(aTransformToSurface, gfxRect(0, 0, 0, 0), nullptr);
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,642 +8,14 @@
|
||||
|
||||
#include "Layers.h"
|
||||
|
||||
#include "ImageTypes.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "gfxPattern.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
struct ID3D10Texture2D;
|
||||
struct ID3D10Device;
|
||||
struct ID3D10ShaderResourceView;
|
||||
|
||||
typedef void* HANDLE;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CrossProcessMutex;
|
||||
namespace ipc {
|
||||
class Shmem;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class ImageContainerChild;
|
||||
class ImageBridgeChild;
|
||||
|
||||
enum StereoMode {
|
||||
STEREO_MODE_MONO,
|
||||
STEREO_MODE_LEFT_RIGHT,
|
||||
STEREO_MODE_RIGHT_LEFT,
|
||||
STEREO_MODE_BOTTOM_TOP,
|
||||
STEREO_MODE_TOP_BOTTOM
|
||||
};
|
||||
|
||||
struct ImageBackendData
|
||||
{
|
||||
virtual ~ImageBackendData() {}
|
||||
|
||||
protected:
|
||||
ImageBackendData() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class representing a buffer of pixel data. The data can be in one
|
||||
* of various formats including YCbCr.
|
||||
*
|
||||
* Create an image using an ImageContainer. Fill the image with data, and
|
||||
* then call ImageContainer::SetImage to display it. An image must not be
|
||||
* modified after calling SetImage. Image implementations do not need to
|
||||
* perform locking; when filling an Image, the Image client is responsible
|
||||
* for ensuring only one thread accesses the Image at a time, and after
|
||||
* SetImage the image is immutable.
|
||||
*
|
||||
* When resampling an Image, only pixels within the buffer should be
|
||||
* sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
|
||||
*/
|
||||
class THEBES_API Image {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image)
|
||||
|
||||
public:
|
||||
virtual ~Image() {}
|
||||
|
||||
enum Format {
|
||||
/**
|
||||
* The PLANAR_YCBCR format creates a PlanarYCbCrImage. All backends should
|
||||
* support this format, because the Ogg video decoder depends on it.
|
||||
* The maximum image width and height is 16384.
|
||||
*/
|
||||
PLANAR_YCBCR,
|
||||
|
||||
/**
|
||||
* The CAIRO_SURFACE format creates a CairoImage. All backends should
|
||||
* support this format, because video rendering sometimes requires it.
|
||||
*
|
||||
* This format is useful even though a ThebesLayer could be used.
|
||||
* It makes it easy to render a cairo surface when another Image format
|
||||
* could be used. It can also avoid copying the surface data in some
|
||||
* cases.
|
||||
*
|
||||
* Images in CAIRO_SURFACE format should only be created and
|
||||
* manipulated on the main thread, since the underlying cairo surface
|
||||
* is main-thread-only.
|
||||
*/
|
||||
CAIRO_SURFACE,
|
||||
|
||||
/**
|
||||
* The MAC_IO_SURFACE format creates a MacIOSurfaceImage.
|
||||
*
|
||||
* It wraps an IOSurface object and binds it directly to a GL texture.
|
||||
*/
|
||||
MAC_IO_SURFACE,
|
||||
|
||||
/**
|
||||
* The GONK_IO_SURFACE format creates a GonkIOSurfaceImage.
|
||||
*
|
||||
* It wraps an GraphicBuffer object and binds it directly to a GL texture.
|
||||
*/
|
||||
GONK_IO_SURFACE,
|
||||
|
||||
/**
|
||||
* An bitmap image that can be shared with a remote process.
|
||||
*/
|
||||
REMOTE_IMAGE_BITMAP,
|
||||
|
||||
/**
|
||||
* A OpenGL texture that can be shared across threads or processes
|
||||
*/
|
||||
SHARED_TEXTURE,
|
||||
|
||||
/**
|
||||
* An DXGI shared surface handle that can be shared with a remote process.
|
||||
*/
|
||||
REMOTE_IMAGE_DXGI_TEXTURE
|
||||
};
|
||||
|
||||
Format GetFormat() { return mFormat; }
|
||||
void* GetImplData() { return mImplData; }
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
|
||||
virtual gfxIntSize GetSize() = 0;
|
||||
|
||||
ImageBackendData* GetBackendData(LayersBackend aBackend)
|
||||
{ return mBackendData[aBackend]; }
|
||||
void SetBackendData(LayersBackend aBackend, ImageBackendData* aData)
|
||||
{ mBackendData[aBackend] = aData; }
|
||||
|
||||
protected:
|
||||
Image(void* aImplData, Format aFormat) :
|
||||
mImplData(aImplData),
|
||||
mFormat(aFormat)
|
||||
{}
|
||||
|
||||
nsAutoPtr<ImageBackendData> mBackendData[mozilla::layers::LAYERS_LAST];
|
||||
|
||||
void* mImplData;
|
||||
Format mFormat;
|
||||
};
|
||||
|
||||
/**
|
||||
* A RecycleBin is owned by an ImageContainer. We store buffers in it that we
|
||||
* want to recycle from one image to the next.It's a separate object from
|
||||
* ImageContainer because images need to store a strong ref to their RecycleBin
|
||||
* and we must avoid creating a reference loop between an ImageContainer and
|
||||
* its active image.
|
||||
*/
|
||||
class BufferRecycleBin {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin)
|
||||
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
public:
|
||||
BufferRecycleBin();
|
||||
|
||||
void RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize);
|
||||
// Returns a recycled buffer of the right size, or allocates a new buffer.
|
||||
PRUint8* GetBuffer(PRUint32 aSize);
|
||||
|
||||
private:
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
// This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures
|
||||
// and mRecycledTextureSizes
|
||||
Mutex mLock;
|
||||
|
||||
// We should probably do something to prune this list on a timer so we don't
|
||||
// eat excess memory while video is paused...
|
||||
nsTArray<nsAutoArrayPtr<PRUint8> > mRecycledBuffers;
|
||||
// This is only valid if mRecycledBuffers is non-empty
|
||||
PRUint32 mRecycledBufferSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if aFormat is in the given format array.
|
||||
*/
|
||||
static inline bool
|
||||
FormatInList(const Image::Format* aFormats, PRUint32 aNumFormats,
|
||||
Image::Format aFormat)
|
||||
{
|
||||
for (PRUint32 i = 0; i < aNumFormats; ++i) {
|
||||
if (aFormats[i] == aFormat) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class CompositionNotifySink
|
||||
{
|
||||
public:
|
||||
virtual void DidComposite() = 0;
|
||||
virtual ~CompositionNotifySink() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that manages Image creation for a LayerManager. The only reason
|
||||
* we need a separate class here is that LayerMananers aren't threadsafe
|
||||
* (because layers can only be used on the main thread) and we want to
|
||||
* be able to create images from any thread, to facilitate video playback
|
||||
* without involving the main thread, for example.
|
||||
* Different layer managers can implement child classes of this making it
|
||||
* possible to create layer manager specific images.
|
||||
* This class is not meant to be used directly but rather can be set on an
|
||||
* image container. This is usually done by the layer system internally and
|
||||
* not explicitly by users. For PlanarYCbCr or Cairo images the default
|
||||
* implementation will creates images whose data lives in system memory, for
|
||||
* MacIOSurfaces the default implementation will be a simple MacIOSurface
|
||||
* wrapper.
|
||||
*/
|
||||
|
||||
class THEBES_API ImageFactory
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory)
|
||||
protected:
|
||||
friend class ImageContainer;
|
||||
|
||||
ImageFactory() {}
|
||||
virtual ~ImageFactory() {}
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &aScaleHint,
|
||||
BufferRecycleBin *aRecycleBin);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This struct is used to store RemoteImages, it is meant to be able to live in
|
||||
* shared memory. Therefor it should not contain a vtable pointer. Remote
|
||||
* users can manipulate the data in this structure to specify what image is to
|
||||
* be drawn by the container. When accessing this data users should make sure
|
||||
* the mutex synchronizing access to the structure is held!
|
||||
*/
|
||||
struct RemoteImageData {
|
||||
enum Type {
|
||||
/**
|
||||
* This is a format that uses raw bitmap data.
|
||||
*/
|
||||
RAW_BITMAP,
|
||||
|
||||
/**
|
||||
* This is a format that uses a pointer to a texture do draw directly
|
||||
* from a shared texture. Any process may have created this texture handle,
|
||||
* the process creating the texture handle is responsible for managing it's
|
||||
* lifetime by managing the lifetime of the first D3D texture object this
|
||||
* handle was created for. It must also ensure the handle is not set
|
||||
* current anywhere when the last reference to this object is released.
|
||||
*/
|
||||
DXGI_TEXTURE_HANDLE
|
||||
};
|
||||
/* These formats describe the format in the memory byte-order */
|
||||
enum Format {
|
||||
/* 8 bits per channel */
|
||||
BGRA32,
|
||||
/* 8 bits per channel, alpha channel is ignored */
|
||||
BGRX32
|
||||
};
|
||||
|
||||
// This should be set to true if a change was made so that the ImageContainer
|
||||
// knows to throw out any cached RemoteImage objects.
|
||||
bool mWasUpdated;
|
||||
Type mType;
|
||||
Format mFormat;
|
||||
gfxIntSize mSize;
|
||||
union {
|
||||
struct {
|
||||
/* This pointer is set by a remote process, however it will be set to
|
||||
* the container process' address the memory of the raw bitmap resides
|
||||
* at.
|
||||
*/
|
||||
unsigned char *mData;
|
||||
int mStride;
|
||||
} mBitmap;
|
||||
#ifdef XP_WIN
|
||||
HANDLE mTextureHandle;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that manages Images for an ImageLayer. The only reason
|
||||
* we need a separate class here is that ImageLayers aren't threadsafe
|
||||
* (because layers can only be used on the main thread) and we want to
|
||||
* be able to set the current Image from any thread, to facilitate
|
||||
* video playback without involving the main thread, for example.
|
||||
*
|
||||
* An ImageContainer can operate in one of three modes:
|
||||
* 1) Normal. Triggered by constructing the ImageContainer with
|
||||
* DISABLE_ASYNC or when compositing is happening on the main thread.
|
||||
* SetCurrentImage changes ImageContainer state but nothing is sent to the
|
||||
* compositor until the next layer transaction.
|
||||
* 2) Asynchronous. Initiated by constructing the ImageContainer with
|
||||
* ENABLE_ASYNC when compositing is happening on the main thread.
|
||||
* SetCurrentImage sends a message through the ImageBridge to the compositor
|
||||
* thread to update the image, without going through the main thread or
|
||||
* a layer transaction.
|
||||
* 3) Remote. Initiated by calling SetRemoteImageData on the ImageContainer
|
||||
* before any other activity.
|
||||
* The ImageContainer uses a shared memory block containing a cross-process mutex
|
||||
* to communicate with the compositor thread. SetCurrentImage synchronously
|
||||
* updates the shared state to point to the new image and the old image
|
||||
* is immediately released (not true in Normal or Asynchronous modes).
|
||||
*/
|
||||
class THEBES_API ImageContainer {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
|
||||
public:
|
||||
|
||||
enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
|
||||
|
||||
ImageContainer(int flag = 0);
|
||||
|
||||
~ImageContainer();
|
||||
|
||||
/**
|
||||
* Create an Image in one of the given formats.
|
||||
* Picks the "best" format from the list and creates an Image of that
|
||||
* format.
|
||||
* Returns null if this backend does not support any of the formats.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats);
|
||||
|
||||
/**
|
||||
* Set an Image as the current image to display. The Image must have
|
||||
* been created by this ImageContainer.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* aImage can be null. While it's null, nothing will be painted.
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
* Note that this must not be called if ENABLE_ASYNC has not been set.
|
||||
*
|
||||
* Implementations must call CurrentImageChanged() while holding
|
||||
* mReentrantMonitor.
|
||||
*
|
||||
* If this ImageContainer has an ImageContainerChild for async video:
|
||||
* Schelude a task to send the image to the compositor using the
|
||||
* PImageBridge protcol without using the main thread.
|
||||
*/
|
||||
void SetCurrentImage(Image* aImage);
|
||||
|
||||
/**
|
||||
* Set an Image as the current image to display. The Image must have
|
||||
* been created by this ImageContainer.
|
||||
* Must be called on the main thread, within a layers transaction.
|
||||
*
|
||||
* This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* aImage can be null. While it's null, nothing will be painted.
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
* Note that this must not be called if ENABLE_ASYNC been set.
|
||||
*
|
||||
* Implementations must call CurrentImageChanged() while holding
|
||||
* mReentrantMonitor.
|
||||
*/
|
||||
void SetCurrentImageInTransaction(Image* aImage);
|
||||
|
||||
/**
|
||||
* Returns true if this ImageContainer uses the ImageBridge IPDL protocol.
|
||||
*
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
bool IsAsync() const;
|
||||
|
||||
/**
|
||||
* If this ImageContainer uses ImageBridge, returns the ID associated to
|
||||
* this container, for use in the ImageBridge protocol.
|
||||
* Returns 0 if this ImageContainer does not use ImageBridge. Note that
|
||||
* 0 is always an invalid ID for asynchronous image containers.
|
||||
*
|
||||
* Can be called from ay thread.
|
||||
*/
|
||||
PRUint64 GetAsyncContainerID() const;
|
||||
|
||||
/**
|
||||
* Returns if the container currently has an image.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
bool HasCurrentImage();
|
||||
|
||||
/**
|
||||
* Lock the current Image.
|
||||
* This has to add a reference since otherwise there are race conditions
|
||||
* where the current image is destroyed before the caller can add
|
||||
* a reference. This lock strictly guarantees the underlying image remains
|
||||
* valid, it does not mean the current image cannot change.
|
||||
* Can be called on any thread. This method will lock the cross-process
|
||||
* mutex to ensure remote processes cannot alter underlying data. This call
|
||||
* -must- be balanced by a call to UnlockCurrentImage and users should avoid
|
||||
* holding the image locked for a long time.
|
||||
*/
|
||||
already_AddRefed<Image> LockCurrentImage();
|
||||
|
||||
/**
|
||||
* This call unlocks the image. For remote images releasing the cross-process
|
||||
* mutex.
|
||||
*/
|
||||
void UnlockCurrentImage();
|
||||
|
||||
/**
|
||||
* Get the current image as a gfxASurface. This is useful for fallback
|
||||
* rendering.
|
||||
* This can only be called from the main thread, since cairo objects
|
||||
* can only be used from the main thread.
|
||||
* This is defined here and not on Image because it's possible (likely)
|
||||
* that some backends will make an Image "ready to draw" only when it
|
||||
* becomes the current image for an image container.
|
||||
* Returns null if there is no current image.
|
||||
* Returns the size in aSize.
|
||||
* The returned surface will never be modified. The caller must not
|
||||
* modify it.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
* If the current image is a remote image, that is, if it is an image that
|
||||
* may be shared accross processes, calling this function will make
|
||||
* a copy of the image data while holding the mRemoteDataMutex. If possible,
|
||||
* the lock methods should be used to avoid the copy, however this should be
|
||||
* avoided if the surface is required for a long period of time.
|
||||
*/
|
||||
already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult);
|
||||
|
||||
/**
|
||||
* This is similar to GetCurrentAsSurface, however this does not make a copy
|
||||
* of the image data and requires the user to call UnlockCurrentImage when
|
||||
* done with the image data. Once UnlockCurrentImage has been called the
|
||||
* surface returned by this function is no longer valid! This works for any
|
||||
* type of image. Optionally a pointer can be passed to receive the current
|
||||
* image.
|
||||
*/
|
||||
already_AddRefed<gfxASurface> LockCurrentAsSurface(gfxIntSize* aSizeResult,
|
||||
Image** aCurrentImage = nullptr);
|
||||
|
||||
/**
|
||||
* Returns the size of the image in pixels.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor when accessing
|
||||
* thread-shared state.
|
||||
*/
|
||||
gfxIntSize GetCurrentSize();
|
||||
|
||||
/**
|
||||
* Sets a size that the image is expected to be rendered at.
|
||||
* This is a hint for image backends to optimize scaling.
|
||||
* Default implementation in this class is to ignore the hint.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
void SetScaleHint(const gfxIntSize& aScaleHint)
|
||||
{ mScaleHint = aScaleHint; }
|
||||
|
||||
void SetImageFactory(ImageFactory *aFactory)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mImageFactory = aFactory ? aFactory : new ImageFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which the currently contained image was first
|
||||
* painted. This is reset every time a new image is set as the current
|
||||
* image. Note this may return a null timestamp if the current image
|
||||
* has not yet been painted. Can be called from any thread.
|
||||
*/
|
||||
TimeStamp GetPaintTime() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mPaintTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of images which have been contained in this container
|
||||
* and painted at least once. Can be called from any thread.
|
||||
*/
|
||||
PRUint32 GetPaintCount() {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mPaintCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments mPaintCount if this is the first time aPainted has been
|
||||
* painted, and sets mPaintTime if the painted image is the current image.
|
||||
* current image. Can be called from any thread.
|
||||
*/
|
||||
void NotifyPaintedImage(Image* aPainted) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
nsRefPtr<Image> current = mActiveImage;
|
||||
if (aPainted == current) {
|
||||
if (mPaintTime.IsNull()) {
|
||||
mPaintTime = TimeStamp::Now();
|
||||
mPaintCount++;
|
||||
}
|
||||
} else if (!mPreviousImagePainted) {
|
||||
// While we were painting this image, the current image changed. We
|
||||
// still must count it as painted, but can't set mPaintTime, since we're
|
||||
// no longer the current image.
|
||||
mPaintCount++;
|
||||
mPreviousImagePainted = true;
|
||||
}
|
||||
|
||||
if (mCompositionNotifySink) {
|
||||
mCompositionNotifySink->DidComposite();
|
||||
}
|
||||
}
|
||||
|
||||
void SetCompositionNotifySink(CompositionNotifySink *aSink) {
|
||||
mCompositionNotifySink = aSink;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called to tell the ImageContainer where the
|
||||
* (cross-process) segment lives where the shared data about possible
|
||||
* remote images are stored. In addition to this a CrossProcessMutex object
|
||||
* is passed telling the container how to synchronize access to this data.
|
||||
* NOTE: This should be called during setup of the container and not after
|
||||
* usage has started.
|
||||
*/
|
||||
void SetRemoteImageData(RemoteImageData *aRemoteData,
|
||||
CrossProcessMutex *aRemoteDataMutex);
|
||||
/**
|
||||
* This can be used to check if the container has RemoteData set.
|
||||
*/
|
||||
RemoteImageData *GetRemoteImageData() { return mRemoteData; }
|
||||
|
||||
protected:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
|
||||
void SetCurrentImageInternal(Image* aImage);
|
||||
|
||||
// This is called to ensure we have an active image, this may not be true
|
||||
// when we're storing image information in a RemoteImageData structure.
|
||||
// NOTE: If we have remote data mRemoteDataMutex should be locked when
|
||||
// calling this function!
|
||||
void EnsureActiveImage();
|
||||
|
||||
// ReentrantMonitor to protect thread safe access to the "current
|
||||
// image", and any other state which is shared between threads.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
// Performs necessary housekeeping to ensure the painted frame statistics
|
||||
// are accurate. Must be called by SetCurrentImage() implementations with
|
||||
// mReentrantMonitor held.
|
||||
void CurrentImageChanged() {
|
||||
mReentrantMonitor.AssertCurrentThreadIn();
|
||||
mPreviousImagePainted = !mPaintTime.IsNull();
|
||||
mPaintTime = TimeStamp();
|
||||
}
|
||||
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
|
||||
// Number of contained images that have been painted at least once. It's up
|
||||
// to the ImageContainer implementation to ensure accesses to this are
|
||||
// threadsafe.
|
||||
PRUint32 mPaintCount;
|
||||
|
||||
// Time stamp at which the current image was first painted. It's up to the
|
||||
// ImageContainer implementation to ensure accesses to this are threadsafe.
|
||||
TimeStamp mPaintTime;
|
||||
|
||||
// Denotes whether the previous image was painted.
|
||||
bool mPreviousImagePainted;
|
||||
|
||||
// This is the image factory used by this container, layer managers using
|
||||
// this container can set an alternative image factory that will be used to
|
||||
// create images for this container.
|
||||
nsRefPtr<ImageFactory> mImageFactory;
|
||||
|
||||
gfxIntSize mScaleHint;
|
||||
|
||||
nsRefPtr<BufferRecycleBin> mRecycleBin;
|
||||
|
||||
// This contains the remote image data for this container, if this is NULL
|
||||
// that means the container has no other process that may control its active
|
||||
// image.
|
||||
RemoteImageData *mRemoteData;
|
||||
|
||||
// This cross-process mutex is used to synchronise access to mRemoteData.
|
||||
// When this mutex is held, we will always be inside the mReentrantMonitor
|
||||
// however the same is not true vice versa.
|
||||
CrossProcessMutex *mRemoteDataMutex;
|
||||
|
||||
CompositionNotifySink *mCompositionNotifySink;
|
||||
|
||||
// This member points to an ImageContainerChild if this ImageContainer was
|
||||
// sucessfully created with ENABLE_ASYNC, or points to null otherwise.
|
||||
// 'unsuccessful' in this case only means that the ImageContainerChild could not
|
||||
// be created, most likely because off-main-thread compositing is not enabled.
|
||||
// In this case the ImageContainer is perfectly usable, but it will forward
|
||||
// frames to the compositor through transactions in the main thread rather than
|
||||
// asynchronusly using the ImageBridge IPDL protocol.
|
||||
nsRefPtr<ImageContainerChild> mImageContainerChild;
|
||||
};
|
||||
|
||||
class AutoLockImage
|
||||
{
|
||||
public:
|
||||
AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
|
||||
AutoLockImage(ImageContainer *aContainer, gfxASurface **aSurface) : mContainer(aContainer) {
|
||||
*aSurface = mContainer->LockCurrentAsSurface(&mSize, getter_AddRefs(mImage)).get();
|
||||
}
|
||||
~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
|
||||
|
||||
Image* GetImage() { return mImage; }
|
||||
const gfxIntSize &GetSize() { return mSize; }
|
||||
|
||||
void Unlock() {
|
||||
if (mContainer) {
|
||||
mImage = nullptr;
|
||||
mContainer->UnlockCurrentImage();
|
||||
mContainer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Things get a little tricky here, because our underlying image can -still-
|
||||
* change, and OS X requires a complicated callback mechanism to update this
|
||||
* we need to support staying the lock and getting the new image in a proper
|
||||
* way. This method makes any images retrieved with GetImage invalid!
|
||||
*/
|
||||
void Refresh() {
|
||||
if (mContainer) {
|
||||
mContainer->UnlockCurrentImage();
|
||||
mImage = mContainer->LockCurrentImage();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ImageContainer *mContainer;
|
||||
nsRefPtr<Image> mImage;
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
class ImageContainer;
|
||||
|
||||
/**
|
||||
* A Layer which renders an Image.
|
||||
@ -661,10 +33,8 @@ public:
|
||||
* Set the ImageContainer. aContainer must have the same layer manager
|
||||
* as this layer.
|
||||
*/
|
||||
void SetContainer(ImageContainer* aContainer)
|
||||
{
|
||||
mContainer = aContainer;
|
||||
}
|
||||
void SetContainer(ImageContainer* aContainer);
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* Set the filter used to resample this image if necessary.
|
||||
@ -687,23 +57,7 @@ public:
|
||||
|
||||
MOZ_LAYER_DECL_NAME("ImageLayer", TYPE_IMAGE)
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
{
|
||||
// Snap image edges to pixel boundaries
|
||||
gfxRect snap(0, 0, 0, 0);
|
||||
if (mContainer) {
|
||||
gfxIntSize size = mContainer->GetCurrentSize();
|
||||
snap.SizeTo(gfxSize(size.width, size.height));
|
||||
}
|
||||
// Snap our local transform first, and snap the inherited transform as well.
|
||||
// This makes our snapping equivalent to what would happen if our content
|
||||
// was drawn into a ThebesLayer (gfxContext would snap using the local
|
||||
// transform, then we'd snap again when compositing the ThebesLayer).
|
||||
mEffectiveTransform =
|
||||
SnapTransform(GetLocalTransform(), snap, nullptr)*
|
||||
SnapTransform(aTransformToSurface, gfxRect(0, 0, 0, 0), nullptr);
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
}
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface);
|
||||
|
||||
/**
|
||||
* if true, the image will only be backed by a single tile texture
|
||||
@ -715,10 +69,8 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
ImageLayer(LayerManager* aManager, void* aImplData)
|
||||
: Layer(aManager, aImplData), mFilter(gfxPattern::FILTER_GOOD)
|
||||
, mScaleMode(SCALE_NONE), mForceSingleTile(false) {}
|
||||
|
||||
ImageLayer(LayerManager* aManager, void* aImplData);
|
||||
~ImageLayer();
|
||||
virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
|
||||
|
||||
|
||||
@ -729,244 +81,6 @@ protected:
|
||||
bool mForceSingleTile;
|
||||
};
|
||||
|
||||
/****** Image subtypes for the different formats ******/
|
||||
|
||||
/**
|
||||
* We assume that the image data is in the REC 470M color space (see
|
||||
* Theora specification, section 4.3.1).
|
||||
*
|
||||
* The YCbCr format can be:
|
||||
*
|
||||
* 4:4:4 - CbCr width/height are the same as Y.
|
||||
* 4:2:2 - CbCr width is half that of Y. Height is the same.
|
||||
* 4:2:0 - CbCr width and height is half that of Y.
|
||||
*
|
||||
* The color format is detected based on the height/width ratios
|
||||
* defined above.
|
||||
*
|
||||
* The Image that is rendered is the picture region defined by
|
||||
* mPicX, mPicY and mPicSize. The size of the rendered image is
|
||||
* mPicSize, not mYSize or mCbCrSize.
|
||||
*/
|
||||
class THEBES_API PlanarYCbCrImage : public Image {
|
||||
public:
|
||||
struct Data {
|
||||
// Luminance buffer
|
||||
PRUint8* mYChannel;
|
||||
PRInt32 mYStride;
|
||||
gfxIntSize mYSize;
|
||||
// Chroma buffers
|
||||
PRUint8* mCbChannel;
|
||||
PRUint8* mCrChannel;
|
||||
PRInt32 mCbCrStride;
|
||||
gfxIntSize mCbCrSize;
|
||||
// Picture region
|
||||
PRUint32 mPicX;
|
||||
PRUint32 mPicY;
|
||||
gfxIntSize mPicSize;
|
||||
StereoMode mStereoMode;
|
||||
|
||||
nsIntRect GetPictureRect() const {
|
||||
return nsIntRect(mPicX, mPicY,
|
||||
mPicSize.width,
|
||||
mPicSize.height);
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_DIMENSION = 16384
|
||||
};
|
||||
|
||||
~PlanarYCbCrImage();
|
||||
|
||||
/**
|
||||
* This makes a copy of the data buffers, in order to support functioning
|
||||
* in all different layer managers.
|
||||
*/
|
||||
virtual void SetData(const Data& aData);
|
||||
|
||||
/**
|
||||
* Ask this Image to not convert YUV to RGB during SetData, and make
|
||||
* the original data available through GetData. This is optional,
|
||||
* and not all PlanarYCbCrImages will support it.
|
||||
*/
|
||||
virtual void SetDelayedConversion(bool aDelayed) { }
|
||||
|
||||
/**
|
||||
* Grab the original YUV data. This is optional.
|
||||
*/
|
||||
virtual const Data* GetData() { return &mData; }
|
||||
|
||||
/**
|
||||
* Make a copy of the YCbCr data into local storage.
|
||||
*
|
||||
* @param aData Input image data.
|
||||
* @param aYOffset Pixels to skip between lines in the Y plane.
|
||||
* @param aYSkip Pixels to skip between pixels in the Y plane.
|
||||
* @param aCbOffset Pixels to skip between lines in the Cb plane.
|
||||
* @param aCbSkip Pixels to skip between pixels in the Cb plane.
|
||||
* @param aCrOffset Pixels to skip between lines in the Cr plane.
|
||||
* @param aCrSkip Pixels to skip between pixels in the Cr plane.
|
||||
*/
|
||||
void CopyData(const Data& aData,
|
||||
PRInt32 aYOffset = 0, PRInt32 aYSkip = 0,
|
||||
PRInt32 aCbOffset = 0, PRInt32 aCbSkip = 0,
|
||||
PRInt32 aCrOffset = 0, PRInt32 aCrSkip = 0);
|
||||
|
||||
/**
|
||||
* Return a buffer to store image data in.
|
||||
* The default implementation returns memory that can
|
||||
* be freed wit delete[]
|
||||
*/
|
||||
virtual PRUint8* AllocateBuffer(PRUint32 aSize);
|
||||
|
||||
/**
|
||||
* Return the number of bytes of heap memory used to store this image.
|
||||
*/
|
||||
virtual PRUint32 GetDataSize() { return mBufferSize; }
|
||||
|
||||
already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
virtual gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
|
||||
gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
|
||||
|
||||
// XXX - not easy to protect these sadly.
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferSize;
|
||||
Data mData;
|
||||
gfxIntSize mSize;
|
||||
gfxImageFormat mOffscreenFormat;
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
nsRefPtr<BufferRecycleBin> mRecycleBin;
|
||||
|
||||
PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
|
||||
};
|
||||
|
||||
/**
|
||||
* Currently, the data in a CairoImage surface is treated as being in the
|
||||
* device output color space. This class is very simple as all backends
|
||||
* have to know about how to deal with drawing a cairo image.
|
||||
*/
|
||||
class THEBES_API CairoImage : public Image {
|
||||
public:
|
||||
struct Data {
|
||||
gfxASurface* mSurface;
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* This can only be called on the main thread. It may add a reference
|
||||
* to the surface (which will eventually be released on the main thread).
|
||||
* The surface must not be modified after this call!!!
|
||||
*/
|
||||
void SetData(const Data& aData)
|
||||
{
|
||||
mSurface = aData.mSurface;
|
||||
mSize = aData.mSize;
|
||||
}
|
||||
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
|
||||
nsRefPtr<gfxASurface> surface = mSurface.get();
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
CairoImage() : Image(NULL, CAIRO_SURFACE) {}
|
||||
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
class THEBES_API MacIOSurfaceImage : public Image {
|
||||
public:
|
||||
struct Data {
|
||||
MacIOSurface* mIOSurface;
|
||||
};
|
||||
|
||||
MacIOSurfaceImage()
|
||||
: Image(NULL, MAC_IO_SURFACE)
|
||||
, mSize(0, 0)
|
||||
, mPluginInstanceOwner(NULL)
|
||||
, mUpdateCallback(NULL)
|
||||
, mDestroyCallback(NULL)
|
||||
{}
|
||||
|
||||
virtual ~MacIOSurfaceImage()
|
||||
{
|
||||
if (mDestroyCallback) {
|
||||
mDestroyCallback(mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This can only be called on the main thread. It may add a reference
|
||||
* to the surface (which will eventually be released on the main thread).
|
||||
* The surface must not be modified after this call!!!
|
||||
*/
|
||||
virtual void SetData(const Data& aData);
|
||||
|
||||
/**
|
||||
* Temporary hacks to force plugin drawing during an empty transaction.
|
||||
* This should not be used for anything else, and will be removed
|
||||
* when async plugin rendering is complete.
|
||||
*/
|
||||
typedef void (*UpdateSurfaceCallback)(ImageContainer* aContainer, void* aInstanceOwner);
|
||||
virtual void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aInstanceOwner)
|
||||
{
|
||||
mUpdateCallback = aCallback;
|
||||
mPluginInstanceOwner = aInstanceOwner;
|
||||
}
|
||||
|
||||
typedef void (*DestroyCallback)(void* aInstanceOwner);
|
||||
virtual void SetDestroyCallback(DestroyCallback aCallback)
|
||||
{
|
||||
mDestroyCallback = aCallback;
|
||||
}
|
||||
|
||||
virtual gfxIntSize GetSize()
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
MacIOSurface* GetIOSurface()
|
||||
{
|
||||
return mIOSurface;
|
||||
}
|
||||
|
||||
void Update(ImageContainer* aContainer);
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
private:
|
||||
gfxIntSize mSize;
|
||||
RefPtr<MacIOSurface> mIOSurface;
|
||||
void* mPluginInstanceOwner;
|
||||
UpdateSurfaceCallback mUpdateCallback;
|
||||
DestroyCallback mDestroyCallback;
|
||||
};
|
||||
#endif
|
||||
|
||||
class RemoteBitmapImage : public Image {
|
||||
public:
|
||||
RemoteBitmapImage() : Image(NULL, REMOTE_IMAGE_BITMAP) {}
|
||||
|
||||
already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
unsigned char *mData;
|
||||
int mStride;
|
||||
gfxIntSize mSize;
|
||||
RemoteImageData::Format mFormat;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
76
gfx/layers/ImageTypes.h
Normal file
76
gfx/layers/ImageTypes.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
||||
#ifndef GFX_IMAGETYPES_H
|
||||
#define GFX_IMAGETYPES_H
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum ImageFormat {
|
||||
/**
|
||||
* The PLANAR_YCBCR format creates a PlanarYCbCrImage. All backends should
|
||||
* support this format, because the Ogg video decoder depends on it.
|
||||
* The maximum image width and height is 16384.
|
||||
*/
|
||||
PLANAR_YCBCR,
|
||||
|
||||
/**
|
||||
* The CAIRO_SURFACE format creates a CairoImage. All backends should
|
||||
* support this format, because video rendering sometimes requires it.
|
||||
*
|
||||
* This format is useful even though a ThebesLayer could be used.
|
||||
* It makes it easy to render a cairo surface when another Image format
|
||||
* could be used. It can also avoid copying the surface data in some
|
||||
* cases.
|
||||
*
|
||||
* Images in CAIRO_SURFACE format should only be created and
|
||||
* manipulated on the main thread, since the underlying cairo surface
|
||||
* is main-thread-only.
|
||||
*/
|
||||
CAIRO_SURFACE,
|
||||
|
||||
/**
|
||||
* The MAC_IO_SURFACE format creates a MacIOSurfaceImage.
|
||||
*
|
||||
* It wraps an IOSurface object and binds it directly to a GL texture.
|
||||
*/
|
||||
MAC_IO_SURFACE,
|
||||
|
||||
/**
|
||||
* The GONK_IO_SURFACE format creates a GonkIOSurfaceImage.
|
||||
*
|
||||
* It wraps an GraphicBuffer object and binds it directly to a GL texture.
|
||||
*/
|
||||
GONK_IO_SURFACE,
|
||||
|
||||
/**
|
||||
* An bitmap image that can be shared with a remote process.
|
||||
*/
|
||||
REMOTE_IMAGE_BITMAP,
|
||||
|
||||
/**
|
||||
* A OpenGL texture that can be shared across threads or processes
|
||||
*/
|
||||
SHARED_TEXTURE,
|
||||
|
||||
/**
|
||||
* An DXGI shared surface handle that can be shared with a remote process.
|
||||
*/
|
||||
REMOTE_IMAGE_DXGI_TEXTURE
|
||||
};
|
||||
|
||||
|
||||
enum StereoMode {
|
||||
STEREO_MODE_MONO,
|
||||
STEREO_MODE_LEFT_RIGHT,
|
||||
STEREO_MODE_RIGHT_LEFT,
|
||||
STEREO_MODE_BOTTOM_TOP,
|
||||
STEREO_MODE_TOP_BOTTOM
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
@ -7,9 +7,9 @@
|
||||
|
||||
#include "mozilla/layers/PLayers.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h" // TODO: temp
|
||||
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "Layers.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "ReadbackLayer.h"
|
||||
|
@ -34,7 +34,9 @@ EXPORTS = \
|
||||
GonkIOSurfaceImage.h \
|
||||
FrameMetrics.h \
|
||||
CompositorParent.h \
|
||||
ImageContainer.h \
|
||||
ImageLayers.h \
|
||||
ImageTypes.h \
|
||||
Layers.h \
|
||||
LayersTypes.h \
|
||||
LayerManagerOGLShaders.h \
|
||||
@ -58,6 +60,7 @@ CPPSRCS = \
|
||||
BasicThebesLayer.cpp \
|
||||
BasicBuffers.cpp \
|
||||
BasicTiledThebesLayer.cpp \
|
||||
ImageContainer.cpp \
|
||||
Layers.cpp \
|
||||
RenderTrace.cpp \
|
||||
ReadbackProcessor.cpp \
|
||||
|
@ -6,7 +6,7 @@
|
||||
#ifndef GFX_SHAREDTEXTUREIMAGE_H
|
||||
#define GFX_SHAREDTEXTUREIMAGE_H
|
||||
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "GLContext.h"
|
||||
|
||||
// Split into a separate header from ImageLayers.h due to GLContext.h dependence
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "gfxImageSurface.h"
|
||||
#include "GLContext.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "BasicLayersImpl.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
@ -281,7 +281,7 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
|
||||
->Paint(aContext, nullptr);
|
||||
}
|
||||
|
||||
if (image->GetFormat() == Image::SHARED_TEXTURE &&
|
||||
if (image->GetFormat() == ImageFormat::SHARED_TEXTURE &&
|
||||
BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL) {
|
||||
SharedTextureImage *sharedImage = static_cast<SharedTextureImage*>(image);
|
||||
const SharedTextureImage::Data *data = sharedImage->GetData();
|
||||
@ -292,7 +292,7 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
|
||||
return;
|
||||
}
|
||||
|
||||
if (image->GetFormat() == Image::PLANAR_YCBCR && BasicManager()->IsCompositingCheap()) {
|
||||
if (image->GetFormat() == ImageFormat::PLANAR_YCBCR && BasicManager()->IsCompositingCheap()) {
|
||||
PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image);
|
||||
const PlanarYCbCrImage::Data *data = YCbCrImage->GetData();
|
||||
NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");
|
||||
|
@ -57,7 +57,7 @@ class BasicImageFactory : public ImageFactory
|
||||
public:
|
||||
BasicImageFactory() {}
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
virtual already_AddRefed<Image> CreateImage(const ImageFormat* aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &aScaleHint,
|
||||
BufferRecycleBin *aRecycleBin)
|
||||
@ -67,7 +67,7 @@ public:
|
||||
}
|
||||
|
||||
nsRefPtr<Image> image;
|
||||
if (aFormats[0] == Image::PLANAR_YCBCR) {
|
||||
if (aFormats[0] == ImageFormat::PLANAR_YCBCR) {
|
||||
image = new BasicPlanarYCbCrImage(aScaleHint, gfxPlatform::GetPlatform()->GetOffscreenFormat(), aRecycleBin);
|
||||
return image.forget();
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "gfxSharedImageSurface.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "RenderTrace.h"
|
||||
#include "sampler.h"
|
||||
|
@ -27,6 +27,7 @@ class ShadowImageLayer;
|
||||
class ShadowCanvasLayer;
|
||||
class ShadowColorLayer;
|
||||
class ReadbackProcessor;
|
||||
class ImageFactory;
|
||||
|
||||
/**
|
||||
* This is a cairo/Thebes-only, main-thread-only implementation of layers.
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "BasicTiledThebesLayer.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "sampler.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
|
||||
#include "cairo.h"
|
||||
|
@ -96,7 +96,7 @@ ImageLayerD3D10::GetImageSRView(Image* aImage, bool& aHasAlpha, IDXGIKeyedMutex
|
||||
{
|
||||
NS_ASSERTION(aImage, "Null image.");
|
||||
|
||||
if (aImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
|
||||
if (aImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) {
|
||||
RemoteBitmapImage *remoteImage =
|
||||
static_cast<RemoteBitmapImage*>(aImage);
|
||||
|
||||
@ -111,14 +111,14 @@ ImageLayerD3D10::GetImageSRView(Image* aImage, bool& aHasAlpha, IDXGIKeyedMutex
|
||||
}
|
||||
|
||||
aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
|
||||
} else if (aImage->GetFormat() == Image::REMOTE_IMAGE_DXGI_TEXTURE) {
|
||||
} else if (aImage->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE) {
|
||||
RemoteDXGITextureImage *remoteImage =
|
||||
static_cast<RemoteDXGITextureImage*>(aImage);
|
||||
|
||||
remoteImage->GetD3D10TextureBackendData(device());
|
||||
|
||||
aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
|
||||
} else if (aImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
} else if (aImage->GetFormat() == ImageFormat::CAIRO_SURFACE) {
|
||||
CairoImage *cairoImage =
|
||||
static_cast<CairoImage*>(aImage);
|
||||
|
||||
@ -188,10 +188,10 @@ ImageLayerD3D10::RenderLayer()
|
||||
ID3D10EffectTechnique *technique;
|
||||
nsRefPtr<IDXGIKeyedMutex> keyedMutex;
|
||||
|
||||
if (image->GetFormat() == Image::CAIRO_SURFACE || image->GetFormat() == Image::REMOTE_IMAGE_BITMAP ||
|
||||
image->GetFormat() == Image::REMOTE_IMAGE_DXGI_TEXTURE)
|
||||
if (image->GetFormat() == ImageFormat::CAIRO_SURFACE || image->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP ||
|
||||
image->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE)
|
||||
{
|
||||
NS_ASSERTION(image->GetFormat() != Image::CAIRO_SURFACE ||
|
||||
NS_ASSERTION(image->GetFormat() != ImageFormat::CAIRO_SURFACE ||
|
||||
!static_cast<CairoImage*>(image)->mSurface ||
|
||||
static_cast<CairoImage*>(image)->mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA,
|
||||
"Image layer has alpha image");
|
||||
@ -220,7 +220,7 @@ ImageLayerD3D10::RenderLayer()
|
||||
(float)size.width,
|
||||
(float)size.height)
|
||||
);
|
||||
} else if (image->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
} else if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImage *yuvImage =
|
||||
static_cast<PlanarYCbCrImage*>(image);
|
||||
|
||||
@ -306,7 +306,7 @@ ImageLayerD3D10::RenderLayer()
|
||||
);
|
||||
}
|
||||
|
||||
bool resetTexCoords = image->GetFormat() == Image::PLANAR_YCBCR;
|
||||
bool resetTexCoords = image->GetFormat() == ImageFormat::PLANAR_YCBCR;
|
||||
image = nullptr;
|
||||
autoLock.Unlock();
|
||||
|
||||
@ -384,7 +384,7 @@ ImageLayerD3D10::GetAsTexture(gfxIntSize* aSize)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (image->GetFormat() != Image::CAIRO_SURFACE) {
|
||||
if (image->GetFormat() != ImageFormat::CAIRO_SURFACE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "LayerManagerD3D10.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "yuv_convert.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -300,7 +300,7 @@ ImageLayerD3D9::GetTexture(Image *aImage, bool& aHasAlpha)
|
||||
{
|
||||
NS_ASSERTION(aImage, "Null image.");
|
||||
|
||||
if (aImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
|
||||
if (aImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) {
|
||||
RemoteBitmapImage *remoteImage =
|
||||
static_cast<RemoteBitmapImage*>(aImage);
|
||||
|
||||
@ -313,7 +313,7 @@ ImageLayerD3D9::GetTexture(Image *aImage, bool& aHasAlpha)
|
||||
}
|
||||
|
||||
aHasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
|
||||
} else if (aImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
} else if (aImage->GetFormat() == ImageFormat::CAIRO_SURFACE) {
|
||||
CairoImage *cairoImage =
|
||||
static_cast<CairoImage*>(aImage);
|
||||
|
||||
@ -370,10 +370,10 @@ ImageLayerD3D9::RenderLayer()
|
||||
|
||||
gfxIntSize size = mScaleMode == SCALE_NONE ? image->GetSize() : mScaleToSize;
|
||||
|
||||
if (image->GetFormat() == Image::CAIRO_SURFACE ||
|
||||
image->GetFormat() == Image::REMOTE_IMAGE_BITMAP)
|
||||
if (image->GetFormat() == ImageFormat::CAIRO_SURFACE ||
|
||||
image->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP)
|
||||
{
|
||||
NS_ASSERTION(image->GetFormat() != Image::CAIRO_SURFACE ||
|
||||
NS_ASSERTION(image->GetFormat() != ImageFormat::CAIRO_SURFACE ||
|
||||
!static_cast<CairoImage*>(image)->mSurface ||
|
||||
static_cast<CairoImage*>(image)->mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA,
|
||||
"Image layer has alpha image");
|
||||
@ -522,8 +522,8 @@ ImageLayerD3D9::GetAsTexture(gfxIntSize* aSize)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (image->GetFormat() != Image::CAIRO_SURFACE &&
|
||||
image->GetFormat() != Image::REMOTE_IMAGE_BITMAP) {
|
||||
if (image->GetFormat() != ImageFormat::CAIRO_SURFACE &&
|
||||
image->GetFormat() != ImageFormat::REMOTE_IMAGE_BITMAP) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "LayerManagerD3D9.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "yuv_convert.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "ShadowLayers.h"
|
||||
#include "mozilla/layers/PLayers.h"
|
||||
#include "mozilla/layers/SharedImageUtils.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "GonkIOSurfaceImage.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -121,7 +121,7 @@ void ImageContainerChild::DestroySharedImage(const SharedImage& aImage)
|
||||
|
||||
bool ImageContainerChild::CopyDataIntoSharedImage(Image* src, SharedImage* dest)
|
||||
{
|
||||
if ((src->GetFormat() == Image::PLANAR_YCBCR) &&
|
||||
if ((src->GetFormat() == ImageFormat::PLANAR_YCBCR) &&
|
||||
(dest->type() == SharedImage::TYUVImage)) {
|
||||
PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(src);
|
||||
const PlanarYCbCrImage::Data *data = YCbCrImage->GetData();
|
||||
@ -161,7 +161,7 @@ SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image)
|
||||
|
||||
++mActiveImageCount;
|
||||
|
||||
if (image->GetFormat() == Image::PLANAR_YCBCR ) {
|
||||
if (image->GetFormat() == ImageFormat::PLANAR_YCBCR ) {
|
||||
PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image);
|
||||
const PlanarYCbCrImage::Data *data = YCbCrImage->GetData();
|
||||
NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");
|
||||
@ -202,7 +202,7 @@ SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image)
|
||||
"SharedImage type not set correctly");
|
||||
return result;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
} else if (image->GetFormat() == Image::GONK_IO_SURFACE) {
|
||||
} else if (image->GetFormat() == ImageFormat::GONK_IO_SURFACE) {
|
||||
GonkIOSurfaceImage* gonkImage = static_cast<GonkIOSurfaceImage*>(image);
|
||||
SharedImage* result = new SharedImage(gonkImage->GetSurfaceDescriptor());
|
||||
return result;
|
||||
@ -236,7 +236,7 @@ SharedImageCompatibleWith(SharedImage* aSharedImage, Image* aImage)
|
||||
{
|
||||
// TODO accept more image formats
|
||||
switch (aImage->GetFormat()) {
|
||||
case Image::PLANAR_YCBCR: {
|
||||
case ImageFormat::PLANAR_YCBCR: {
|
||||
if (aSharedImage->type() != SharedImage::TYUVImage) {
|
||||
return false;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "ShadowLayerUtilsGralloc.h"
|
||||
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "sampler.h"
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ShadowLayers.h"
|
||||
#include "ShadowLayerUtils.h"
|
||||
#include "TiledLayerBuffer.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
|
||||
|
||||
|
@ -16,6 +16,10 @@
|
||||
#include "GLContextProvider.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "gfxWindowsSurface.h"
|
||||
#include "WGLLibrary.h"
|
||||
|
@ -66,9 +66,10 @@ protected:
|
||||
|
||||
nsRefPtr<gfxImageSurface> mCachedTempSurface;
|
||||
gfxIntSize mCachedSize;
|
||||
gfxImageFormat mCachedFormat;
|
||||
gfxASurface::gfxImageFormat mCachedFormat;
|
||||
|
||||
gfxImageSurface* GetTempSurface(const gfxIntSize& aSize, const gfxImageFormat aFormat)
|
||||
gfxImageSurface* GetTempSurface(const gfxIntSize& aSize,
|
||||
const gfxASurface::gfxImageFormat aFormat)
|
||||
{
|
||||
if (!mCachedTempSurface ||
|
||||
aSize.width != mCachedSize.width ||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "gfxSharedImageSurface.h"
|
||||
#include "mozilla/layers/ImageContainerParent.h"
|
||||
|
||||
#include "ImageContainer.h" // for PlanarYCBCRImage
|
||||
#include "ipc/AutoOpenSurface.h"
|
||||
#include "ImageLayerOGL.h"
|
||||
#include "gfxImageSurface.h"
|
||||
@ -243,12 +244,12 @@ ImageLayerOGL::RenderLayer(int,
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(image->GetFormat() != Image::REMOTE_IMAGE_BITMAP,
|
||||
NS_ASSERTION(image->GetFormat() != ImageFormat::REMOTE_IMAGE_BITMAP,
|
||||
"Remote images aren't handled yet in OGL layers!");
|
||||
NS_ASSERTION(mScaleMode == SCALE_NONE,
|
||||
"Scale modes other than none not handled yet in OGL layers!");
|
||||
|
||||
if (image->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImage *yuvImage =
|
||||
static_cast<PlanarYCbCrImage*>(image);
|
||||
|
||||
@ -308,7 +309,7 @@ ImageLayerOGL::RenderLayer(int,
|
||||
// We shouldn't need to do this, but do it anyway just in case
|
||||
// someone else forgets.
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
} else if (image->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
} else if (image->GetFormat() == ImageFormat::CAIRO_SURFACE) {
|
||||
CairoImage *cairoImage =
|
||||
static_cast<CairoImage*>(image);
|
||||
|
||||
@ -384,7 +385,7 @@ ImageLayerOGL::RenderLayer(int,
|
||||
}
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
} else if (image->GetFormat() == Image::MAC_IO_SURFACE) {
|
||||
} else if (image->GetFormat() == ImageFormat::MAC_IO_SURFACE) {
|
||||
MacIOSurfaceImage *ioImage =
|
||||
static_cast<MacIOSurfaceImage*>(image);
|
||||
|
||||
@ -440,7 +441,7 @@ ImageLayerOGL::RenderLayer(int,
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
} else if (image->GetFormat() == Image::GONK_IO_SURFACE) {
|
||||
} else if (image->GetFormat() == ImageFormat::GONK_IO_SURFACE) {
|
||||
|
||||
GonkIOSurfaceImage *ioImage = static_cast<GonkIOSurfaceImage*>(image);
|
||||
if (!ioImage) {
|
||||
@ -635,7 +636,7 @@ ImageLayerOGL::LoadAsTexture(GLuint aTextureUnit, gfxIntSize* aSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (image->GetFormat() != Image::CAIRO_SURFACE) {
|
||||
if (image->GetFormat() != ImageFormat::CAIRO_SURFACE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,16 @@
|
||||
|
||||
#include "LayerManagerOGL.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "yuv_convert.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class CairoImage;
|
||||
class PlanarYCbCrImage;
|
||||
|
||||
/**
|
||||
* This class wraps a GL texture. It includes a GLContext reference
|
||||
* so we can use to free the texture when destroyed. The implementation
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxPattern.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "imgIContainer.h"
|
||||
|
||||
|
@ -17,7 +17,8 @@
|
||||
#include "prmem.h"
|
||||
#include "prenv.h"
|
||||
#include "ImageLogging.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "Layers.h"
|
||||
|
||||
#include "nsPNGDecoder.h"
|
||||
#include "nsGIFDecoder2.h"
|
||||
@ -882,7 +883,7 @@ RasterImage::GetImageContainer(ImageContainer **_retval)
|
||||
mImageContainer = LayerManager::CreateImageContainer();
|
||||
|
||||
// Now create a CairoImage to display the surface.
|
||||
layers::Image::Format cairoFormat = layers::Image::CAIRO_SURFACE;
|
||||
ImageFormat cairoFormat = ImageFormat::CAIRO_SURFACE;
|
||||
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(&cairoFormat, 1);
|
||||
NS_ASSERTION(image, "Failed to create Image");
|
||||
|
||||
|
@ -3188,7 +3188,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
|
||||
// build the image and container
|
||||
container = aLayer->Manager()->CreateImageContainer();
|
||||
NS_ASSERTION(container, "Could not create image container for mask layer.");
|
||||
static const Image::Format format = Image::CAIRO_SURFACE;
|
||||
static const ImageFormat format = ImageFormat::CAIRO_SURFACE;
|
||||
nsRefPtr<Image> image = container->CreateImage(&format, 1);
|
||||
NS_ASSERTION(image, "Could not create image container for mask layer.");
|
||||
CairoImage::Data data;
|
||||
|
@ -4,11 +4,20 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MaskLayerImageCache.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
using namespace mozilla::layers;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MaskLayerImageCache::MaskLayerImageCache()
|
||||
{
|
||||
mMaskImageContainers.Init();
|
||||
}
|
||||
MaskLayerImageCache::~MaskLayerImageCache()
|
||||
{}
|
||||
|
||||
|
||||
/* static */ PLDHashOperator
|
||||
MaskLayerImageCache::SweepFunc(MaskLayerImageEntry* aEntry,
|
||||
void* aUserArg)
|
||||
|
@ -8,10 +8,13 @@
|
||||
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "ImageLayers.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class ImageContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps a record of image containers for mask layers, containers are mapped
|
||||
* from the rounded rects used to create them.
|
||||
@ -29,10 +32,8 @@ class MaskLayerImageCache
|
||||
{
|
||||
typedef mozilla::layers::ImageContainer ImageContainer;
|
||||
public:
|
||||
MaskLayerImageCache()
|
||||
{
|
||||
mMaskImageContainers.Init();
|
||||
}
|
||||
MaskLayerImageCache();
|
||||
~MaskLayerImageCache();
|
||||
|
||||
/**
|
||||
* Representation of a rounded rectangle in device pixel coordinates, in
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "sampler.h"
|
||||
#include "nsCSSRenderingBorders.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::css;
|
||||
|
@ -41,6 +41,8 @@
|
||||
#include "nsAnimationManager.h"
|
||||
#include "nsTransitionManager.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
#include "mozilla/StandardInteger.h"
|
||||
|
||||
@ -1383,6 +1385,13 @@ nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayBackground::~nsDisplayBackground()
|
||||
{
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
MOZ_COUNT_DTOR(nsDisplayBackground);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper for RoundedRectIntersectsRect.
|
||||
static bool
|
||||
CheckCorner(nscoord aXOffset, nscoord aYOffset,
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "nsRegion.h"
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsThemeConstants.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#include "mozilla/StandardInteger.h"
|
||||
@ -37,6 +36,13 @@ class nsDeviceContext;
|
||||
class nsDisplayTableItem;
|
||||
class nsDisplayItem;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class ImageLayer;
|
||||
class ImageContainer;
|
||||
} //namepsace
|
||||
} //namepsace
|
||||
|
||||
/*
|
||||
* An nsIFrame can have many different visual parts. For example an image frame
|
||||
* can have a background, border, and outline, the image itself, and a
|
||||
@ -1592,11 +1598,7 @@ private:
|
||||
class nsDisplayBackground : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayBackground() {
|
||||
MOZ_COUNT_DTOR(nsDisplayBackground);
|
||||
}
|
||||
#endif
|
||||
virtual ~nsDisplayBackground();
|
||||
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
|
@ -66,6 +66,7 @@
|
||||
|
||||
#include "gfxRect.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Util.h" // for DebugOnly
|
||||
|
@ -88,6 +88,7 @@
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "ImageLayers.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "gfxWindowsNativeDrawing.h"
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "nsCSSRendering.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "ImageLayers.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "nsAccessibilityService.h"
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsRegion.h"
|
||||
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "Framebuffer.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "LayerManagerOGL.h"
|
||||
|
Loading…
Reference in New Issue
Block a user