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