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

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: Enabled kIndex8 testing in dm, Created a test for SkSwizzler::Fill() 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 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 fInfo_ptr = NULL; 386 fInfo_ptr = NULL;
381 } 387 }
382 } 388 }
383 389
384 /////////////////////////////////////////////////////////////////////////////// 390 ///////////////////////////////////////////////////////////////////////////////
385 // Getting the pixels 391 // Getting the pixels
386 /////////////////////////////////////////////////////////////////////////////// 392 ///////////////////////////////////////////////////////////////////////////////
387 393
388 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { 394 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
389 // TODO: Support other conversions 395 // TODO: Support other conversions
390 if (dst.colorType() != src.colorType()) { 396 if (dst.colorType() != src.colorType()) {
scroggo 2015/04/07 21:15:34 I think we should still support N32 if src was kIn
msarett 2015/04/08 13:59:10 Agreed, I missed this one.
391 return false; 397 return false;
392 } 398 }
393 if (dst.profileType() != src.profileType()) { 399 if (dst.profileType() != src.profileType()) {
394 return false; 400 return false;
395 } 401 }
396 if (dst.alphaType() == src.alphaType()) { 402 if (dst.alphaType() == src.alphaType()) {
397 return true; 403 return true;
398 } 404 }
399 return kPremul_SkAlphaType == dst.alphaType() && 405 return kPremul_SkAlphaType == dst.alphaType() &&
400 kUnpremul_SkAlphaType == src.alphaType(); 406 kUnpremul_SkAlphaType == src.alphaType();
401 } 407 }
402 408
403 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 409 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
404 void* dst, size_t rowBytes, 410 void* dst, size_t rowBytes,
405 const Options& options) { 411 const Options& options,
412 int* ctableCount) {
406 // FIXME: Could we use the return value of setjmp to specify the type of 413 // FIXME: Could we use the return value of setjmp to specify the type of
407 // error? 414 // error?
408 if (setjmp(png_jmpbuf(fPng_ptr))) { 415 if (setjmp(png_jmpbuf(fPng_ptr))) {
409 SkCodecPrintf("setjmp long jump!\n"); 416 SkCodecPrintf("setjmp long jump!\n");
410 return kInvalidInput; 417 return kInvalidInput;
411 } 418 }
412 419
413 // FIXME: We already retrieved this information. Store it in SkPngCodec? 420 // FIXME: We already retrieved this information. Store it in SkPngCodec?
414 png_uint_32 origWidth, origHeight; 421 png_uint_32 origWidth, origHeight;
415 int bitDepth, pngColorType, interlaceType; 422 int bitDepth, pngColorType, interlaceType;
416 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, 423 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
417 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); 424 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL);
418 425
419 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ? 426 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ?
420 png_set_interlace_handling(fPng_ptr) : 1; 427 png_set_interlace_handling(fPng_ptr) : 1;
421 428
422 // Set to the default before calling decodePalette, which may change it. 429 // Set to the default before calling decodePalette, which may change it.
423 fReallyHasAlpha = false; 430 fReallyHasAlpha = false;
424 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { 431 if (PNG_COLOR_TYPE_PALETTE == pngColorType) {
425 fSrcConfig = SkSwizzler::kIndex; 432 fSrcConfig = SkSwizzler::kIndex;
426 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ))) { 433 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ), bitDepth,
434 ctableCount)) {
427 return kInvalidInput; 435 return kInvalidInput;
428 } 436 }
429 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { 437 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) {
430 // Note: we check the destination, since otherwise we would have 438 // Note: we check the destination, since otherwise we would have
431 // told png to upscale. 439 // told png to upscale.
432 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); 440 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType);
433 fSrcConfig = SkSwizzler::kGray; 441 fSrcConfig = SkSwizzler::kGray;
434 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { 442 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
435 fSrcConfig = SkSwizzler::kRGBX; 443 fSrcConfig = SkSwizzler::kRGBX;
436 } else { 444 } else {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 if (!this->handleRewind()) { 493 if (!this->handleRewind()) {
486 return kCouldNotRewind; 494 return kCouldNotRewind;
487 } 495 }
488 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { 496 if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
489 return kInvalidScale; 497 return kInvalidScale;
490 } 498 }
491 if (!conversion_possible(requestedInfo, this->getInfo())) { 499 if (!conversion_possible(requestedInfo, this->getInfo())) {
492 return kInvalidConversion; 500 return kInvalidConversion;
493 } 501 }
494 502
503 // Note that ctableCount will be modified if there is a color table
495 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, 504 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes,
496 options); 505 options, ctableCount);
506
507 // Copy the color table to the client if necessary
508 if (kIndex_8_SkColorType == requestedInfo.colorType()) {
509 SkASSERT(NULL != ctable);
510 SkASSERT(NULL != ctableCount);
511 SkASSERT(NULL != fColorTable.get());
512 sk_memcpy32(ctable, fColorTable->readColors(), *ctableCount);
513 }
514
497 if (result != kSuccess) { 515 if (result != kSuccess) {
498 return result; 516 return result;
499 } 517 }
500 518
501 // FIXME: Could we use the return value of setjmp to specify the type of 519 // FIXME: Could we use the return value of setjmp to specify the type of
502 // error? 520 // error?
503 if (setjmp(png_jmpbuf(fPng_ptr))) { 521 if (setjmp(png_jmpbuf(fPng_ptr))) {
504 SkCodecPrintf("setjmp long jump!\n"); 522 SkCodecPrintf("setjmp long jump!\n");
505 return kInvalidInput; 523 return kInvalidInput;
506 } 524 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 SkCodecPrintf("no conversion possible\n"); 642 SkCodecPrintf("no conversion possible\n");
625 return NULL; 643 return NULL;
626 } 644 }
627 645
628 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, 646 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded,
629 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to 647 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to
630 // be at least dstInfo.minRowBytes. 648 // be at least dstInfo.minRowBytes.
631 Options opts; 649 Options opts;
632 // FIXME: Pass this in to getScanlineDecoder? 650 // FIXME: Pass this in to getScanlineDecoder?
633 opts.fZeroInitialized = kNo_ZeroInitialized; 651 opts.fZeroInitialized = kNo_ZeroInitialized;
634 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts) != kSuccess) { 652 // FIXME: onGetScanlineDecoder does not currently have a way to get color ta ble information
653 // for a kIndex8 decoder.
654 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts, NUL L) != kSuccess) {
635 SkCodecPrintf("failed to initialize the swizzler.\n"); 655 SkCodecPrintf("failed to initialize the swizzler.\n");
636 return NULL; 656 return NULL;
637 } 657 }
638 658
639 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); 659 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
640 if (fNumberPasses > 1) { 660 if (fNumberPasses > 1) {
641 // We cannot efficiently do scanline decoding. 661 // We cannot efficiently do scanline decoding.
642 return NULL; 662 return NULL;
643 } 663 }
644 664
645 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); 665 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this));
646 } 666 }
647 667
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698