Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: src/codec/SkCodec_libgif.cpp

Issue 1321433002: Add subsetting to SkScaledCodec (Closed) Base URL: https://skia.googlesource.com/skia.git@gif-scan
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 // Use maximum unsigned int (surely an invalid index) to indicate that a val id 94 // Use maximum unsigned int (surely an invalid index) to indicate that a val id
95 // index was not found. 95 // index was not found.
96 return SK_MaxU32; 96 return SK_MaxU32;
97 } 97 }
98 98
99 /* 99 /*
100 * This function cleans up the gif object after the decode completes 100 * This function cleans up the gif object after the decode completes
101 * It is used in a SkAutoTCallIProc template 101 * It is used in a SkAutoTCallIProc template
102 */ 102 */
103 void SkGifCodec::CloseGif(GifFileType* gif) { 103 void SkGifCodec::CloseGif(GifFileType* gif) {
104 DGifCloseFile(gif, NULL); 104 DGifCloseFile(gif, nullptr);
105 } 105 }
106 106
107 /* 107 /*
108 * This function free extension data that has been saved to assist the image 108 * This function free extension data that has been saved to assist the image
109 * decoder 109 * decoder
110 */ 110 */
111 void SkGifCodec::FreeExtension(SavedImage* image) { 111 void SkGifCodec::FreeExtension(SavedImage* image) {
112 if (NULL != image->ExtensionBlocks) { 112 if (nullptr != image->ExtensionBlocks) {
113 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks); 113 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks);
114 } 114 }
115 } 115 }
116 116
117 /* 117 /*
118 * Read enough of the stream to initialize the SkGifCodec. 118 * Read enough of the stream to initialize the SkGifCodec.
119 * Returns a bool representing success or failure. 119 * Returns a bool representing success or failure.
120 * 120 *
121 * @param codecOut 121 * @param codecOut
122 * If it returned true, and codecOut was not nullptr, 122 * If it returned true, and codecOut was not nullptr,
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 , fSrcBuffer(new uint8_t[this->getInfo().width()]) 215 , fSrcBuffer(new uint8_t[this->getInfo().width()])
216 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno w if 216 // If it is valid, fTransIndex will be used to set fFillIndex. We don't kno w if
217 // fTransIndex is valid until we process the color table, since fTransIndex may 217 // fTransIndex is valid until we process the color table, since fTransIndex may
218 // be greater than the size of the color table. 218 // be greater than the size of the color table.
219 , fTransIndex(transIndex) 219 , fTransIndex(transIndex)
220 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid, or if 220 // Default fFillIndex is 0. We will overwrite this if fTransIndex is valid, or if
221 // there is a valid background color. 221 // there is a valid background color.
222 , fFillIndex(0) 222 , fFillIndex(0)
223 , fFrameDims(SkIRect::MakeEmpty()) 223 , fFrameDims(SkIRect::MakeEmpty())
224 , fFrameIsSubset(false) 224 , fFrameIsSubset(false)
225 , fColorTable(NULL) 225 , fColorTable(nullptr)
226 , fSwizzler(NULL) 226 , fSwizzler(nullptr)
227 {} 227 {}
228 228
229 bool SkGifCodec::onRewind() { 229 bool SkGifCodec::onRewind() {
230 GifFileType* gifOut = nullptr; 230 GifFileType* gifOut = nullptr;
231 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { 231 if (!ReadHeader(this->stream(), nullptr, &gifOut)) {
232 return false; 232 return false;
233 } 233 }
234 234
235 SkASSERT(nullptr != gifOut); 235 SkASSERT(nullptr != gifOut);
236 fGif.reset(gifOut); 236 fGif.reset(gifOut);
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 } 370 }
371 371
372 return true; 372 return true;
373 } 373 }
374 374
375 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp utColorPtr, 375 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp utColorPtr,
376 int* inputColorCount) { 376 int* inputColorCount) {
377 // Set up our own color table 377 // Set up our own color table
378 const uint32_t maxColors = 256; 378 const uint32_t maxColors = 256;
379 SkPMColor colorPtr[256]; 379 SkPMColor colorPtr[256];
380 if (NULL != inputColorCount) { 380 if (nullptr != inputColorCount) {
381 // We set the number of colors to maxColors in order to ensure 381 // We set the number of colors to maxColors in order to ensure
382 // safe memory accesses. Otherwise, an invalid pixel could 382 // safe memory accesses. Otherwise, an invalid pixel could
383 // access memory outside of our color table array. 383 // access memory outside of our color table array.
384 *inputColorCount = maxColors; 384 *inputColorCount = maxColors;
385 } 385 }
386 386
387 // Get local color table 387 // Get local color table
388 ColorMapObject* colorMap = fGif->Image.ColorMap; 388 ColorMapObject* colorMap = fGif->Image.ColorMap;
389 // If there is no local color table, use the global color table 389 // If there is no local color table, use the global color table
390 if (NULL == colorMap) { 390 if (nullptr == colorMap) {
391 colorMap = fGif->SColorMap; 391 colorMap = fGif->SColorMap;
392 } 392 }
393 393
394 uint32_t colorCount = 0; 394 uint32_t colorCount = 0;
395 if (NULL != colorMap) { 395 if (nullptr != colorMap) {
396 colorCount = colorMap->ColorCount; 396 colorCount = colorMap->ColorCount;
397 // giflib guarantees these properties 397 // giflib guarantees these properties
398 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); 398 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel)));
399 SkASSERT(colorCount <= 256); 399 SkASSERT(colorCount <= 256);
400 for (uint32_t i = 0; i < colorCount; i++) { 400 for (uint32_t i = 0; i < colorCount; i++) {
401 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, 401 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red,
402 colorMap->Colors[i].Green, colorMap->Colors[i].Blue); 402 colorMap->Colors[i].Green, colorMap->Colors[i].Blue);
403 } 403 }
404 } 404 }
405 405
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 if(!this->setFrameDimensions(desc)) { 450 if(!this->setFrameDimensions(desc)) {
451 return gif_error("Invalid dimensions for image frame.\n", kInvalidInput) ; 451 return gif_error("Invalid dimensions for image frame.\n", kInvalidInput) ;
452 } 452 }
453 453
454 // Initialize color table and copy to the client if necessary 454 // Initialize color table and copy to the client if necessary
455 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount); 455 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount);
456 return kSuccess; 456 return kSuccess;
457 } 457 }
458 458
459 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, 459 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo,
460 ZeroInitialized zeroInit) { 460 ZeroInitialized zeroInit, int subsetLeft, int subsetWidth) {
461 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 461 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
462 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, 462 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dst Info, zeroInit,
463 colorPtr, dstInfo, zeroInit, this->getInfo())); 463 this->getInfo(), subsetLeft, subsetWidth));
scroggo 2015/10/02 18:27:03 If we stick these on options, we can update SkSwiz
464 if (nullptr != fSwizzler.get()) { 464 if (nullptr != fSwizzler.get()) {
465 return kSuccess; 465 return kSuccess;
466 } 466 }
467 return kUnimplemented; 467 return kUnimplemented;
468 } 468 }
469 469
470 bool SkGifCodec::readRow() { 470 bool SkGifCodec::readRow() {
471 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width()); 471 return GIF_ERROR != DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width());
472 } 472 }
473 473
(...skipping 11 matching lines...) Expand all
485 return result; 485 return result;
486 } 486 }
487 487
488 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 488 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
489 return gif_error("Scaling not supported.\n", kInvalidScale); 489 return gif_error("Scaling not supported.\n", kInvalidScale);
490 } 490 }
491 491
492 // Initialize the swizzler 492 // Initialize the swizzler
493 if (fFrameIsSubset) { 493 if (fFrameIsSubset) {
494 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height()); 494 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height());
495 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { 495 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized, 0,
496 fFrameDims.width())) {
496 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; 497 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ;
497 } 498 }
498 499
499 // Fill the background 500 // Fill the background
500 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 501 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
501 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getFillValue(dstInfo.c olorType(), 502 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getFillValue(dstInfo.c olorType(),
502 dstInfo.alphaType()), opts.fZeroInitialized); 503 dstInfo.alphaType()), opts.fZeroInitialized);
503 504
504 // Modify the dst pointer 505 // Modify the dst pointer
505 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype()); 506 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype());
506 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() + 507 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() +
507 dstBytesPerPixel * fFrameDims.left()); 508 dstBytesPerPixel * fFrameDims.left());
508 } else { 509 } else {
509 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { 510 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized, 0,
511 dstInfo.width())) {
510 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; 512 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ;
511 } 513 }
512 } 514 }
513 515
514 // Iterate over rows of the input 516 // Iterate over rows of the input
515 uint32_t width = fFrameDims.width(); 517 uint32_t width = fFrameDims.width();
516 uint32_t height = fFrameDims.height(); 518 uint32_t height = fFrameDims.height();
517 for (uint32_t y = 0; y < height; y++) { 519 for (uint32_t y = 0; y < height; y++) {
518 if (!this->readRow()) { 520 if (!this->readRow()) {
519 *rowsDecoded = y; 521 *rowsDecoded = y;
520 return gif_error("Could not decode line.\n", kIncompleteInput); 522 return gif_error("Could not decode line.\n", kIncompleteInput);
521 } 523 }
522 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin e(y)); 524 void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanlin e(y));
523 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); 525 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
524 } 526 }
525 return kSuccess; 527 return kSuccess;
526 } 528 }
527 529
528 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType ) const { 530 uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType ) const {
529 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 531 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
530 return get_color_table_fill_value(colorType, colorPtr, fFillIndex); 532 return get_color_table_fill_value(colorType, colorPtr, fFillIndex);
531 } 533 }
532 534
533 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, 535 SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
534 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor Count) { 536 const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColor Count,
537 int subsetLeft, int subsetWidth) {
535 538
536 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, this->options()); 539 Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCoun t, this->options());
537 if (kSuccess != result) { 540 if (kSuccess != result) {
538 return result; 541 return result;
539 } 542 }
540 543
541 // Check to see if scaling was requested. 544 // Check to see if scaling was requested.
542 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 545 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
543 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstI nfo)) { 546 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstI nfo)) {
544 return gif_error("Scaling not supported.\n", SkCodec::kInvalidScale) ; 547 return gif_error("Scaling not supported.\n", SkCodec::kInvalidScale) ;
545 } 548 }
546 } 549 }
547 550
548 // Initialize the swizzler 551 // Initialize the swizzler
549 if (fFrameIsSubset) { 552 if (fFrameIsSubset) {
550 int sampleX; 553 int sampleX;
551 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &sampleX, NUL L); 554 SkScaledCodec::ComputeSampleSize(dstInfo.dimensions(), this->getInfo().d imensions(),
555 &sampleX, NULL);
552 const SkImageInfo subsetDstInfo = dstInfo.makeWH( 556 const SkImageInfo subsetDstInfo = dstInfo.makeWH(
553 get_scaled_dimension(fFrameDims.width(), sampleX), 557 get_scaled_dimension(fFrameDims.width(), sampleX),
554 fFrameDims.height()); 558 fFrameDims.height());
555 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) { 559 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized, subsetLeft,
560 subsetWidth)) {
556 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; 561 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ;
557 } 562 }
558 } else { 563 } else {
559 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) { 564 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized, subsetLeft,
565 subsetWidth)) {
560 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ; 566 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ;
561 } 567 }
562 } 568 }
563 569
564 return kSuccess; 570 return kSuccess;
565 } 571 }
566 572
567 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { 573 int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
568 int rowsBeforeFrame = 0; 574 int rowsBeforeFrame = 0;
569 int rowsAfterFrame = 0; 575 int rowsAfterFrame = 0;
570 if (fFrameIsSubset) { 576 if (fFrameIsSubset) {
571 // Fill the requested rows 577 // Fill the requested rows
572 SkSwizzler::Fill(dst, this->dstInfo().makeWH(this->dstInfo().width(), co unt), rowBytes, 578 SkSwizzler::Fill(dst, this->dstInfo().makeWH(this->subsetWidth(), count) , rowBytes,
573 this->onGetFillValue(this->dstInfo().colorType(), this->dstInfo( ).alphaType()), 579 this->onGetFillValue(this->dstInfo().colorType(), this->dstInfo( ).alphaType()),
574 this->options().fZeroInitialized); 580 this->options().fZeroInitialized);
575 581
576 // Do nothing for rows before the image frame 582 // Do nothing for rows before the image frame
577 // FIXME: Do we handle fFrameIsSubset properly for interlaced images? 583 // FIXME: Do we handle fFrameIsSubset properly for interlaced images?
578 rowsBeforeFrame = SkTMax(0, fFrameDims.top() - this->nextScanline()); 584 rowsBeforeFrame = SkTMax(0, fFrameDims.top() - this->nextScanline());
579 count = SkTMax(0, count - rowsBeforeFrame); 585 count = SkTMax(0, count - rowsBeforeFrame);
580 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); 586 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame);
581 587
582 // Do nothing for rows after the image frame 588 // Do nothing for rows after the image frame
(...skipping 14 matching lines...) Expand all
597 } 603 }
598 return count + rowsBeforeFrame + rowsAfterFrame; 604 return count + rowsBeforeFrame + rowsAfterFrame;
599 } 605 }
600 606
601 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const { 607 SkCodec::SkScanlineOrder SkGifCodec::onGetScanlineOrder() const {
602 if (fGif->Image.Interlace) { 608 if (fGif->Image.Interlace) {
603 return kOutOfOrder_SkScanlineOrder; 609 return kOutOfOrder_SkScanlineOrder;
604 } 610 }
605 return kTopDown_SkScanlineOrder; 611 return kTopDown_SkScanlineOrder;
606 } 612 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698