OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
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 "SkCodec_libgif.h" | 8 #include "SkCodec_libgif.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id | 93 // Use maximum unsigned int (surely an invalid index) to indicate that a val
id |
94 // index was not found. | 94 // index was not found. |
95 return SK_MaxU32; | 95 return SK_MaxU32; |
96 } | 96 } |
97 | 97 |
98 /* | 98 /* |
99 * This function cleans up the gif object after the decode completes | 99 * This function cleans up the gif object after the decode completes |
100 * It is used in a SkAutoTCallIProc template | 100 * It is used in a SkAutoTCallIProc template |
101 */ | 101 */ |
102 void SkGifCodec::CloseGif(GifFileType* gif) { | 102 void SkGifCodec::CloseGif(GifFileType* gif) { |
103 DGifCloseFile(gif, NULL); | 103 DGifCloseFile(gif, nullptr); |
104 } | 104 } |
105 | 105 |
106 /* | 106 /* |
107 * This function free extension data that has been saved to assist the image | 107 * This function free extension data that has been saved to assist the image |
108 * decoder | 108 * decoder |
109 */ | 109 */ |
110 void SkGifCodec::FreeExtension(SavedImage* image) { | 110 void SkGifCodec::FreeExtension(SavedImage* image) { |
111 if (NULL != image->ExtensionBlocks) { | 111 if (nullptr != image->ExtensionBlocks) { |
112 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); | 112 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); |
113 } | 113 } |
114 } | 114 } |
115 | 115 |
116 /* | 116 /* |
117 * Read enough of the stream to initialize the SkGifCodec. | 117 * Read enough of the stream to initialize the SkGifCodec. |
118 * Returns a bool representing success or failure. | 118 * Returns a bool representing success or failure. |
119 * | 119 * |
120 * @param codecOut | 120 * @param codecOut |
121 * If it returned true, and codecOut was not nullptr, | 121 * If it returned true, and codecOut was not nullptr, |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 , fSrcBuffer(new uint8_t[this->getInfo().width()]) | 214 , fSrcBuffer(new uint8_t[this->getInfo().width()]) |
215 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno
w if | 215 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno
w if |
216 // fTransIndex is valid until we process the color table, since fTransIndex
may | 216 // fTransIndex is valid until we process the color table, since fTransIndex
may |
217 // be greater than the size of the color table. | 217 // be greater than the size of the color table. |
218 , fTransIndex(transIndex) | 218 , fTransIndex(transIndex) |
219 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid,
or if | 219 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid,
or if |
220 // there is a valid background color. | 220 // there is a valid background color. |
221 , fFillIndex(0) | 221 , fFillIndex(0) |
222 , fFrameRect(frameRect) | 222 , fFrameRect(frameRect) |
223 , fFrameIsSubset(frameIsSubset) | 223 , fFrameIsSubset(frameIsSubset) |
224 , fColorTable(NULL) | 224 , fColorTable(nullptr) |
225 , fSwizzler(NULL) | 225 , fSwizzler(nullptr) |
226 {} | 226 {} |
227 | 227 |
228 bool SkGifCodec::onRewind() { | 228 bool SkGifCodec::onRewind() { |
229 GifFileType* gifOut = nullptr; | 229 GifFileType* gifOut = nullptr; |
230 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { | 230 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { |
231 return false; | 231 return false; |
232 } | 232 } |
233 | 233 |
234 SkASSERT(nullptr != gifOut); | 234 SkASSERT(nullptr != gifOut); |
235 fGif.reset(gifOut); | 235 fGif.reset(gifOut); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); | 348 frameRect->setXYWH(frameLeft, frameTop, frameWidth, frameHeight); |
349 size->set(width, height); | 349 size->set(width, height); |
350 return true; | 350 return true; |
351 } | 351 } |
352 | 352 |
353 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp
utColorPtr, | 353 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp
utColorPtr, |
354 int* inputColorCount) { | 354 int* inputColorCount) { |
355 // Set up our own color table | 355 // Set up our own color table |
356 const uint32_t maxColors = 256; | 356 const uint32_t maxColors = 256; |
357 SkPMColor colorPtr[256]; | 357 SkPMColor colorPtr[256]; |
358 if (NULL != inputColorCount) { | 358 if (nullptr != inputColorCount) { |
359 // We set the number of colors to maxColors in order to ensure | 359 // We set the number of colors to maxColors in order to ensure |
360 // safe memory accesses. Otherwise, an invalid pixel could | 360 // safe memory accesses. Otherwise, an invalid pixel could |
361 // access memory outside of our color table array. | 361 // access memory outside of our color table array. |
362 *inputColorCount = maxColors; | 362 *inputColorCount = maxColors; |
363 } | 363 } |
364 | 364 |
365 // Get local color table | 365 // Get local color table |
366 ColorMapObject* colorMap = fGif->Image.ColorMap; | 366 ColorMapObject* colorMap = fGif->Image.ColorMap; |
367 // If there is no local color table, use the global color table | 367 // If there is no local color table, use the global color table |
368 if (NULL == colorMap) { | 368 if (nullptr == colorMap) { |
369 colorMap = fGif->SColorMap; | 369 colorMap = fGif->SColorMap; |
370 } | 370 } |
371 | 371 |
372 uint32_t colorCount = 0; | 372 uint32_t colorCount = 0; |
373 if (NULL != colorMap) { | 373 if (nullptr != colorMap) { |
374 colorCount = colorMap->ColorCount; | 374 colorCount = colorMap->ColorCount; |
375 // giflib guarantees these properties | 375 // giflib guarantees these properties |
376 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); | 376 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); |
377 SkASSERT(colorCount <= 256); | 377 SkASSERT(colorCount <= 256); |
378 for (uint32_t i = 0; i < colorCount; i++) { | 378 for (uint32_t i = 0; i < colorCount; i++) { |
379 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, | 379 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, |
380 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); | 380 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); |
381 } | 381 } |
382 } | 382 } |
383 | 383 |
(...skipping 19 matching lines...) Expand all Loading... |
403 colorPtr[i] = colorPtr[fFillIndex]; | 403 colorPtr[i] = colorPtr[fFillIndex]; |
404 } | 404 } |
405 | 405 |
406 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); | 406 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); |
407 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount)
; | 407 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount)
; |
408 } | 408 } |
409 | 409 |
410 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo
r* inputColorPtr, | 410 SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo
r* inputColorPtr, |
411 int* inputColorCount, const Options& opts) { | 411 int* inputColorCount, const Options& opts) { |
412 // Check for valid input parameters | 412 // Check for valid input parameters |
413 if (opts.fSubset) { | |
414 // Subsets are not supported. | |
415 return kUnimplemented; | |
416 } | |
417 if (!conversion_possible(dstInfo, this->getInfo())) { | 413 if (!conversion_possible(dstInfo, this->getInfo())) { |
418 return gif_error("Cannot convert input type to output type.\n", | 414 return gif_error("Cannot convert input type to output type.\n", |
419 kInvalidConversion); | 415 kInvalidConversion); |
420 } | 416 } |
421 | 417 |
422 // Initialize color table and copy to the client if necessary | 418 // Initialize color table and copy to the client if necessary |
423 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); | 419 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); |
424 return kSuccess; | 420 return kSuccess; |
425 } | 421 } |
426 | 422 |
427 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, | 423 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const
Options& opts) { |
428 ZeroInitialized zeroInit) { | |
429 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 424 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
430 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, | 425 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dst
Info, opts)); |
431 colorPtr, dstInfo, zeroInit)); | |
432 if (nullptr != fSwizzler.get()) { | 426 if (nullptr != fSwizzler.get()) { |
433 return kSuccess; | 427 return kSuccess; |
434 } | 428 } |
435 return kUnimplemented; | 429 return kUnimplemented; |
436 } | 430 } |
437 | 431 |
438 bool SkGifCodec::readRow() { | 432 bool SkGifCodec::readRow() { |
439 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); | 433 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameRect.width()); |
440 } | 434 } |
441 | 435 |
(...skipping 11 matching lines...) Expand all Loading... |
453 return result; | 447 return result; |
454 } | 448 } |
455 | 449 |
456 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 450 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
457 return gif_error("Scaling not supported.\n", kInvalidScale); | 451 return gif_error("Scaling not supported.\n", kInvalidScale); |
458 } | 452 } |
459 | 453 |
460 // Initialize the swizzler | 454 // Initialize the swizzler |
461 if (fFrameIsSubset) { | 455 if (fFrameIsSubset) { |
462 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 456 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
463 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 457 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { |
464 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 458 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
465 } | 459 } |
466 | 460 |
467 // Fill the background | 461 // Fill the background |
468 SkSampler::Fill(dst, dstInfo, dstRowBytes, | 462 SkSampler::Fill(dst, dstInfo, dstRowBytes, |
469 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), | 463 this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), |
470 opts.fZeroInitialized); | 464 opts.fZeroInitialized); |
471 | 465 |
472 // Modify the dst pointer | 466 // Modify the dst pointer |
473 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); | 467 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT
ype()); |
474 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + | 468 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + |
475 dstBytesPerPixel * fFrameRect.left()); | 469 dstBytesPerPixel * fFrameRect.left()); |
476 } else { | 470 } else { |
477 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 471 if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { |
478 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 472 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
479 } | 473 } |
480 } | 474 } |
481 | 475 |
482 // Iterate over rows of the input | 476 // Iterate over rows of the input |
483 uint32_t width = fFrameRect.width(); | 477 uint32_t width = fFrameRect.width(); |
484 uint32_t height = fFrameRect.height(); | 478 uint32_t height = fFrameRect.height(); |
485 for (uint32_t y = 0; y < height; y++) { | 479 for (uint32_t y = 0; y < height; y++) { |
486 if (!this->readRow()) { | 480 if (!this->readRow()) { |
487 *rowsDecoded = y; | 481 *rowsDecoded = y; |
(...skipping 14 matching lines...) Expand all Loading... |
502 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { | 496 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor
Count) { |
503 | 497 |
504 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); | 498 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun
t, this->options()); |
505 if (kSuccess != result) { | 499 if (kSuccess != result) { |
506 return result; | 500 return result; |
507 } | 501 } |
508 | 502 |
509 // Initialize the swizzler | 503 // Initialize the swizzler |
510 if (fFrameIsSubset) { | 504 if (fFrameIsSubset) { |
511 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); | 505 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFr
ameRect.height()); |
512 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia
lized)) { | 506 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { |
513 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 507 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
514 } | 508 } |
515 } else { | 509 } else { |
516 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)
) { | 510 if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { |
517 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; | 511 return gif_error("Could not initialize swizzler.\n", kUnimplemented)
; |
518 } | 512 } |
519 } | 513 } |
520 | 514 |
521 return kSuccess; | 515 return kSuccess; |
522 } | 516 } |
523 | 517 |
524 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { | 518 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { |
525 int rowsBeforeFrame = 0; | 519 int rowsBeforeFrame = 0; |
526 int rowsAfterFrame = 0; | 520 int rowsAfterFrame = 0; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 | 560 |
567 int SkGifCodec::onOutputScanline(int inputScanline) const { | 561 int SkGifCodec::onOutputScanline(int inputScanline) const { |
568 if (fGif->Image.Interlace) { | 562 if (fGif->Image.Interlace) { |
569 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { | 563 if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bott
om()) { |
570 return inputScanline; | 564 return inputScanline; |
571 } | 565 } |
572 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); | 566 return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFram
eRect.height()); |
573 } | 567 } |
574 return inputScanline; | 568 return inputScanline; |
575 } | 569 } |
OLD | NEW |