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 "SkBitmap.h" | 8 #include "SkBitmap.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 fPng_ptr = nullptr; | 85 fPng_ptr = nullptr; |
86 fInfo_ptr = nullptr; | 86 fInfo_ptr = nullptr; |
87 } | 87 } |
88 | 88 |
89 private: | 89 private: |
90 png_structp fPng_ptr; | 90 png_structp fPng_ptr; |
91 png_infop fInfo_ptr; | 91 png_infop fInfo_ptr; |
92 }; | 92 }; |
93 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) | 93 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) |
94 | 94 |
| 95 static inline SkAlphaType xform_alpha_type(SkAlphaType dstAlphaType, SkAlphaType
srcAlphaType) { |
| 96 return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlph
aType; |
| 97 } |
| 98 |
95 // Note: SkColorTable claims to store SkPMColors, which is not necessarily the c
ase here. | 99 // Note: SkColorTable claims to store SkPMColors, which is not necessarily the c
ase here. |
96 bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, in
t* ctableCount) { | 100 bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount)
{ |
97 | 101 |
98 int numColors; | 102 int numColors; |
99 png_color* palette; | 103 png_color* palette; |
100 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { | 104 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { |
101 return false; | 105 return false; |
102 } | 106 } |
103 | 107 |
104 // Note: These are not necessarily SkPMColors. | 108 // Contents depend on tableColorType and our choice of if/when to premultipl
y: |
105 SkPMColor colorPtr[256]; | 109 // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA } |
| 110 SkPMColor colorTable[256]; |
| 111 SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo.
colorType(); |
106 | 112 |
107 png_bytep alphas; | 113 png_bytep alphas; |
108 int numColorsWithAlpha = 0; | 114 int numColorsWithAlpha = 0; |
109 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)
) { | 115 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)
) { |
| 116 // If we are performing a color xform, it will handle the premultiply.
Otherwise, |
| 117 // we'll do it here. |
| 118 bool premultiply = !fColorXform && needs_premul(dstInfo, this->getInfo(
)); |
| 119 |
110 // Choose which function to use to create the color table. If the final
destination's | 120 // Choose which function to use to create the color table. If the final
destination's |
111 // colortype is unpremultiplied, the color table will store unpremultipl
ied colors. | 121 // colortype is unpremultiplied, the color table will store unpremultipl
ied colors. |
112 PackColorProc proc = choose_pack_color_proc(premultiply, dstColorType); | 122 PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType)
; |
113 | 123 |
114 for (int i = 0; i < numColorsWithAlpha; i++) { | 124 for (int i = 0; i < numColorsWithAlpha; i++) { |
115 // We don't have a function in SkOpts that combines a set of alphas
with a set | 125 // We don't have a function in SkOpts that combines a set of alphas
with a set |
116 // of RGBs. We could write one, but it's hardly worth it, given tha
t this | 126 // of RGBs. We could write one, but it's hardly worth it, given tha
t this |
117 // is such a small fraction of the total decode time. | 127 // is such a small fraction of the total decode time. |
118 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette-
>blue); | 128 colorTable[i] = proc(alphas[i], palette->red, palette->green, palett
e->blue); |
119 palette++; | 129 palette++; |
120 } | 130 } |
121 } | 131 } |
122 | 132 |
123 if (numColorsWithAlpha < numColors) { | 133 if (numColorsWithAlpha < numColors) { |
124 // The optimized code depends on a 3-byte png_color struct with the colo
rs | 134 // The optimized code depends on a 3-byte png_color struct with the colo
rs |
125 // in RGB order. These checks make sure it is safe to use. | 135 // in RGB order. These checks make sure it is safe to use. |
126 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op
ts are broken."); | 136 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op
ts are broken."); |
127 #ifdef SK_DEBUG | 137 #ifdef SK_DEBUG |
128 SkASSERT(&palette->red < &palette->green); | 138 SkASSERT(&palette->red < &palette->green); |
129 SkASSERT(&palette->green < &palette->blue); | 139 SkASSERT(&palette->green < &palette->blue); |
130 #endif | 140 #endif |
131 | 141 |
132 if (is_rgba(dstColorType)) { | 142 if (is_rgba(tableColorType)) { |
133 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, | 143 SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette, |
134 numColors - numColorsWithAlpha); | 144 numColors - numColorsWithAlpha); |
135 } else { | 145 } else { |
136 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, | 146 SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette, |
137 numColors - numColorsWithAlpha); | 147 numColors - numColorsWithAlpha); |
138 } | 148 } |
139 } | 149 } |
140 | 150 |
| 151 // If we are not decoding to F16, we can color xform now and store the resul
ts |
| 152 // in the color table. |
| 153 if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) { |
| 154 SkColorType xformColorType = is_rgba(dstInfo.colorType()) ? |
| 155 kRGBA_8888_SkColorType : kBGRA_8888_SkColorType; |
| 156 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), |
| 157 this->getInfo().alphaType(
)); |
| 158 fColorXform->apply(colorTable, colorTable, numColors, xformColorType, xf
ormAlphaType); |
| 159 } |
| 160 |
141 // Pad the color table with the last color in the table (or black) in the ca
se that | 161 // Pad the color table with the last color in the table (or black) in the ca
se that |
142 // invalid pixel indices exceed the number of colors in the table. | 162 // invalid pixel indices exceed the number of colors in the table. |
143 const int maxColors = 1 << fBitDepth; | 163 const int maxColors = 1 << fBitDepth; |
144 if (numColors < maxColors) { | 164 if (numColors < maxColors) { |
145 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color
BLACK; | 165 SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_Col
orBLACK; |
146 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); | 166 sk_memset32(colorTable + numColors, lastColor, maxColors - numColors); |
147 } | 167 } |
148 | 168 |
149 // Set the new color count. | 169 // Set the new color count. |
150 if (ctableCount != nullptr) { | 170 if (ctableCount != nullptr) { |
151 *ctableCount = maxColors; | 171 *ctableCount = maxColors; |
152 } | 172 } |
153 | 173 |
154 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); | 174 fColorTable.reset(new SkColorTable(colorTable, maxColors)); |
155 return true; | 175 return true; |
156 } | 176 } |
157 | 177 |
158 /////////////////////////////////////////////////////////////////////////////// | 178 /////////////////////////////////////////////////////////////////////////////// |
159 // Creation | 179 // Creation |
160 /////////////////////////////////////////////////////////////////////////////// | 180 /////////////////////////////////////////////////////////////////////////////// |
161 | 181 |
162 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { | 182 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { |
163 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); | 183 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); |
164 } | 184 } |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 | 380 |
361 void SkPngCodec::allocateStorage() { | 381 void SkPngCodec::allocateStorage() { |
362 size_t colorXformBytes = fColorXform ? fSwizzler->swizzleWidth() * sizeof(ui
nt32_t) : 0; | 382 size_t colorXformBytes = fColorXform ? fSwizzler->swizzleWidth() * sizeof(ui
nt32_t) : 0; |
363 | 383 |
364 fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes); | 384 fStorage.reset(SkAlign4(fSrcRowBytes) + colorXformBytes); |
365 fSwizzlerSrcRow = fStorage.get(); | 385 fSwizzlerSrcRow = fStorage.get(); |
366 fColorXformSrcRow = | 386 fColorXformSrcRow = |
367 fColorXform ? SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcR
owBytes)) : 0; | 387 fColorXform ? SkTAddOffset<uint32_t>(fSwizzlerSrcRow, SkAlign4(fSrcR
owBytes)) : 0; |
368 } | 388 } |
369 | 389 |
| 390 static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo
::Color srcColor) { |
| 391 // We will apply the color xform when reading the color table, unless F16 is
requested. |
| 392 return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType ==
dstColorType; |
| 393 } |
| 394 |
370 class SkPngNormalCodec : public SkPngCodec { | 395 class SkPngNormalCodec : public SkPngCodec { |
371 public: | 396 public: |
372 SkPngNormalCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageI
nfo, | 397 SkPngNormalCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageI
nfo, |
373 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr
, | 398 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr
, |
374 png_infop info_ptr, int bitDepth) | 399 png_infop info_ptr, int bitDepth) |
375 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p
tr, bitDepth, 1) | 400 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p
tr, bitDepth, 1) |
376 {} | 401 {} |
377 | 402 |
378 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, | 403 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
379 SkPMColor ctable[], int* ctableCount) override { | 404 SkPMColor ctable[], int* ctableCount) override { |
(...skipping 13 matching lines...) Expand all Loading... |
393 | 418 |
394 // Assume that an error in libpng indicates an incomplete input. | 419 // Assume that an error in libpng indicates an incomplete input. |
395 int y = 0; | 420 int y = 0; |
396 if (setjmp(png_jmpbuf(fPng_ptr))) { | 421 if (setjmp(png_jmpbuf(fPng_ptr))) { |
397 SkCodecPrintf("Failed to read row.\n"); | 422 SkCodecPrintf("Failed to read row.\n"); |
398 return y; | 423 return y; |
399 } | 424 } |
400 | 425 |
401 void* swizzlerDstRow = dst; | 426 void* swizzlerDstRow = dst; |
402 size_t swizzlerDstRowBytes = rowBytes; | 427 size_t swizzlerDstRowBytes = rowBytes; |
403 if (fColorXform) { | 428 |
| 429 bool colorXform = fColorXform && |
| 430 apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo(
).color()); |
| 431 if (colorXform) { |
404 swizzlerDstRow = fColorXformSrcRow; | 432 swizzlerDstRow = fColorXformSrcRow; |
405 swizzlerDstRowBytes = 0; | 433 swizzlerDstRowBytes = 0; |
406 } | 434 } |
407 | 435 |
408 SkAlphaType xformAlphaType = (kOpaque_SkAlphaType == this->getInfo().alp
haType()) ? | 436 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), |
409 kOpaque_SkAlphaType : dstInfo.alphaType(); | 437 this->getInfo().alphaType(
)); |
410 for (; y < count; y++) { | 438 for (; y < count; y++) { |
411 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); | 439 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); |
412 fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow); | 440 fSwizzler->swizzle(swizzlerDstRow, fSwizzlerSrcRow); |
413 | 441 |
414 if (fColorXform) { | 442 if (colorXform) { |
415 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz
ler->swizzleWidth(), | 443 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz
ler->swizzleWidth(), |
416 dstInfo.colorType(), xformAlphaType); | 444 dstInfo.colorType(), xformAlphaType); |
417 dst = SkTAddOffset<void>(dst, rowBytes); | 445 dst = SkTAddOffset<void>(dst, rowBytes); |
418 } | 446 } |
419 | 447 |
420 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy
tes); | 448 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy
tes); |
421 } | 449 } |
422 | 450 |
423 return y; | 451 return y; |
424 } | 452 } |
(...skipping 10 matching lines...) Expand all Loading... |
435 | 463 |
436 for (int row = 0; row < count; row++) { | 464 for (int row = 0; row < count; row++) { |
437 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); | 465 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); |
438 } | 466 } |
439 return true; | 467 return true; |
440 } | 468 } |
441 | 469 |
442 typedef SkPngCodec INHERITED; | 470 typedef SkPngCodec INHERITED; |
443 }; | 471 }; |
444 | 472 |
445 | |
446 class SkPngInterlacedCodec : public SkPngCodec { | 473 class SkPngInterlacedCodec : public SkPngCodec { |
447 public: | 474 public: |
448 SkPngInterlacedCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& im
ageInfo, | 475 SkPngInterlacedCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& im
ageInfo, |
449 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr
, | 476 SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr
, |
450 png_infop info_ptr, int bitDepth, int numberPasses) | 477 png_infop info_ptr, int bitDepth, int numberPasses) |
451 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p
tr, bitDepth, | 478 : INHERITED(encodedInfo, imageInfo, stream, chunkReader, png_ptr, info_p
tr, bitDepth, |
452 numberPasses) | 479 numberPasses) |
453 , fCanSkipRewind(false) | 480 , fCanSkipRewind(false) |
454 { | 481 { |
455 SkASSERT(numberPasses != 1); | 482 SkASSERT(numberPasses != 1); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 } | 520 } |
494 // Discard rows that we don't need. | 521 // Discard rows that we don't need. |
495 for (int y = 0; y < this->getInfo().height() - startRow - count; y++
) { | 522 for (int y = 0; y < this->getInfo().height() - startRow - count; y++
) { |
496 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); | 523 png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr); |
497 } | 524 } |
498 } | 525 } |
499 | 526 |
500 // Swizzle and xform the rows we care about | 527 // Swizzle and xform the rows we care about |
501 void* swizzlerDstRow = dst; | 528 void* swizzlerDstRow = dst; |
502 size_t swizzlerDstRowBytes = rowBytes; | 529 size_t swizzlerDstRowBytes = rowBytes; |
503 if (fColorXform) { | 530 |
| 531 bool colorXform = fColorXform && |
| 532 apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo(
).color()); |
| 533 if (colorXform) { |
504 swizzlerDstRow = fColorXformSrcRow; | 534 swizzlerDstRow = fColorXformSrcRow; |
505 swizzlerDstRowBytes = 0; | 535 swizzlerDstRowBytes = 0; |
506 } | 536 } |
507 | 537 |
508 SkAlphaType xformAlphaType = (kOpaque_SkAlphaType == this->getInfo().alp
haType()) ? | 538 SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), |
509 kOpaque_SkAlphaType : dstInfo.alphaType(); | 539 this->getInfo().alphaType(
)); |
510 srcRow = storage.get(); | 540 srcRow = storage.get(); |
511 for (int y = 0; y < count; y++) { | 541 for (int y = 0; y < count; y++) { |
512 fSwizzler->swizzle(swizzlerDstRow, srcRow); | 542 fSwizzler->swizzle(swizzlerDstRow, srcRow); |
513 srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes); | 543 srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes); |
514 | 544 |
515 if (fColorXform) { | 545 if (colorXform) { |
516 if (fColorXform) { | 546 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizz
ler->swizzleWidth(), |
517 fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, | 547 dstInfo.colorType(), xformAlphaType); |
518 fSwizzler->swizzleWidth(), dstInfo.colorT
ype(), | 548 dst = SkTAddOffset<void>(dst, rowBytes); |
519 xformAlphaType); | |
520 dst = SkTAddOffset<void>(dst, rowBytes); | |
521 } | |
522 } | 549 } |
523 | 550 |
524 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy
tes); | 551 swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBy
tes); |
525 } | 552 } |
526 | 553 |
527 return count; | 554 return count; |
528 } | 555 } |
529 | 556 |
530 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 557 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
531 // rewind stream if have previously called onGetScanlines, | 558 // rewind stream if have previously called onGetScanlines, |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
795 if (needsColorXform) { | 822 if (needsColorXform) { |
796 switch (dstInfo.colorType()) { | 823 switch (dstInfo.colorType()) { |
797 case kRGBA_8888_SkColorType: | 824 case kRGBA_8888_SkColorType: |
798 case kBGRA_8888_SkColorType: | 825 case kBGRA_8888_SkColorType: |
799 case kRGBA_F16_SkColorType: | 826 case kRGBA_F16_SkColorType: |
800 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType
); | 827 swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType
); |
801 if (kPremul_SkAlphaType == dstInfo.alphaType()) { | 828 if (kPremul_SkAlphaType == dstInfo.alphaType()) { |
802 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaT
ype); | 829 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaT
ype); |
803 } | 830 } |
804 break; | 831 break; |
| 832 case kIndex_8_SkColorType: |
| 833 break; |
805 default: | 834 default: |
806 return false; | 835 return false; |
807 } | 836 } |
808 | 837 |
809 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpac
e()), | 838 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpac
e()), |
810 sk_ref_sp(dstInfo.colorSpace())); | 839 sk_ref_sp(dstInfo.colorSpace())); |
811 | 840 |
812 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) { | 841 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) { |
813 return false; | 842 return false; |
814 } | 843 } |
815 } | 844 } |
816 | 845 |
817 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { | 846 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { |
818 if (!this->createColorTable(swizzlerInfo.colorType(), | 847 if (!this->createColorTable(dstInfo, ctableCount)) { |
819 kPremul_SkAlphaType == swizzlerInfo.alphaTyp
e(), ctableCount)) { | |
820 return false; | 848 return false; |
821 } | 849 } |
822 } | 850 } |
823 | 851 |
824 // Copy the color table to the client if they request kIndex8 mode | 852 // Copy the color table to the client if they request kIndex8 mode |
825 copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount); | 853 copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount); |
826 | 854 |
827 // Create the swizzler. SkPngCodec retains ownership of the color table. | 855 // Create the swizzler. SkPngCodec retains ownership of the color table. |
828 const SkPMColor* colors = get_color_ptr(fColorTable.get()); | 856 const SkPMColor* colors = get_color_ptr(fColorTable.get()); |
829 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, s
wizzlerInfo, | 857 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, s
wizzlerInfo, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
889 SkCodec* outCodec; | 917 SkCodec* outCodec; |
890 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) { | 918 if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) { |
891 // Codec has taken ownership of the stream. | 919 // Codec has taken ownership of the stream. |
892 SkASSERT(outCodec); | 920 SkASSERT(outCodec); |
893 streamDeleter.release(); | 921 streamDeleter.release(); |
894 return outCodec; | 922 return outCodec; |
895 } | 923 } |
896 | 924 |
897 return nullptr; | 925 return nullptr; |
898 } | 926 } |
OLD | NEW |