OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkColor.h" | 8 #include "SkColor.h" |
9 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
10 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
11 #include "SkImageDecoder.h" | 11 #include "SkImageDecoder.h" |
12 #include "SkRTConf.h" | 12 #include "SkRTConf.h" |
13 #include "SkScaledBitmapSampler.h" | 13 #include "SkScaledBitmapSampler.h" |
14 #include "SkStream.h" | 14 #include "SkStream.h" |
15 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
16 #include "SkUtils.h" | 16 #include "SkUtils.h" |
17 | 17 |
18 #include "gif_lib.h" | 18 #include "gif_lib.h" |
19 | 19 |
20 class SkGIFImageDecoder : public SkImageDecoder { | 20 class SkGIFImageDecoder : public SkImageDecoder { |
21 public: | 21 public: |
22 virtual Format getFormat() const SK_OVERRIDE { | 22 virtual Format getFormat() const SK_OVERRIDE { |
23 return kGIF_Format; | 23 return kGIF_Format; |
24 } | 24 } |
25 | 25 |
26 protected: | 26 protected: |
27 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE
; | 27 virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRI
DE; |
28 | 28 |
29 private: | 29 private: |
30 typedef SkImageDecoder INHERITED; | 30 typedef SkImageDecoder INHERITED; |
31 }; | 31 }; |
32 | 32 |
33 static const uint8_t gStartingIterlaceYValue[] = { | 33 static const uint8_t gStartingIterlaceYValue[] = { |
34 0, 4, 2, 1 | 34 0, 4, 2, 1 |
35 }; | 35 }; |
36 static const uint8_t gDeltaIterlaceYValue[] = { | 36 static const uint8_t gDeltaIterlaceYValue[] = { |
37 8, 8, 4, 2 | 37 8, 8, 4, 2 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 if (transpIndex >= colorCount) { | 145 if (transpIndex >= colorCount) { |
146 transpIndex = -1; | 146 transpIndex = -1; |
147 } | 147 } |
148 break; | 148 break; |
149 } | 149 } |
150 } | 150 } |
151 } | 151 } |
152 return transpIndex; | 152 return transpIndex; |
153 } | 153 } |
154 | 154 |
155 static bool error_return(const SkBitmap& bm, const char msg[]) { | 155 static SkImageDecoder::Result error_return(const SkBitmap& bm, const char msg[])
{ |
156 if (!c_suppressGIFImageDecoderWarnings) { | 156 if (!c_suppressGIFImageDecoderWarnings) { |
157 SkDebugf("libgif error [%s] bitmap [%d %d] pixels %p colortable %p\n", | 157 SkDebugf("libgif error [%s] bitmap [%d %d] pixels %p colortable %p\n", |
158 msg, bm.width(), bm.height(), bm.getPixels(), | 158 msg, bm.width(), bm.height(), bm.getPixels(), |
159 bm.getColorTable()); | 159 bm.getColorTable()); |
160 } | 160 } |
161 return false; | 161 return SkImageDecoder::kFailure; |
162 } | 162 } |
| 163 |
163 static void gif_warning(const SkBitmap& bm, const char msg[]) { | 164 static void gif_warning(const SkBitmap& bm, const char msg[]) { |
164 if (!c_suppressGIFImageDecoderWarnings) { | 165 if (!c_suppressGIFImageDecoderWarnings) { |
165 SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n", | 166 SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n", |
166 msg, bm.width(), bm.height(), bm.getPixels(), | 167 msg, bm.width(), bm.height(), bm.getPixels(), |
167 bm.getColorTable()); | 168 bm.getColorTable()); |
168 } | 169 } |
169 } | 170 } |
170 | 171 |
171 /** | 172 /** |
172 * Skip rows in the source gif image. | 173 * Skip rows in the source gif image. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 addr += rowBytes; | 222 addr += rowBytes; |
222 } | 223 } |
223 if (warning) { | 224 if (warning) { |
224 gif_warning(*bm, "Index out of bounds."); | 225 gif_warning(*bm, "Index out of bounds."); |
225 } | 226 } |
226 } | 227 } |
227 } | 228 } |
228 } | 229 } |
229 } | 230 } |
230 | 231 |
231 bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) { | 232 SkImageDecoder::Result SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap
* bm, Mode mode) { |
232 #if GIFLIB_MAJOR < 5 | 233 #if GIFLIB_MAJOR < 5 |
233 GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc); | 234 GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc); |
234 #else | 235 #else |
235 GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc, NULL); | 236 GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc, NULL); |
236 #endif | 237 #endif |
237 if (NULL == gif) { | 238 if (NULL == gif) { |
238 return error_return(*bm, "DGifOpen"); | 239 return error_return(*bm, "DGifOpen"); |
239 } | 240 } |
240 | 241 |
241 SkAutoTCallIProc<GifFileType, DGifCloseFile> acp(gif); | 242 SkAutoTCallIProc<GifFileType, DGifCloseFile> acp(gif); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 return error_return(*bm, "chooseFromOneChoice"); | 316 return error_return(*bm, "chooseFromOneChoice"); |
316 } | 317 } |
317 #endif | 318 #endif |
318 | 319 |
319 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); | 320 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); |
320 | 321 |
321 bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledH
eight(), | 322 bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledH
eight(), |
322 kIndex_8_SkColorType, kPremul_SkAlphaT
ype)); | 323 kIndex_8_SkColorType, kPremul_SkAlphaT
ype)); |
323 | 324 |
324 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | 325 if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
325 return true; | 326 return kSuccess; |
326 } | 327 } |
327 | 328 |
328 | 329 |
329 // now we decode the colortable | 330 // now we decode the colortable |
330 int colorCount = 0; | 331 int colorCount = 0; |
331 { | 332 { |
332 // Declare colorPtr here for scope. | 333 // Declare colorPtr here for scope. |
333 SkPMColor colorPtr[256]; // storage for worst-case | 334 SkPMColor colorPtr[256]; // storage for worst-case |
334 const ColorMapObject* cmap = find_colormap(gif); | 335 const ColorMapObject* cmap = find_colormap(gif); |
335 if (cmap != NULL) { | 336 if (cmap != NULL) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 // take care of skipping unneeded rows. | 417 // take care of skipping unneeded rows. |
417 GifInterlaceIter iter(innerHeight); | 418 GifInterlaceIter iter(innerHeight); |
418 for (int y = 0; y < innerHeight; y++) { | 419 for (int y = 0; y < innerHeight; y++) { |
419 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { | 420 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { |
420 gif_warning(*bm, "interlace DGifGetLine"); | 421 gif_warning(*bm, "interlace DGifGetLine"); |
421 memset(scanline, fillIndex, innerWidth); | 422 memset(scanline, fillIndex, innerWidth); |
422 for (; y < innerHeight; y++) { | 423 for (; y < innerHeight; y++) { |
423 sampler.sampleInterlaced(scanline, iter.currY()); | 424 sampler.sampleInterlaced(scanline, iter.currY()); |
424 iter.next(); | 425 iter.next(); |
425 } | 426 } |
426 return true; | 427 return kPartialSuccess; |
427 } | 428 } |
428 sampler.sampleInterlaced(scanline, iter.currY()); | 429 sampler.sampleInterlaced(scanline, iter.currY()); |
429 iter.next(); | 430 iter.next(); |
430 } | 431 } |
431 } else { | 432 } else { |
432 // easy, non-interlace case | 433 // easy, non-interlace case |
433 const int outHeight = workingBitmap->height(); | 434 const int outHeight = workingBitmap->height(); |
434 skip_src_rows(gif, scanline, innerWidth, sampler.srcY0()); | 435 skip_src_rows(gif, scanline, innerWidth, sampler.srcY0()); |
435 for (int y = 0; y < outHeight; y++) { | 436 for (int y = 0; y < outHeight; y++) { |
436 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { | 437 if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) { |
437 gif_warning(*bm, "DGifGetLine"); | 438 gif_warning(*bm, "DGifGetLine"); |
438 memset(scanline, fillIndex, innerWidth); | 439 memset(scanline, fillIndex, innerWidth); |
439 for (; y < outHeight; y++) { | 440 for (; y < outHeight; y++) { |
440 sampler.next(scanline); | 441 sampler.next(scanline); |
441 } | 442 } |
442 return true; | 443 return kPartialSuccess; |
443 } | 444 } |
444 // scanline now contains the raw data. Sample it. | 445 // scanline now contains the raw data. Sample it. |
445 sampler.next(scanline); | 446 sampler.next(scanline); |
446 if (y < outHeight - 1) { | 447 if (y < outHeight - 1) { |
447 skip_src_rows(gif, scanline, innerWidth, sampler.srcDY()
- 1); | 448 skip_src_rows(gif, scanline, innerWidth, sampler.srcDY()
- 1); |
448 } | 449 } |
449 } | 450 } |
450 // skip the rest of the rows (if any) | 451 // skip the rest of the rows (if any) |
451 int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() +
1; | 452 int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() +
1; |
452 SkASSERT(read <= innerHeight); | 453 SkASSERT(read <= innerHeight); |
453 skip_src_rows(gif, scanline, innerWidth, innerHeight - read); | 454 skip_src_rows(gif, scanline, innerWidth, innerHeight - read); |
454 } | 455 } |
455 sanitize_indexed_bitmap(bm); | 456 sanitize_indexed_bitmap(bm); |
456 return true; | 457 return kSuccess; |
457 } break; | 458 } break; |
458 | 459 |
459 case EXTENSION_RECORD_TYPE: | 460 case EXTENSION_RECORD_TYPE: |
460 #if GIFLIB_MAJOR < 5 | 461 #if GIFLIB_MAJOR < 5 |
461 if (DGifGetExtension(gif, &temp_save.Function, | 462 if (DGifGetExtension(gif, &temp_save.Function, |
462 &extData) == GIF_ERROR) { | 463 &extData) == GIF_ERROR) { |
463 #else | 464 #else |
464 if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) { | 465 if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) { |
465 #endif | 466 #endif |
466 return error_return(*bm, "DGifGetExtension"); | 467 return error_return(*bm, "DGifGetExtension"); |
(...skipping 24 matching lines...) Expand all Loading... |
491 | 492 |
492 case TERMINATE_RECORD_TYPE: | 493 case TERMINATE_RECORD_TYPE: |
493 break; | 494 break; |
494 | 495 |
495 default: /* Should be trapped by DGifGetRecordType */ | 496 default: /* Should be trapped by DGifGetRecordType */ |
496 break; | 497 break; |
497 } | 498 } |
498 } while (recType != TERMINATE_RECORD_TYPE); | 499 } while (recType != TERMINATE_RECORD_TYPE); |
499 | 500 |
500 sanitize_indexed_bitmap(bm); | 501 sanitize_indexed_bitmap(bm); |
501 return true; | 502 return kSuccess; |
502 } | 503 } |
503 | 504 |
504 /////////////////////////////////////////////////////////////////////////////// | 505 /////////////////////////////////////////////////////////////////////////////// |
505 DEFINE_DECODER_CREATOR(GIFImageDecoder); | 506 DEFINE_DECODER_CREATOR(GIFImageDecoder); |
506 /////////////////////////////////////////////////////////////////////////////// | 507 /////////////////////////////////////////////////////////////////////////////// |
507 | 508 |
508 static bool is_gif(SkStreamRewindable* stream) { | 509 static bool is_gif(SkStreamRewindable* stream) { |
509 char buf[GIF_STAMP_LEN]; | 510 char buf[GIF_STAMP_LEN]; |
510 if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { | 511 if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { |
511 if (memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0 || | 512 if (memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0 || |
(...skipping 15 matching lines...) Expand all Loading... |
527 static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory); | 528 static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory); |
528 | 529 |
529 static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) { | 530 static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) { |
530 if (is_gif(stream)) { | 531 if (is_gif(stream)) { |
531 return SkImageDecoder::kGIF_Format; | 532 return SkImageDecoder::kGIF_Format; |
532 } | 533 } |
533 return SkImageDecoder::kUnknown_Format; | 534 return SkImageDecoder::kUnknown_Format; |
534 } | 535 } |
535 | 536 |
536 static SkImageDecoder_FormatReg gFormatReg(get_format_gif); | 537 static SkImageDecoder_FormatReg gFormatReg(get_format_gif); |
OLD | NEW |