1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/ImageContainer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,649 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#include "ImageContainer.h" 1.11 +#include <string.h> // for memcpy, memset 1.12 +#include "SharedTextureImage.h" // for SharedTextureImage 1.13 +#include "gfx2DGlue.h" 1.14 +#include "gfxPlatform.h" // for gfxPlatform 1.15 +#include "gfxUtils.h" // for gfxUtils 1.16 +#include "mozilla/RefPtr.h" // for TemporaryRef 1.17 +#include "mozilla/ipc/CrossProcessMutex.h" // for CrossProcessMutex, etc 1.18 +#include "mozilla/layers/CompositorTypes.h" 1.19 +#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild 1.20 +#include "mozilla/layers/ImageClient.h" // for ImageClient 1.21 +#include "nsISupportsUtils.h" // for NS_IF_ADDREF 1.22 +#include "YCbCrUtils.h" // for YCbCr conversions 1.23 +#ifdef MOZ_WIDGET_GONK 1.24 +#include "GrallocImages.h" 1.25 +#endif 1.26 +#include "gfx2DGlue.h" 1.27 +#include "mozilla/gfx/2D.h" 1.28 + 1.29 +#ifdef XP_MACOSX 1.30 +#include "mozilla/gfx/QuartzSupport.h" 1.31 +#include "MacIOSurfaceImage.h" 1.32 +#endif 1.33 + 1.34 +#ifdef XP_WIN 1.35 +#include "gfxD2DSurface.h" 1.36 +#include "gfxWindowsPlatform.h" 1.37 +#include <d3d10_1.h> 1.38 +#include "d3d10/ImageLayerD3D10.h" 1.39 +#include "D3D9SurfaceImage.h" 1.40 +#endif 1.41 + 1.42 +using namespace mozilla::ipc; 1.43 +using namespace android; 1.44 +using namespace mozilla::gfx; 1.45 + 1.46 + 1.47 +namespace mozilla { 1.48 +namespace layers { 1.49 + 1.50 + 1.51 +Atomic<int32_t> Image::sSerialCounter(0); 1.52 + 1.53 +already_AddRefed<Image> 1.54 +ImageFactory::CreateImage(ImageFormat aFormat, 1.55 + const gfx::IntSize &, 1.56 + BufferRecycleBin *aRecycleBin) 1.57 +{ 1.58 + nsRefPtr<Image> img; 1.59 +#ifdef MOZ_WIDGET_GONK 1.60 + if (aFormat == ImageFormat::GRALLOC_PLANAR_YCBCR) { 1.61 + img = new GrallocImage(); 1.62 + return img.forget(); 1.63 + } 1.64 +#endif 1.65 + if (aFormat == ImageFormat::PLANAR_YCBCR) { 1.66 + img = new PlanarYCbCrImage(aRecycleBin); 1.67 + return img.forget(); 1.68 + } 1.69 + if (aFormat == ImageFormat::CAIRO_SURFACE) { 1.70 + img = new CairoImage(); 1.71 + return img.forget(); 1.72 + } 1.73 + if (aFormat == ImageFormat::SHARED_TEXTURE) { 1.74 + img = new SharedTextureImage(); 1.75 + return img.forget(); 1.76 + } 1.77 +#ifdef XP_MACOSX 1.78 + if (aFormat == ImageFormat::MAC_IOSURFACE) { 1.79 + img = new MacIOSurfaceImage(); 1.80 + return img.forget(); 1.81 + } 1.82 +#endif 1.83 +#ifdef XP_WIN 1.84 + if (aFormat == ImageFormat::D3D9_RGB32_TEXTURE) { 1.85 + img = new D3D9SurfaceImage(); 1.86 + return img.forget(); 1.87 + } 1.88 +#endif 1.89 + return nullptr; 1.90 +} 1.91 + 1.92 +BufferRecycleBin::BufferRecycleBin() 1.93 + : mLock("mozilla.layers.BufferRecycleBin.mLock") 1.94 +{ 1.95 +} 1.96 + 1.97 +void 1.98 +BufferRecycleBin::RecycleBuffer(uint8_t* aBuffer, uint32_t aSize) 1.99 +{ 1.100 + MutexAutoLock lock(mLock); 1.101 + 1.102 + if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) { 1.103 + mRecycledBuffers.Clear(); 1.104 + } 1.105 + mRecycledBufferSize = aSize; 1.106 + mRecycledBuffers.AppendElement(aBuffer); 1.107 +} 1.108 + 1.109 +uint8_t* 1.110 +BufferRecycleBin::GetBuffer(uint32_t aSize) 1.111 +{ 1.112 + MutexAutoLock lock(mLock); 1.113 + 1.114 + if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize) 1.115 + return new uint8_t[aSize]; 1.116 + 1.117 + uint32_t last = mRecycledBuffers.Length() - 1; 1.118 + uint8_t* result = mRecycledBuffers[last].forget(); 1.119 + mRecycledBuffers.RemoveElementAt(last); 1.120 + return result; 1.121 +} 1.122 + 1.123 +ImageContainer::ImageContainer(int flag) 1.124 +: mReentrantMonitor("ImageContainer.mReentrantMonitor"), 1.125 + mPaintCount(0), 1.126 + mPreviousImagePainted(false), 1.127 + mImageFactory(new ImageFactory()), 1.128 + mRecycleBin(new BufferRecycleBin()), 1.129 + mRemoteData(nullptr), 1.130 + mRemoteDataMutex(nullptr), 1.131 + mCompositionNotifySink(nullptr), 1.132 + mImageClient(nullptr) 1.133 +{ 1.134 + if (flag == ENABLE_ASYNC && ImageBridgeChild::IsCreated()) { 1.135 + // the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount 1.136 + // of this class must be done on the ImageBridge thread. 1.137 + mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(BUFFER_IMAGE_SINGLE).drop(); 1.138 + MOZ_ASSERT(mImageClient); 1.139 + } 1.140 +} 1.141 + 1.142 +ImageContainer::~ImageContainer() 1.143 +{ 1.144 + if (IsAsync()) { 1.145 + ImageBridgeChild::DispatchReleaseImageClient(mImageClient); 1.146 + } 1.147 +} 1.148 + 1.149 +already_AddRefed<Image> 1.150 +ImageContainer::CreateImage(ImageFormat aFormat) 1.151 +{ 1.152 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.153 + 1.154 + if (mImageClient) { 1.155 + nsRefPtr<Image> img = mImageClient->CreateImage(aFormat); 1.156 + if (img) { 1.157 + return img.forget(); 1.158 + } 1.159 + } 1.160 + return mImageFactory->CreateImage(aFormat, mScaleHint, mRecycleBin); 1.161 +} 1.162 + 1.163 +void 1.164 +ImageContainer::SetCurrentImageInternal(Image *aImage) 1.165 +{ 1.166 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.167 + 1.168 + if (mRemoteData) { 1.169 + NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); 1.170 + mRemoteDataMutex->Lock(); 1.171 + // This is important since it ensures we won't change the active image 1.172 + // when we currently have a locked image that depends on mRemoteData. 1.173 + } 1.174 + 1.175 + mActiveImage = aImage; 1.176 + CurrentImageChanged(); 1.177 + 1.178 + if (mRemoteData) { 1.179 + mRemoteDataMutex->Unlock(); 1.180 + } 1.181 +} 1.182 + 1.183 +void 1.184 +ImageContainer::ClearCurrentImage() 1.185 +{ 1.186 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.187 + SetCurrentImageInternal(nullptr); 1.188 +} 1.189 + 1.190 +void 1.191 +ImageContainer::SetCurrentImage(Image *aImage) 1.192 +{ 1.193 + if (!aImage) { 1.194 + ClearAllImages(); 1.195 + return; 1.196 + } 1.197 + 1.198 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.199 + if (IsAsync()) { 1.200 + ImageBridgeChild::DispatchImageClientUpdate(mImageClient, this); 1.201 + } 1.202 + SetCurrentImageInternal(aImage); 1.203 +} 1.204 + 1.205 + void 1.206 +ImageContainer::ClearAllImages() 1.207 +{ 1.208 + if (IsAsync()) { 1.209 + // Let ImageClient release all TextureClients. 1.210 + ImageBridgeChild::FlushAllImages(mImageClient, this, false); 1.211 + return; 1.212 + } 1.213 + 1.214 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.215 + SetCurrentImageInternal(nullptr); 1.216 +} 1.217 + 1.218 +void 1.219 +ImageContainer::ClearAllImagesExceptFront() 1.220 +{ 1.221 + if (IsAsync()) { 1.222 + // Let ImageClient release all TextureClients except front one. 1.223 + ImageBridgeChild::FlushAllImages(mImageClient, this, true); 1.224 + } 1.225 +} 1.226 + 1.227 +void 1.228 +ImageContainer::SetCurrentImageInTransaction(Image *aImage) 1.229 +{ 1.230 + NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); 1.231 + NS_ASSERTION(!mImageClient, "Should use async image transfer with ImageBridge."); 1.232 + 1.233 + SetCurrentImageInternal(aImage); 1.234 +} 1.235 + 1.236 +bool ImageContainer::IsAsync() const { 1.237 + return mImageClient != nullptr; 1.238 +} 1.239 + 1.240 +uint64_t ImageContainer::GetAsyncContainerID() const 1.241 +{ 1.242 + NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers"); 1.243 + if (IsAsync()) { 1.244 + return mImageClient->GetAsyncID(); 1.245 + } else { 1.246 + return 0; // zero is always an invalid AsyncID 1.247 + } 1.248 +} 1.249 + 1.250 +bool 1.251 +ImageContainer::HasCurrentImage() 1.252 +{ 1.253 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.254 + 1.255 + if (mRemoteData) { 1.256 + CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); 1.257 + 1.258 + EnsureActiveImage(); 1.259 + 1.260 + return !!mActiveImage.get(); 1.261 + } 1.262 + 1.263 + return !!mActiveImage.get(); 1.264 +} 1.265 + 1.266 +already_AddRefed<Image> 1.267 +ImageContainer::LockCurrentImage() 1.268 +{ 1.269 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.270 + 1.271 + if (mRemoteData) { 1.272 + NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); 1.273 + mRemoteDataMutex->Lock(); 1.274 + } 1.275 + 1.276 + EnsureActiveImage(); 1.277 + 1.278 + nsRefPtr<Image> retval = mActiveImage; 1.279 + return retval.forget(); 1.280 +} 1.281 + 1.282 +TemporaryRef<gfx::SourceSurface> 1.283 +ImageContainer::LockCurrentAsSourceSurface(gfx::IntSize *aSize, Image** aCurrentImage) 1.284 +{ 1.285 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.286 + 1.287 + if (mRemoteData) { 1.288 + NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); 1.289 + mRemoteDataMutex->Lock(); 1.290 + 1.291 + EnsureActiveImage(); 1.292 + 1.293 + if (aCurrentImage) { 1.294 + NS_IF_ADDREF(mActiveImage); 1.295 + *aCurrentImage = mActiveImage.get(); 1.296 + } 1.297 + 1.298 + if (!mActiveImage) { 1.299 + return nullptr; 1.300 + } 1.301 + 1.302 + if (mActiveImage->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP) { 1.303 + gfxImageFormat fmt = mRemoteData->mFormat == RemoteImageData::BGRX32 1.304 + ? gfxImageFormat::ARGB32 1.305 + : gfxImageFormat::RGB24; 1.306 + 1.307 + RefPtr<gfx::DataSourceSurface> newSurf 1.308 + = gfx::Factory::CreateWrappingDataSourceSurface(mRemoteData->mBitmap.mData, 1.309 + mRemoteData->mBitmap.mStride, 1.310 + mRemoteData->mSize, 1.311 + gfx::ImageFormatToSurfaceFormat(fmt)); 1.312 + *aSize = newSurf->GetSize(); 1.313 + 1.314 + return newSurf; 1.315 + } 1.316 + 1.317 + *aSize = mActiveImage->GetSize(); 1.318 + return mActiveImage->GetAsSourceSurface(); 1.319 + } 1.320 + 1.321 + if (aCurrentImage) { 1.322 + NS_IF_ADDREF(mActiveImage); 1.323 + *aCurrentImage = mActiveImage.get(); 1.324 + } 1.325 + 1.326 + if (!mActiveImage) { 1.327 + return nullptr; 1.328 + } 1.329 + 1.330 + *aSize = mActiveImage->GetSize(); 1.331 + return mActiveImage->GetAsSourceSurface(); 1.332 +} 1.333 + 1.334 +void 1.335 +ImageContainer::UnlockCurrentImage() 1.336 +{ 1.337 + if (mRemoteData) { 1.338 + NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!"); 1.339 + mRemoteDataMutex->Unlock(); 1.340 + } 1.341 +} 1.342 + 1.343 +TemporaryRef<gfx::SourceSurface> 1.344 +ImageContainer::GetCurrentAsSourceSurface(gfx::IntSize *aSize) 1.345 +{ 1.346 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.347 + 1.348 + if (mRemoteData) { 1.349 + CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); 1.350 + EnsureActiveImage(); 1.351 + 1.352 + if (!mActiveImage) 1.353 + return nullptr; 1.354 + *aSize = mRemoteData->mSize; 1.355 + } else { 1.356 + if (!mActiveImage) 1.357 + return nullptr; 1.358 + *aSize = mActiveImage->GetSize(); 1.359 + } 1.360 + return mActiveImage->GetAsSourceSurface(); 1.361 +} 1.362 + 1.363 +gfx::IntSize 1.364 +ImageContainer::GetCurrentSize() 1.365 +{ 1.366 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.367 + 1.368 + if (mRemoteData) { 1.369 + CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex); 1.370 + 1.371 + // We don't need to ensure we have an active image here, as we need to 1.372 + // be in the mutex anyway, and this is easiest to return from there. 1.373 + return mRemoteData->mSize; 1.374 + } 1.375 + 1.376 + if (!mActiveImage) { 1.377 + return gfx::IntSize(0, 0); 1.378 + } 1.379 + 1.380 + return mActiveImage->GetSize(); 1.381 +} 1.382 + 1.383 +void 1.384 +ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex) 1.385 +{ 1.386 + ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.387 + 1.388 + NS_ASSERTION(!mActiveImage || !aData, "No active image expected when SetRemoteImageData is called with non-NULL aData."); 1.389 + NS_ASSERTION(!mRemoteData || !aData, "No remote data expected when SetRemoteImageData is called with non-NULL aData."); 1.390 + 1.391 + mRemoteData = aData; 1.392 + 1.393 + if (aData) { 1.394 + memset(aData, 0, sizeof(RemoteImageData)); 1.395 + } else { 1.396 + mActiveImage = nullptr; 1.397 + } 1.398 + 1.399 + mRemoteDataMutex = aMutex; 1.400 +} 1.401 + 1.402 +void 1.403 +ImageContainer::EnsureActiveImage() 1.404 +{ 1.405 + if (mRemoteData) { 1.406 + if (mRemoteData->mWasUpdated) { 1.407 + mActiveImage = nullptr; 1.408 + } 1.409 + 1.410 + if (mRemoteData->mType == RemoteImageData::RAW_BITMAP && 1.411 + mRemoteData->mBitmap.mData && !mActiveImage) { 1.412 + nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage(); 1.413 + 1.414 + newImg->mFormat = mRemoteData->mFormat; 1.415 + newImg->mData = mRemoteData->mBitmap.mData; 1.416 + newImg->mSize = mRemoteData->mSize; 1.417 + newImg->mStride = mRemoteData->mBitmap.mStride; 1.418 + mRemoteData->mWasUpdated = false; 1.419 + 1.420 + mActiveImage = newImg; 1.421 + } 1.422 +#ifdef XP_WIN 1.423 + else if (mRemoteData->mType == RemoteImageData::DXGI_TEXTURE_HANDLE && 1.424 + mRemoteData->mTextureHandle && !mActiveImage) { 1.425 + nsRefPtr<RemoteDXGITextureImage> newImg = new RemoteDXGITextureImage(); 1.426 + newImg->mSize = mRemoteData->mSize; 1.427 + newImg->mHandle = mRemoteData->mTextureHandle; 1.428 + newImg->mFormat = mRemoteData->mFormat; 1.429 + mRemoteData->mWasUpdated = false; 1.430 + 1.431 + mActiveImage = newImg; 1.432 + } 1.433 +#endif 1.434 + } 1.435 +} 1.436 + 1.437 + 1.438 +PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin) 1.439 + : Image(nullptr, ImageFormat::PLANAR_YCBCR) 1.440 + , mBufferSize(0) 1.441 + , mOffscreenFormat(gfxImageFormat::Unknown) 1.442 + , mRecycleBin(aRecycleBin) 1.443 +{ 1.444 +} 1.445 + 1.446 +PlanarYCbCrImage::~PlanarYCbCrImage() 1.447 +{ 1.448 + if (mBuffer) { 1.449 + mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize); 1.450 + } 1.451 +} 1.452 + 1.453 +size_t 1.454 +PlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.455 +{ 1.456 + // Ignoring: 1.457 + // - mData - just wraps mBuffer 1.458 + // - Surfaces should be reported under gfx-surfaces-*: 1.459 + // - mSourceSurface 1.460 + // - Base class: 1.461 + // - mImplData is not used 1.462 + // Not owned: 1.463 + // - mRecycleBin 1.464 + size_t size = mBuffer.SizeOfExcludingThis(aMallocSizeOf); 1.465 + 1.466 + // Could add in the future: 1.467 + // - mBackendData (from base class) 1.468 + 1.469 + return size; 1.470 +} 1.471 + 1.472 +uint8_t* 1.473 +PlanarYCbCrImage::AllocateBuffer(uint32_t aSize) 1.474 +{ 1.475 + return mRecycleBin->GetBuffer(aSize); 1.476 +} 1.477 + 1.478 +static void 1.479 +CopyPlane(uint8_t *aDst, const uint8_t *aSrc, 1.480 + const gfx::IntSize &aSize, int32_t aStride, int32_t aSkip) 1.481 +{ 1.482 + if (!aSkip) { 1.483 + // Fast path: planar input. 1.484 + memcpy(aDst, aSrc, aSize.height * aStride); 1.485 + } else { 1.486 + int32_t height = aSize.height; 1.487 + int32_t width = aSize.width; 1.488 + for (int y = 0; y < height; ++y) { 1.489 + const uint8_t *src = aSrc; 1.490 + uint8_t *dst = aDst; 1.491 + // Slow path 1.492 + for (int x = 0; x < width; ++x) { 1.493 + *dst++ = *src++; 1.494 + src += aSkip; 1.495 + } 1.496 + aSrc += aStride; 1.497 + aDst += aStride; 1.498 + } 1.499 + } 1.500 +} 1.501 + 1.502 +void 1.503 +PlanarYCbCrImage::CopyData(const Data& aData) 1.504 +{ 1.505 + mData = aData; 1.506 + 1.507 + // update buffer size 1.508 + size_t size = mData.mCbCrStride * mData.mCbCrSize.height * 2 + 1.509 + mData.mYStride * mData.mYSize.height; 1.510 + 1.511 + // get new buffer 1.512 + mBuffer = AllocateBuffer(size); 1.513 + if (!mBuffer) 1.514 + return; 1.515 + 1.516 + // update buffer size 1.517 + mBufferSize = size; 1.518 + 1.519 + mData.mYChannel = mBuffer; 1.520 + mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height; 1.521 + mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height; 1.522 + 1.523 + CopyPlane(mData.mYChannel, aData.mYChannel, 1.524 + mData.mYSize, mData.mYStride, mData.mYSkip); 1.525 + CopyPlane(mData.mCbChannel, aData.mCbChannel, 1.526 + mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip); 1.527 + CopyPlane(mData.mCrChannel, aData.mCrChannel, 1.528 + mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip); 1.529 + 1.530 + mSize = aData.mPicSize; 1.531 +} 1.532 + 1.533 +void 1.534 +PlanarYCbCrImage::SetData(const Data &aData) 1.535 +{ 1.536 + CopyData(aData); 1.537 +} 1.538 + 1.539 +gfxImageFormat 1.540 +PlanarYCbCrImage::GetOffscreenFormat() 1.541 +{ 1.542 + return mOffscreenFormat == gfxImageFormat::Unknown ? 1.543 + gfxPlatform::GetPlatform()->GetOffscreenFormat() : 1.544 + mOffscreenFormat; 1.545 +} 1.546 + 1.547 +void 1.548 +PlanarYCbCrImage::SetDataNoCopy(const Data &aData) 1.549 +{ 1.550 + mData = aData; 1.551 + mSize = aData.mPicSize; 1.552 +} 1.553 + 1.554 +uint8_t* 1.555 +PlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize) 1.556 +{ 1.557 + // get new buffer 1.558 + mBuffer = AllocateBuffer(aSize); 1.559 + if (mBuffer) { 1.560 + // update buffer size 1.561 + mBufferSize = aSize; 1.562 + } 1.563 + return mBuffer; 1.564 +} 1.565 + 1.566 +TemporaryRef<gfx::SourceSurface> 1.567 +PlanarYCbCrImage::GetAsSourceSurface() 1.568 +{ 1.569 + if (mSourceSurface) { 1.570 + return mSourceSurface.get(); 1.571 + } 1.572 + 1.573 + gfx::IntSize size(mSize); 1.574 + gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat()); 1.575 + gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size); 1.576 + if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION || 1.577 + mSize.height > PlanarYCbCrImage::MAX_DIMENSION) { 1.578 + NS_ERROR("Illegal image dest width or height"); 1.579 + return nullptr; 1.580 + } 1.581 + 1.582 + RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format); 1.583 + 1.584 + gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride()); 1.585 + 1.586 + mSourceSurface = surface; 1.587 + 1.588 + return surface.forget(); 1.589 +} 1.590 + 1.591 +TemporaryRef<gfx::SourceSurface> 1.592 +RemoteBitmapImage::GetAsSourceSurface() 1.593 +{ 1.594 + gfx::SurfaceFormat fmt = mFormat == RemoteImageData::BGRX32 1.595 + ? gfx::SurfaceFormat::B8G8R8X8 1.596 + : gfx::SurfaceFormat::B8G8R8A8; 1.597 + RefPtr<gfx::DataSourceSurface> newSurf = gfx::Factory::CreateDataSourceSurface(mSize, fmt); 1.598 + 1.599 + for (int y = 0; y < mSize.height; y++) { 1.600 + memcpy(newSurf->GetData() + newSurf->Stride() * y, 1.601 + mData + mStride * y, 1.602 + mSize.width * 4); 1.603 + } 1.604 + 1.605 + return newSurf; 1.606 +} 1.607 + 1.608 +CairoImage::CairoImage() 1.609 + : Image(nullptr, ImageFormat::CAIRO_SURFACE) 1.610 +{} 1.611 + 1.612 +CairoImage::~CairoImage() 1.613 +{ 1.614 +} 1.615 + 1.616 +TextureClient* 1.617 +CairoImage::GetTextureClient(CompositableClient *aClient) 1.618 +{ 1.619 + CompositableForwarder* forwarder = aClient->GetForwarder(); 1.620 + RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial()); 1.621 + if (textureClient) { 1.622 + return textureClient; 1.623 + } 1.624 + 1.625 + RefPtr<SourceSurface> surface = GetAsSourceSurface(); 1.626 + MOZ_ASSERT(surface); 1.627 + 1.628 + // gfx::BackendType::NONE means default to content backend 1.629 + textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), 1.630 + TEXTURE_FLAGS_DEFAULT, 1.631 + gfx::BackendType::NONE, 1.632 + surface->GetSize()); 1.633 + MOZ_ASSERT(textureClient->CanExposeDrawTarget()); 1.634 + if (!textureClient->AllocateForSurface(surface->GetSize()) || 1.635 + !textureClient->Lock(OPEN_WRITE_ONLY)) { 1.636 + return nullptr; 1.637 + } 1.638 + 1.639 + { 1.640 + // We must not keep a reference to the DrawTarget after it has been unlocked. 1.641 + RefPtr<DrawTarget> dt = textureClient->GetAsDrawTarget(); 1.642 + dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); 1.643 + } 1.644 + 1.645 + textureClient->Unlock(); 1.646 + 1.647 + mTextureClients.Put(forwarder->GetSerial(), textureClient); 1.648 + return textureClient; 1.649 +} 1.650 + 1.651 +} // namespace 1.652 +} // namespace