Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; 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 "DecoderFactory.h"
7 :
8 : #include "nsMimeTypes.h"
9 : #include "mozilla/RefPtr.h"
10 :
11 : #include "AnimationSurfaceProvider.h"
12 : #include "Decoder.h"
13 : #include "IDecodingTask.h"
14 : #include "nsPNGDecoder.h"
15 : #include "nsGIFDecoder2.h"
16 : #include "nsJPEGDecoder.h"
17 : #include "nsBMPDecoder.h"
18 : #include "nsICODecoder.h"
19 : #include "nsIconDecoder.h"
20 :
21 : namespace mozilla {
22 :
23 : using namespace gfx;
24 :
25 : namespace image {
26 :
27 : /* static */ DecoderType
28 24 : DecoderFactory::GetDecoderType(const char* aMimeType)
29 : {
30 : // By default we don't know.
31 24 : DecoderType type = DecoderType::UNKNOWN;
32 :
33 : // PNG
34 24 : if (!strcmp(aMimeType, IMAGE_PNG)) {
35 18 : type = DecoderType::PNG;
36 6 : } else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
37 0 : type = DecoderType::PNG;
38 6 : } else if (!strcmp(aMimeType, IMAGE_APNG)) {
39 0 : type = DecoderType::PNG;
40 :
41 : // GIF
42 6 : } else if (!strcmp(aMimeType, IMAGE_GIF)) {
43 1 : type = DecoderType::GIF;
44 :
45 : // JPEG
46 5 : } else if (!strcmp(aMimeType, IMAGE_JPEG)) {
47 0 : type = DecoderType::JPEG;
48 5 : } else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
49 0 : type = DecoderType::JPEG;
50 5 : } else if (!strcmp(aMimeType, IMAGE_JPG)) {
51 0 : type = DecoderType::JPEG;
52 :
53 : // BMP
54 5 : } else if (!strcmp(aMimeType, IMAGE_BMP)) {
55 0 : type = DecoderType::BMP;
56 5 : } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
57 0 : type = DecoderType::BMP;
58 :
59 : // ICO
60 5 : } else if (!strcmp(aMimeType, IMAGE_ICO)) {
61 0 : type = DecoderType::ICO;
62 5 : } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
63 0 : type = DecoderType::ICO;
64 :
65 : // Icon
66 5 : } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
67 0 : type = DecoderType::ICON;
68 : }
69 :
70 24 : return type;
71 : }
72 :
73 : /* static */ already_AddRefed<Decoder>
74 33 : DecoderFactory::GetDecoder(DecoderType aType,
75 : RasterImage* aImage,
76 : bool aIsRedecode)
77 : {
78 66 : RefPtr<Decoder> decoder;
79 :
80 33 : switch (aType) {
81 : case DecoderType::PNG:
82 31 : decoder = new nsPNGDecoder(aImage);
83 31 : break;
84 : case DecoderType::GIF:
85 2 : decoder = new nsGIFDecoder2(aImage);
86 2 : break;
87 : case DecoderType::JPEG:
88 : // If we have all the data we don't want to waste cpu time doing
89 : // a progressive decode.
90 : decoder = new nsJPEGDecoder(aImage,
91 : aIsRedecode ? Decoder::SEQUENTIAL
92 0 : : Decoder::PROGRESSIVE);
93 0 : break;
94 : case DecoderType::BMP:
95 0 : decoder = new nsBMPDecoder(aImage);
96 0 : break;
97 : case DecoderType::ICO:
98 0 : decoder = new nsICODecoder(aImage);
99 0 : break;
100 : case DecoderType::ICON:
101 0 : decoder = new nsIconDecoder(aImage);
102 0 : break;
103 : default:
104 0 : MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
105 : }
106 :
107 66 : return decoder.forget();
108 : }
109 :
110 : /* static */ already_AddRefed<IDecodingTask>
111 12 : DecoderFactory::CreateDecoder(DecoderType aType,
112 : NotNull<RasterImage*> aImage,
113 : NotNull<SourceBuffer*> aSourceBuffer,
114 : const IntSize& aIntrinsicSize,
115 : const IntSize& aOutputSize,
116 : DecoderFlags aDecoderFlags,
117 : SurfaceFlags aSurfaceFlags)
118 : {
119 12 : if (aType == DecoderType::UNKNOWN) {
120 0 : return nullptr;
121 : }
122 :
123 : // Create an anonymous decoder. Interaction with the SurfaceCache and the
124 : // owning RasterImage will be mediated by DecodedSurfaceProvider.
125 : RefPtr<Decoder> decoder =
126 24 : GetDecoder(aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
127 12 : MOZ_ASSERT(decoder, "Should have a decoder now");
128 :
129 : // Initialize the decoder.
130 12 : decoder->SetMetadataDecode(false);
131 12 : decoder->SetIterator(aSourceBuffer->Iterator());
132 12 : decoder->SetOutputSize(aOutputSize);
133 12 : decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
134 12 : decoder->SetSurfaceFlags(aSurfaceFlags);
135 :
136 12 : if (NS_FAILED(decoder->Init())) {
137 0 : return nullptr;
138 : }
139 :
140 : // Create a DecodedSurfaceProvider which will manage the decoding process and
141 : // make this decoder's output available in the surface cache.
142 : SurfaceKey surfaceKey =
143 24 : RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic);
144 : NotNull<RefPtr<DecodedSurfaceProvider>> provider =
145 24 : WrapNotNull(new DecodedSurfaceProvider(aImage,
146 : surfaceKey,
147 60 : WrapNotNull(decoder)));
148 :
149 : // Attempt to insert the surface provider into the surface cache right away so
150 : // we won't trigger any more decoders with the same parameters.
151 12 : if (SurfaceCache::Insert(provider) != InsertOutcome::SUCCESS) {
152 0 : return nullptr;
153 : }
154 :
155 : // Return the surface provider in its IDecodingTask guise.
156 24 : RefPtr<IDecodingTask> task = provider.get();
157 12 : return task.forget();
158 : }
159 :
160 : /* static */ already_AddRefed<IDecodingTask>
161 2 : DecoderFactory::CreateAnimationDecoder(DecoderType aType,
162 : NotNull<RasterImage*> aImage,
163 : NotNull<SourceBuffer*> aSourceBuffer,
164 : const IntSize& aIntrinsicSize,
165 : DecoderFlags aDecoderFlags,
166 : SurfaceFlags aSurfaceFlags)
167 : {
168 2 : if (aType == DecoderType::UNKNOWN) {
169 0 : return nullptr;
170 : }
171 :
172 2 : MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG,
173 : "Calling CreateAnimationDecoder for non-animating DecoderType");
174 :
175 : // Create an anonymous decoder. Interaction with the SurfaceCache and the
176 : // owning RasterImage will be mediated by AnimationSurfaceProvider.
177 4 : RefPtr<Decoder> decoder = GetDecoder(aType, nullptr, /* aIsRedecode = */ true);
178 2 : MOZ_ASSERT(decoder, "Should have a decoder now");
179 :
180 : // Initialize the decoder.
181 2 : decoder->SetMetadataDecode(false);
182 2 : decoder->SetIterator(aSourceBuffer->Iterator());
183 2 : decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
184 2 : decoder->SetSurfaceFlags(aSurfaceFlags);
185 :
186 2 : if (NS_FAILED(decoder->Init())) {
187 0 : return nullptr;
188 : }
189 :
190 : // Create an AnimationSurfaceProvider which will manage the decoding process
191 : // and make this decoder's output available in the surface cache.
192 : SurfaceKey surfaceKey =
193 4 : RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated);
194 : NotNull<RefPtr<AnimationSurfaceProvider>> provider =
195 4 : WrapNotNull(new AnimationSurfaceProvider(aImage,
196 : surfaceKey,
197 10 : WrapNotNull(decoder)));
198 :
199 : // Attempt to insert the surface provider into the surface cache right away so
200 : // we won't trigger any more decoders with the same parameters.
201 2 : if (SurfaceCache::Insert(provider) != InsertOutcome::SUCCESS) {
202 0 : return nullptr;
203 : }
204 :
205 : // Return the surface provider in its IDecodingTask guise.
206 4 : RefPtr<IDecodingTask> task = provider.get();
207 2 : return task.forget();
208 : }
209 :
210 : /* static */ already_AddRefed<IDecodingTask>
211 19 : DecoderFactory::CreateMetadataDecoder(DecoderType aType,
212 : NotNull<RasterImage*> aImage,
213 : NotNull<SourceBuffer*> aSourceBuffer)
214 : {
215 19 : if (aType == DecoderType::UNKNOWN) {
216 0 : return nullptr;
217 : }
218 :
219 : RefPtr<Decoder> decoder =
220 38 : GetDecoder(aType, aImage, /* aIsRedecode = */ false);
221 19 : MOZ_ASSERT(decoder, "Should have a decoder now");
222 :
223 : // Initialize the decoder.
224 19 : decoder->SetMetadataDecode(true);
225 19 : decoder->SetIterator(aSourceBuffer->Iterator());
226 :
227 19 : if (NS_FAILED(decoder->Init())) {
228 0 : return nullptr;
229 : }
230 :
231 57 : RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
232 19 : return task.forget();
233 : }
234 :
235 : /* static */ already_AddRefed<Decoder>
236 0 : DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
237 : NotNull<SourceBuffer*> aSourceBuffer,
238 : NotNull<nsICODecoder*> aICODecoder,
239 : const Maybe<uint32_t>& aDataOffset
240 : /* = Nothing() */)
241 : {
242 : // Create the decoder.
243 0 : RefPtr<Decoder> decoder;
244 0 : switch (aType) {
245 : case DecoderType::BMP:
246 0 : MOZ_ASSERT(aDataOffset);
247 0 : decoder = new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
248 0 : break;
249 :
250 : case DecoderType::PNG:
251 0 : MOZ_ASSERT(!aDataOffset);
252 0 : decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
253 0 : break;
254 :
255 : default:
256 0 : MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
257 : return nullptr;
258 : }
259 :
260 0 : MOZ_ASSERT(decoder);
261 :
262 : // Initialize the decoder, copying settings from @aICODecoder.
263 0 : MOZ_ASSERT(!aICODecoder->IsMetadataDecode());
264 0 : decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode());
265 0 : decoder->SetIterator(aSourceBuffer->Iterator());
266 0 : decoder->SetOutputSize(aICODecoder->OutputSize());
267 0 : decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
268 0 : decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
269 0 : decoder->SetFinalizeFrames(false);
270 :
271 0 : if (NS_FAILED(decoder->Init())) {
272 0 : return nullptr;
273 : }
274 :
275 0 : return decoder.forget();
276 : }
277 :
278 : /* static */ already_AddRefed<Decoder>
279 0 : DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
280 : NotNull<SourceBuffer*> aSourceBuffer,
281 : const Maybe<IntSize>& aOutputSize,
282 : SurfaceFlags aSurfaceFlags)
283 : {
284 0 : if (aType == DecoderType::UNKNOWN) {
285 0 : return nullptr;
286 : }
287 :
288 : RefPtr<Decoder> decoder =
289 0 : GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
290 0 : MOZ_ASSERT(decoder, "Should have a decoder now");
291 :
292 : // Initialize the decoder.
293 0 : decoder->SetMetadataDecode(false);
294 0 : decoder->SetIterator(aSourceBuffer->Iterator());
295 :
296 : // Anonymous decoders are always transient; we don't want to optimize surfaces
297 : // or do any other expensive work that might be wasted.
298 0 : DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
299 :
300 : // Without an image, the decoder can't store anything in the SurfaceCache, so
301 : // callers will only be able to retrieve the most recent frame via
302 : // Decoder::GetCurrentFrame(). That means that anonymous decoders should
303 : // always be first-frame-only decoders, because nobody ever wants the *last*
304 : // frame.
305 0 : decoderFlags |= DecoderFlags::FIRST_FRAME_ONLY;
306 :
307 0 : decoder->SetDecoderFlags(decoderFlags);
308 0 : decoder->SetSurfaceFlags(aSurfaceFlags);
309 :
310 : // Set an output size for downscale-during-decode if requested.
311 0 : if (aOutputSize) {
312 0 : decoder->SetOutputSize(*aOutputSize);
313 : }
314 :
315 0 : if (NS_FAILED(decoder->Init())) {
316 0 : return nullptr;
317 : }
318 :
319 0 : return decoder.forget();
320 : }
321 :
322 : /* static */ already_AddRefed<Decoder>
323 0 : DecoderFactory::CreateAnonymousMetadataDecoder(DecoderType aType,
324 : NotNull<SourceBuffer*> aSourceBuffer)
325 : {
326 0 : if (aType == DecoderType::UNKNOWN) {
327 0 : return nullptr;
328 : }
329 :
330 : RefPtr<Decoder> decoder =
331 0 : GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
332 0 : MOZ_ASSERT(decoder, "Should have a decoder now");
333 :
334 : // Initialize the decoder.
335 0 : decoder->SetMetadataDecode(true);
336 0 : decoder->SetIterator(aSourceBuffer->Iterator());
337 0 : decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
338 :
339 0 : if (NS_FAILED(decoder->Init())) {
340 0 : return nullptr;
341 : }
342 :
343 0 : return decoder.forget();
344 : }
345 :
346 : } // namespace image
347 : } // namespace mozilla
|