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

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

Issue 1055743003: Swizzler changes Index8 and 565 (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Avoid setting a field to a local variable Created 5 years, 8 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_libpng.h" 8 #include "SkCodec_libpng.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
11 #include "SkColorTable.h" 11 #include "SkColorTable.h"
12 #include "SkBitmap.h" 12 #include "SkBitmap.h"
13 #include "SkMath.h" 13 #include "SkMath.h"
14 #include "SkScanlineDecoder.h" 14 #include "SkScanlineDecoder.h"
15 #include "SkSize.h" 15 #include "SkSize.h"
16 #include "SkStream.h" 16 #include "SkStream.h"
17 #include "SkSwizzler.h" 17 #include "SkSwizzler.h"
18 #include "SkUtils.h"
18 19
19 /////////////////////////////////////////////////////////////////////////////// 20 ///////////////////////////////////////////////////////////////////////////////
20 // Helper macros 21 // Helper macros
21 /////////////////////////////////////////////////////////////////////////////// 22 ///////////////////////////////////////////////////////////////////////////////
22 23
23 #ifndef png_jmpbuf 24 #ifndef png_jmpbuf
24 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 25 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
25 #endif 26 #endif
26 27
27 /* These were dropped in libpng >= 1.4 */ 28 /* These were dropped in libpng >= 1.4 */
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 113 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
113 return num_trans > 0; 114 return num_trans > 0;
114 } 115 }
115 116
116 // Method for coverting to either an SkPMColor or a similarly packed 117 // Method for coverting to either an SkPMColor or a similarly packed
117 // unpremultiplied color. 118 // unpremultiplied color.
118 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); 119 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
119 120
120 // Note: SkColorTable claims to store SkPMColors, which is not necessarily 121 // Note: SkColorTable claims to store SkPMColors, which is not necessarily
121 // the case here. 122 // the case here.
122 bool SkPngCodec::decodePalette(bool premultiply) { 123 bool SkPngCodec::decodePalette(bool premultiply, int bitDepth, int* ctableCount) {
123 int numPalette; 124 int numPalette;
124 png_colorp palette; 125 png_colorp palette;
125 png_bytep trans; 126 png_bytep trans;
126 127
127 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { 128 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) {
128 return false; 129 return false;
129 } 130 }
130 131
131 /* BUGGY IMAGE WORKAROUND 132 // Note: These are not necessarily SkPMColors
132
133 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count
134 which is a problem since we use the byte as an index. To work around thi s we grow
135 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot.
136 */
137 const int colorCount = numPalette + (numPalette < 256);
138 // Note: These are not necessarily SkPMColors.
139 SkPMColor colorStorage[256]; // worst-case storage 133 SkPMColor colorStorage[256]; // worst-case storage
140 SkPMColor* colorPtr = colorStorage; 134 SkPMColor* colorPtr = colorStorage;
141 135
142 int numTrans; 136 int numTrans;
143 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { 137 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
144 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL); 138 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL);
145 } else { 139 } else {
146 numTrans = 0; 140 numTrans = 0;
147 } 141 }
148 142
(...skipping 19 matching lines...) Expand all
168 palette++; 162 palette++;
169 } 163 }
170 164
171 fReallyHasAlpha = transLessThanFF < 0; 165 fReallyHasAlpha = transLessThanFF < 0;
172 166
173 for (; index < numPalette; index++) { 167 for (; index < numPalette; index++) {
174 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); 168 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue);
175 palette++; 169 palette++;
176 } 170 }
177 171
178 // see BUGGY IMAGE WORKAROUND comment above 172 /* BUGGY IMAGE WORKAROUND
179 if (numPalette < 256) { 173 Invalid images could contain pixel values that are greater than the numb er of palette
180 *colorPtr = colorPtr[-1]; 174 entries. Since we use pixel values as indices into the palette this coul d result in reading
175 beyond the end of the palette which could leak the contents of uninitial ized memory. To
176 ensure this doesn't happen, we grow the colortable to the maximum size t hat can be
177 addressed by the bitdepth of the image and fill it with the last palette color or black if
178 the palette is empty (really broken image).
179 */
180 int colorCount = SkTMax(numPalette, 1 << SkTMin(bitDepth, 8));
181 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0) ;
182 for (; index < colorCount; index++) {
183 *colorPtr++ = lastColor;
184 }
185
186 // Set the new color count
187 if (ctableCount != NULL) {
188 SkASSERT(256 == *ctableCount);
189 *ctableCount = colorCount;
181 } 190 }
182 191
183 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount))); 192 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount)));
184 return true; 193 return true;
185 } 194 }
186 195
187 /////////////////////////////////////////////////////////////////////////////// 196 ///////////////////////////////////////////////////////////////////////////////
188 // Creation 197 // Creation
189 /////////////////////////////////////////////////////////////////////////////// 198 ///////////////////////////////////////////////////////////////////////////////
190 199
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { 278 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
270 png_set_expand_gray_1_2_4_to_8(png_ptr); 279 png_set_expand_gray_1_2_4_to_8(png_ptr);
271 } 280 }
272 281
273 282
274 // Now determine the default SkColorType and SkAlphaType. 283 // Now determine the default SkColorType and SkAlphaType.
275 SkColorType skColorType; 284 SkColorType skColorType;
276 SkAlphaType skAlphaType; 285 SkAlphaType skAlphaType;
277 switch (colorType) { 286 switch (colorType) {
278 case PNG_COLOR_TYPE_PALETTE: 287 case PNG_COLOR_TYPE_PALETTE:
279 // Technically, this is true of the data, but I don't think we want 288 skColorType = kIndex_8_SkColorType;
280 // to support it.
281 // skColorType = kIndex8_SkColorType;
282 skColorType = kN32_SkColorType;
283 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ? 289 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ?
284 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; 290 kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
285 break; 291 break;
286 case PNG_COLOR_TYPE_GRAY: 292 case PNG_COLOR_TYPE_GRAY:
287 if (false) { 293 if (false) {
288 // FIXME: Is this the wrong default behavior? This means if the 294 // FIXME: Is this the wrong default behavior? This means if the
289 // caller supplies the info we gave them, they'll get Alpha 8. 295 // caller supplies the info we gave them, they'll get Alpha 8.
290 skColorType = kAlpha_8_SkColorType; 296 skColorType = kAlpha_8_SkColorType;
291 // FIXME: Strangely, the canonical type for Alpha 8 is Premul. 297 // FIXME: Strangely, the canonical type for Alpha 8 is Premul.
292 skAlphaType = kPremul_SkAlphaType; 298 skAlphaType = kPremul_SkAlphaType;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 } 400 }
395 if (dst.alphaType() == src.alphaType()) { 401 if (dst.alphaType() == src.alphaType()) {
396 return true; 402 return true;
397 } 403 }
398 return kPremul_SkAlphaType == dst.alphaType() && 404 return kPremul_SkAlphaType == dst.alphaType() &&
399 kUnpremul_SkAlphaType == src.alphaType(); 405 kUnpremul_SkAlphaType == src.alphaType();
400 } 406 }
401 407
402 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 408 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
403 void* dst, size_t rowBytes, 409 void* dst, size_t rowBytes,
404 const Options& options) { 410 const Options& options,
411 int* ctableCount) {
405 // FIXME: Could we use the return value of setjmp to specify the type of 412 // FIXME: Could we use the return value of setjmp to specify the type of
406 // error? 413 // error?
407 if (setjmp(png_jmpbuf(fPng_ptr))) { 414 if (setjmp(png_jmpbuf(fPng_ptr))) {
408 SkCodecPrintf("setjmp long jump!\n"); 415 SkCodecPrintf("setjmp long jump!\n");
409 return kInvalidInput; 416 return kInvalidInput;
410 } 417 }
411 418
412 // FIXME: We already retrieved this information. Store it in SkPngCodec? 419 // FIXME: We already retrieved this information. Store it in SkPngCodec?
413 png_uint_32 origWidth, origHeight; 420 png_uint_32 origWidth, origHeight;
414 int bitDepth, pngColorType, interlaceType; 421 int bitDepth, pngColorType, interlaceType;
415 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, 422 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
416 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); 423 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL);
417 424
418 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ? 425 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ?
419 png_set_interlace_handling(fPng_ptr) : 1; 426 png_set_interlace_handling(fPng_ptr) : 1;
420 427
421 // Set to the default before calling decodePalette, which may change it. 428 // Set to the default before calling decodePalette, which may change it.
422 fReallyHasAlpha = false; 429 fReallyHasAlpha = false;
423 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { 430 if (PNG_COLOR_TYPE_PALETTE == pngColorType) {
424 fSrcConfig = SkSwizzler::kIndex; 431 fSrcConfig = SkSwizzler::kIndex;
425 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ))) { 432 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ), bitDepth,
433 ctableCount)) {
426 return kInvalidInput; 434 return kInvalidInput;
427 } 435 }
428 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { 436 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) {
429 // Note: we check the destination, since otherwise we would have 437 // Note: we check the destination, since otherwise we would have
430 // told png to upscale. 438 // told png to upscale.
431 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); 439 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType);
432 fSrcConfig = SkSwizzler::kGray; 440 fSrcConfig = SkSwizzler::kGray;
433 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { 441 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
434 fSrcConfig = SkSwizzler::kRGBX; 442 fSrcConfig = SkSwizzler::kRGBX;
435 } else { 443 } else {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 if (!this->handleRewind()) { 492 if (!this->handleRewind()) {
485 return kCouldNotRewind; 493 return kCouldNotRewind;
486 } 494 }
487 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { 495 if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
488 return kInvalidScale; 496 return kInvalidScale;
489 } 497 }
490 if (!conversion_possible(requestedInfo, this->getInfo())) { 498 if (!conversion_possible(requestedInfo, this->getInfo())) {
491 return kInvalidConversion; 499 return kInvalidConversion;
492 } 500 }
493 501
502 // Note that ctableCount will be modified if there is a color table
494 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, 503 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes,
495 options); 504 options, ctableCount);
505
506 // Copy the color table to the client if necessary
507 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
508 SkASSERT(NULL != ctable);
509 SkASSERT(NULL != ctableCount);
510 SkASSERT(NULL != fColorTable.get());
511 sk_memcpy32(ctable, fColorTable->readColors(), *ctableCount);
msarett 2015/04/03 18:01:32 Is this better than using regular memcpy?
scroggo 2015/04/06 14:55:11 We have MemoryBench which compares the two, and it
msarett 2015/04/06 18:10:55 Acknowledged.
512 }
513
496 if (result != kSuccess) { 514 if (result != kSuccess) {
497 return result; 515 return result;
498 } 516 }
499 517
500 // FIXME: Could we use the return value of setjmp to specify the type of 518 // FIXME: Could we use the return value of setjmp to specify the type of
501 // error? 519 // error?
502 if (setjmp(png_jmpbuf(fPng_ptr))) { 520 if (setjmp(png_jmpbuf(fPng_ptr))) {
503 SkCodecPrintf("setjmp long jump!\n"); 521 SkCodecPrintf("setjmp long jump!\n");
504 return kInvalidInput; 522 return kInvalidInput;
505 } 523 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 SkCodecPrintf("no conversion possible\n"); 641 SkCodecPrintf("no conversion possible\n");
624 return NULL; 642 return NULL;
625 } 643 }
626 644
627 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, 645 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded,
628 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to 646 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to
629 // be at least dstInfo.minRowBytes. 647 // be at least dstInfo.minRowBytes.
630 Options opts; 648 Options opts;
631 // FIXME: Pass this in to getScanlineDecoder? 649 // FIXME: Pass this in to getScanlineDecoder?
632 opts.fZeroInitialized = kNo_ZeroInitialized; 650 opts.fZeroInitialized = kNo_ZeroInitialized;
633 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts) != kSuccess) { 651 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts, NUL L) != kSuccess) {
scroggo 2015/04/06 14:55:11 Maybe add a FIXME acknowledging that getScanlineDe
msarett 2015/04/06 18:10:55 Done.
634 SkCodecPrintf("failed to initialize the swizzler.\n"); 652 SkCodecPrintf("failed to initialize the swizzler.\n");
635 return NULL; 653 return NULL;
636 } 654 }
637 655
638 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); 656 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
639 if (fNumberPasses > 1) { 657 if (fNumberPasses > 1) {
640 // We cannot efficiently do scanline decoding. 658 // We cannot efficiently do scanline decoding.
641 return NULL; 659 return NULL;
642 } 660 }
643 661
644 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); 662 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this));
645 } 663 }
646 664
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698