1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/basic/BasicImages.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,183 @@ 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 +#include <stdint.h> // for uint8_t, uint32_t 1.10 +#include "BasicLayers.h" // for BasicLayerManager 1.11 +#include "ImageContainer.h" // for PlanarYCbCrImage, etc 1.12 +#include "ImageTypes.h" // for ImageFormat, etc 1.13 +#include "cairo.h" // for cairo_user_data_key_t 1.14 +#include "gfxASurface.h" // for gfxASurface, etc 1.15 +#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat 1.16 +#include "gfxUtils.h" // for gfxUtils 1.17 +#include "mozilla/mozalloc.h" // for operator delete[], etc 1.18 +#include "nsAutoPtr.h" // for nsRefPtr, nsAutoArrayPtr 1.19 +#include "nsAutoRef.h" // for nsCountedRef 1.20 +#include "nsCOMPtr.h" // for already_AddRefed 1.21 +#include "nsDebug.h" // for NS_ERROR, NS_ASSERTION 1.22 +#include "nsISupportsImpl.h" // for Image::Release, etc 1.23 +#include "nsThreadUtils.h" // for NS_IsMainThread 1.24 +#include "mozilla/gfx/Point.h" // for IntSize 1.25 +#include "gfx2DGlue.h" 1.26 +#include "YCbCrUtils.h" // for YCbCr conversions 1.27 +#ifdef XP_MACOSX 1.28 +#include "gfxQuartzImageSurface.h" 1.29 +#endif 1.30 + 1.31 +namespace mozilla { 1.32 +namespace layers { 1.33 + 1.34 +class BasicPlanarYCbCrImage : public PlanarYCbCrImage 1.35 +{ 1.36 +public: 1.37 + BasicPlanarYCbCrImage(const gfx::IntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin) 1.38 + : PlanarYCbCrImage(aRecycleBin) 1.39 + , mScaleHint(aScaleHint) 1.40 + , mDelayedConversion(false) 1.41 + { 1.42 + SetOffscreenFormat(aOffscreenFormat); 1.43 + } 1.44 + 1.45 + ~BasicPlanarYCbCrImage() 1.46 + { 1.47 + if (mDecodedBuffer) { 1.48 + // Right now this only happens if the Image was never drawn, otherwise 1.49 + // this will have been tossed away at surface destruction. 1.50 + mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride); 1.51 + } 1.52 + } 1.53 + 1.54 + virtual void SetData(const Data& aData); 1.55 + virtual void SetDelayedConversion(bool aDelayed) { mDelayedConversion = aDelayed; } 1.56 + 1.57 + TemporaryRef<gfx::SourceSurface> GetAsSourceSurface(); 1.58 + 1.59 + virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE 1.60 + { 1.61 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.62 + } 1.63 + 1.64 + virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE 1.65 + { 1.66 + size_t size = PlanarYCbCrImage::SizeOfExcludingThis(aMallocSizeOf); 1.67 + size += mDecodedBuffer.SizeOfExcludingThis(aMallocSizeOf); 1.68 + return size; 1.69 + } 1.70 + 1.71 +private: 1.72 + nsAutoArrayPtr<uint8_t> mDecodedBuffer; 1.73 + gfx::IntSize mScaleHint; 1.74 + int mStride; 1.75 + bool mDelayedConversion; 1.76 +}; 1.77 + 1.78 +class BasicImageFactory : public ImageFactory 1.79 +{ 1.80 +public: 1.81 + BasicImageFactory() {} 1.82 + 1.83 + virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat, 1.84 + const gfx::IntSize &aScaleHint, 1.85 + BufferRecycleBin *aRecycleBin) 1.86 + { 1.87 + nsRefPtr<Image> image; 1.88 + if (aFormat == ImageFormat::PLANAR_YCBCR) { 1.89 + image = new BasicPlanarYCbCrImage(aScaleHint, gfxPlatform::GetPlatform()->GetOffscreenFormat(), aRecycleBin); 1.90 + return image.forget(); 1.91 + } 1.92 + 1.93 + return ImageFactory::CreateImage(aFormat, aScaleHint, aRecycleBin); 1.94 + } 1.95 +}; 1.96 + 1.97 +void 1.98 +BasicPlanarYCbCrImage::SetData(const Data& aData) 1.99 +{ 1.100 + PlanarYCbCrImage::SetData(aData); 1.101 + 1.102 + if (mDelayedConversion) { 1.103 + return; 1.104 + } 1.105 + 1.106 + // Do some sanity checks to prevent integer overflow 1.107 + if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION || 1.108 + aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) { 1.109 + NS_ERROR("Illegal image source width or height"); 1.110 + return; 1.111 + } 1.112 + 1.113 + gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat()); 1.114 + 1.115 + gfx::IntSize size(mScaleHint); 1.116 + gfx::GetYCbCrToRGBDestFormatAndSize(aData, format, size); 1.117 + if (size.width > PlanarYCbCrImage::MAX_DIMENSION || 1.118 + size.height > PlanarYCbCrImage::MAX_DIMENSION) { 1.119 + NS_ERROR("Illegal image dest width or height"); 1.120 + return; 1.121 + } 1.122 + 1.123 + gfxImageFormat iFormat = gfx::SurfaceFormatToImageFormat(format); 1.124 + mStride = gfxASurface::FormatStrideForWidth(iFormat, size.width); 1.125 + mDecodedBuffer = AllocateBuffer(size.height * mStride); 1.126 + if (!mDecodedBuffer) { 1.127 + // out of memory 1.128 + return; 1.129 + } 1.130 + 1.131 + gfx::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer, mStride); 1.132 + SetOffscreenFormat(iFormat); 1.133 + mSize = size; 1.134 +} 1.135 + 1.136 +TemporaryRef<gfx::SourceSurface> 1.137 +BasicPlanarYCbCrImage::GetAsSourceSurface() 1.138 +{ 1.139 + NS_ASSERTION(NS_IsMainThread(), "Must be main thread"); 1.140 + 1.141 + if (mSourceSurface) { 1.142 + return mSourceSurface.get(); 1.143 + } 1.144 + 1.145 + if (!mDecodedBuffer) { 1.146 + return PlanarYCbCrImage::GetAsSourceSurface(); 1.147 + } 1.148 + 1.149 + gfxImageFormat format = GetOffscreenFormat(); 1.150 + 1.151 + RefPtr<gfx::SourceSurface> surface; 1.152 + { 1.153 + // Create a DrawTarget so that we can own the data inside mDecodeBuffer. 1.154 + // We create the target out of mDecodedBuffer, and get a snapshot from it. 1.155 + // The draw target is destroyed on scope exit and the surface owns the data. 1.156 + RefPtr<gfx::DrawTarget> drawTarget 1.157 + = gfxPlatform::GetPlatform()->CreateDrawTargetForData(mDecodedBuffer, 1.158 + mSize, 1.159 + mStride, 1.160 + gfx::ImageFormatToSurfaceFormat(format)); 1.161 + if (!drawTarget) { 1.162 + return nullptr; 1.163 + } 1.164 + 1.165 + surface = drawTarget->Snapshot(); 1.166 + } 1.167 + 1.168 + mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride); 1.169 + 1.170 + mSourceSurface = surface; 1.171 + return mSourceSurface.get(); 1.172 +} 1.173 + 1.174 + 1.175 +ImageFactory* 1.176 +BasicLayerManager::GetImageFactory() 1.177 +{ 1.178 + if (!mFactory) { 1.179 + mFactory = new BasicImageFactory(); 1.180 + } 1.181 + 1.182 + return mFactory.get(); 1.183 +} 1.184 + 1.185 +} 1.186 +}