Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include <stdint.h> // for uint8_t, uint32_t
7 : #include "BasicLayers.h" // for BasicLayerManager
8 : #include "ImageContainer.h" // for PlanarYCbCrImage, etc
9 : #include "ImageTypes.h" // for ImageFormat, etc
10 : #include "cairo.h" // for cairo_user_data_key_t
11 : #include "gfxASurface.h" // for gfxASurface, etc
12 : #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
13 : #include "gfxUtils.h" // for gfxUtils
14 : #include "mozilla/CheckedInt.h"
15 : #include "mozilla/mozalloc.h" // for operator delete[], etc
16 : #include "mozilla/RefPtr.h"
17 : #include "mozilla/UniquePtr.h"
18 : #include "nsAutoRef.h" // for nsCountedRef
19 : #include "nsCOMPtr.h" // for already_AddRefed
20 : #include "nsDebug.h" // for NS_ERROR, NS_ASSERTION
21 : #include "nsISupportsImpl.h" // for Image::Release, etc
22 : #include "nsThreadUtils.h" // for NS_IsMainThread
23 : #include "mozilla/gfx/Point.h" // for IntSize
24 : #include "mozilla/gfx/DataSurfaceHelpers.h"
25 : #include "gfx2DGlue.h"
26 : #include "YCbCrUtils.h" // for YCbCr conversions
27 :
28 : namespace mozilla {
29 : namespace layers {
30 :
31 : class BasicPlanarYCbCrImage : public RecyclingPlanarYCbCrImage
32 : {
33 : public:
34 0 : BasicPlanarYCbCrImage(const gfx::IntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin)
35 0 : : RecyclingPlanarYCbCrImage(aRecycleBin)
36 : , mScaleHint(aScaleHint)
37 : , mStride(0)
38 0 : , mDelayedConversion(false)
39 : {
40 0 : SetOffscreenFormat(aOffscreenFormat);
41 0 : }
42 :
43 0 : ~BasicPlanarYCbCrImage()
44 0 : {
45 0 : if (mDecodedBuffer) {
46 : // Right now this only happens if the Image was never drawn, otherwise
47 : // this will have been tossed away at surface destruction.
48 0 : mRecycleBin->RecycleBuffer(Move(mDecodedBuffer), mSize.height * mStride);
49 : }
50 0 : }
51 :
52 : virtual bool CopyData(const Data& aData) override;
53 0 : virtual void SetDelayedConversion(bool aDelayed) override { mDelayedConversion = aDelayed; }
54 :
55 : already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
56 :
57 0 : virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
58 : {
59 0 : return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
60 : }
61 :
62 0 : virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
63 : {
64 0 : size_t size = RecyclingPlanarYCbCrImage::SizeOfExcludingThis(aMallocSizeOf);
65 0 : size += aMallocSizeOf(mDecodedBuffer.get());
66 0 : return size;
67 : }
68 :
69 : private:
70 : UniquePtr<uint8_t[]> mDecodedBuffer;
71 : gfx::IntSize mScaleHint;
72 : int mStride;
73 : bool mDelayedConversion;
74 : };
75 :
76 0 : class BasicImageFactory : public ImageFactory
77 : {
78 : public:
79 0 : BasicImageFactory() {}
80 :
81 : virtual RefPtr<PlanarYCbCrImage>
82 0 : CreatePlanarYCbCrImage(const gfx::IntSize& aScaleHint, BufferRecycleBin* aRecycleBin)
83 : {
84 0 : return new BasicPlanarYCbCrImage(aScaleHint, gfxPlatform::GetPlatform()->GetOffscreenFormat(), aRecycleBin);
85 : }
86 : };
87 :
88 : bool
89 0 : BasicPlanarYCbCrImage::CopyData(const Data& aData)
90 : {
91 0 : RecyclingPlanarYCbCrImage::CopyData(aData);
92 :
93 0 : if (mDelayedConversion) {
94 0 : return false;
95 : }
96 :
97 : // Do some sanity checks to prevent integer overflow
98 0 : if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
99 0 : aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
100 0 : NS_ERROR("Illegal image source width or height");
101 0 : return false;
102 : }
103 :
104 0 : gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
105 :
106 0 : gfx::IntSize size(mScaleHint);
107 0 : gfx::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
108 0 : if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
109 0 : size.height > PlanarYCbCrImage::MAX_DIMENSION) {
110 0 : NS_ERROR("Illegal image dest width or height");
111 0 : return false;
112 : }
113 :
114 0 : mStride = gfx::StrideForFormatAndWidth(format, size.width);
115 : mozilla::CheckedInt32 requiredBytes =
116 0 : mozilla::CheckedInt32(size.height) * mozilla::CheckedInt32(mStride);
117 0 : if (!requiredBytes.isValid()) {
118 : // invalid size
119 0 : return false;
120 : }
121 0 : mDecodedBuffer = AllocateBuffer(requiredBytes.value());
122 0 : if (!mDecodedBuffer) {
123 : // out of memory
124 0 : return false;
125 : }
126 :
127 0 : gfx::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer.get(), mStride);
128 0 : SetOffscreenFormat(gfx::SurfaceFormatToImageFormat(format));
129 0 : mSize = size;
130 :
131 0 : return true;
132 : }
133 :
134 : already_AddRefed<gfx::SourceSurface>
135 0 : BasicPlanarYCbCrImage::GetAsSourceSurface()
136 : {
137 0 : NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
138 :
139 0 : if (mSourceSurface) {
140 0 : RefPtr<gfx::SourceSurface> surface(mSourceSurface);
141 0 : return surface.forget();
142 : }
143 :
144 0 : if (!mDecodedBuffer) {
145 0 : return PlanarYCbCrImage::GetAsSourceSurface();
146 : }
147 :
148 0 : gfxImageFormat format = GetOffscreenFormat();
149 :
150 0 : RefPtr<gfx::SourceSurface> surface;
151 : {
152 : // Create a DrawTarget so that we can own the data inside mDecodeBuffer.
153 : // We create the target out of mDecodedBuffer, and get a snapshot from it.
154 : // The draw target is destroyed on scope exit and the surface owns the data.
155 : RefPtr<gfx::DrawTarget> drawTarget
156 0 : = gfxPlatform::CreateDrawTargetForData(mDecodedBuffer.get(),
157 : mSize,
158 : mStride,
159 0 : gfx::ImageFormatToSurfaceFormat(format));
160 0 : if (!drawTarget) {
161 0 : return nullptr;
162 : }
163 :
164 0 : surface = drawTarget->Snapshot();
165 : }
166 :
167 0 : mRecycleBin->RecycleBuffer(Move(mDecodedBuffer), mSize.height * mStride);
168 :
169 0 : mSourceSurface = surface;
170 0 : return surface.forget();
171 : }
172 :
173 :
174 : ImageFactory*
175 0 : BasicLayerManager::GetImageFactory()
176 : {
177 0 : if (!mFactory) {
178 0 : mFactory = new BasicImageFactory();
179 : }
180 :
181 0 : return mFactory.get();
182 : }
183 :
184 : } // namespace layers
185 : } // namespace mozilla
|