xref: /aosp_15_r20/external/skia/src/encode/SkPngEncoderBase.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2024 Google LLC.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/encode/SkPngEncoderBase.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
11*c8dee2aaSAndroid Build Coastguard Worker 
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPixmap.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkEncodedInfo.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkMSAN.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkSafeMath.h"
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker namespace {
24*c8dee2aaSAndroid Build Coastguard Worker 
makeInfo(const SkImageInfo & srcInfo,SkEncodedInfo::Color color,int bitsPerComponent)25*c8dee2aaSAndroid Build Coastguard Worker SkEncodedInfo makeInfo(const SkImageInfo& srcInfo,
26*c8dee2aaSAndroid Build Coastguard Worker                        SkEncodedInfo::Color color,
27*c8dee2aaSAndroid Build Coastguard Worker                        int bitsPerComponent) {
28*c8dee2aaSAndroid Build Coastguard Worker     SkEncodedInfo::Alpha alpha =
29*c8dee2aaSAndroid Build Coastguard Worker             color == SkEncodedInfo::kGray_Color || color == SkEncodedInfo::kRGB_Color
30*c8dee2aaSAndroid Build Coastguard Worker                     ? SkEncodedInfo::kOpaque_Alpha
31*c8dee2aaSAndroid Build Coastguard Worker                     : SkEncodedInfo::kUnpremul_Alpha;
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker     return SkEncodedInfo::Make(srcInfo.width(), srcInfo.height(), color, alpha, bitsPerComponent);
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker 
makeGray8Info(const SkImageInfo & srcInfo)36*c8dee2aaSAndroid Build Coastguard Worker SkEncodedInfo makeGray8Info(const SkImageInfo& srcInfo) {
37*c8dee2aaSAndroid Build Coastguard Worker     return makeInfo(srcInfo, SkEncodedInfo::kGray_Color, 8);
38*c8dee2aaSAndroid Build Coastguard Worker }
39*c8dee2aaSAndroid Build Coastguard Worker 
makeGrayAlpha8Info(const SkImageInfo & srcInfo)40*c8dee2aaSAndroid Build Coastguard Worker SkEncodedInfo makeGrayAlpha8Info(const SkImageInfo& srcInfo) {
41*c8dee2aaSAndroid Build Coastguard Worker     return makeInfo(srcInfo, SkEncodedInfo::kGrayAlpha_Color, 8);
42*c8dee2aaSAndroid Build Coastguard Worker }
43*c8dee2aaSAndroid Build Coastguard Worker 
makeRgb8Info(const SkImageInfo & srcInfo)44*c8dee2aaSAndroid Build Coastguard Worker SkEncodedInfo makeRgb8Info(const SkImageInfo& srcInfo) {
45*c8dee2aaSAndroid Build Coastguard Worker     return makeInfo(srcInfo, SkEncodedInfo::kRGB_Color, 8);
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker 
makeRgba8Info(const SkImageInfo & srcInfo)48*c8dee2aaSAndroid Build Coastguard Worker SkEncodedInfo makeRgba8Info(const SkImageInfo& srcInfo) {
49*c8dee2aaSAndroid Build Coastguard Worker     return makeInfo(srcInfo, SkEncodedInfo::kRGBA_Color, 8);
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker 
makeRgb16Info(const SkImageInfo & srcInfo)52*c8dee2aaSAndroid Build Coastguard Worker SkEncodedInfo makeRgb16Info(const SkImageInfo& srcInfo) {
53*c8dee2aaSAndroid Build Coastguard Worker     return makeInfo(srcInfo, SkEncodedInfo::kRGB_Color, 16);
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker 
makeRgba16Info(const SkImageInfo & srcInfo)56*c8dee2aaSAndroid Build Coastguard Worker SkEncodedInfo makeRgba16Info(const SkImageInfo& srcInfo) {
57*c8dee2aaSAndroid Build Coastguard Worker     return makeInfo(srcInfo, SkEncodedInfo::kRGBA_Color, 16);
58*c8dee2aaSAndroid Build Coastguard Worker }
59*c8dee2aaSAndroid Build Coastguard Worker 
makeTargetInfo(SkEncodedInfo dstInfo,transform_scanline_proc transformProc)60*c8dee2aaSAndroid Build Coastguard Worker std::optional<SkPngEncoderBase::TargetInfo> makeTargetInfo(SkEncodedInfo dstInfo,
61*c8dee2aaSAndroid Build Coastguard Worker                                                            transform_scanline_proc transformProc) {
62*c8dee2aaSAndroid Build Coastguard Worker     // `static_cast<size_t>`(dstInfo.bitsPerPixel())` uses trustworthy, bounded
63*c8dee2aaSAndroid Build Coastguard Worker     // data as input - no need to use `SkSafeMath` for this part.
64*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(dstInfo.bitsPerComponent() == 8 || dstInfo.bitsPerComponent() == 16);
65*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(dstInfo.bitsPerPixel() <= (16 * 4));
66*c8dee2aaSAndroid Build Coastguard Worker     size_t bitsPerPixel = static_cast<size_t>(dstInfo.bitsPerPixel());
67*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT((bitsPerPixel % 8) == 0);
68*c8dee2aaSAndroid Build Coastguard Worker     size_t bytesPerPixel = bitsPerPixel / 8;
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker     SkSafeMath safe;
71*c8dee2aaSAndroid Build Coastguard Worker     size_t dstRowSize = safe.mul(safe.castTo<size_t>(dstInfo.width()), bytesPerPixel);
72*c8dee2aaSAndroid Build Coastguard Worker     if (!safe.ok()) {
73*c8dee2aaSAndroid Build Coastguard Worker         return std::nullopt;
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     return SkPngEncoderBase::TargetInfo{std::move(dstInfo), transformProc, dstRowSize};
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker }  // namespace
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker // static
getTargetInfo(const SkImageInfo & srcInfo)82*c8dee2aaSAndroid Build Coastguard Worker std::optional<SkPngEncoderBase::TargetInfo> SkPngEncoderBase::getTargetInfo(
83*c8dee2aaSAndroid Build Coastguard Worker         const SkImageInfo& srcInfo) {
84*c8dee2aaSAndroid Build Coastguard Worker     switch (srcInfo.colorType()) {
85*c8dee2aaSAndroid Build Coastguard Worker         case kUnknown_SkColorType:
86*c8dee2aaSAndroid Build Coastguard Worker             return std::nullopt;
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker         // TODO: I don't think this can just use kRGBA's procs.
89*c8dee2aaSAndroid Build Coastguard Worker         // kPremul is especially tricky here, since it's presumably TF⁻¹(rgb * a),
90*c8dee2aaSAndroid Build Coastguard Worker         // so to get at unpremul rgb we'd need to undo the transfer function first.
91*c8dee2aaSAndroid Build Coastguard Worker         case kSRGBA_8888_SkColorType:
92*c8dee2aaSAndroid Build Coastguard Worker             return std::nullopt;
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_8888_SkColorType:
95*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
96*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
97*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgb8Info(srcInfo), transform_scanline_RGBX);
98*c8dee2aaSAndroid Build Coastguard Worker                 case kUnpremul_SkAlphaType:
99*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba8Info(srcInfo), transform_scanline_memcpy);
100*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
101*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba8Info(srcInfo), transform_scanline_rgbA);
102*c8dee2aaSAndroid Build Coastguard Worker                 default:
103*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
104*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
105*c8dee2aaSAndroid Build Coastguard Worker             }
106*c8dee2aaSAndroid Build Coastguard Worker         case kBGRA_8888_SkColorType:
107*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
108*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
109*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgb8Info(srcInfo), transform_scanline_BGRX);
110*c8dee2aaSAndroid Build Coastguard Worker                 case kUnpremul_SkAlphaType:
111*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba8Info(srcInfo), transform_scanline_BGRA);
112*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
113*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba8Info(srcInfo), transform_scanline_bgrA);
114*c8dee2aaSAndroid Build Coastguard Worker                 default:
115*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
116*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
117*c8dee2aaSAndroid Build Coastguard Worker             }
118*c8dee2aaSAndroid Build Coastguard Worker         case kRGB_565_SkColorType:
119*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(srcInfo.isOpaque());
120*c8dee2aaSAndroid Build Coastguard Worker             return makeTargetInfo(makeRgb8Info(srcInfo), transform_scanline_565);
121*c8dee2aaSAndroid Build Coastguard Worker         case kRGB_888x_SkColorType:
122*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(srcInfo.isOpaque());
123*c8dee2aaSAndroid Build Coastguard Worker             return makeTargetInfo(makeRgb8Info(srcInfo), transform_scanline_RGBX);
124*c8dee2aaSAndroid Build Coastguard Worker         case kARGB_4444_SkColorType:
125*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
126*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
127*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgb8Info(srcInfo), transform_scanline_444);
128*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
129*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba8Info(srcInfo), transform_scanline_4444);
130*c8dee2aaSAndroid Build Coastguard Worker                 default:
131*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
132*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
133*c8dee2aaSAndroid Build Coastguard Worker             }
134*c8dee2aaSAndroid Build Coastguard Worker         case kGray_8_SkColorType:
135*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(srcInfo.isOpaque());
136*c8dee2aaSAndroid Build Coastguard Worker             return makeTargetInfo(makeGray8Info(srcInfo), transform_scanline_memcpy);
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_F16Norm_SkColorType:
139*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_F16_SkColorType:
140*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
141*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
142*c8dee2aaSAndroid Build Coastguard Worker                 case kUnpremul_SkAlphaType:
143*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo), transform_scanline_F16);
144*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
145*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo), transform_scanline_F16_premul);
146*c8dee2aaSAndroid Build Coastguard Worker                 default:
147*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
148*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
149*c8dee2aaSAndroid Build Coastguard Worker             }
150*c8dee2aaSAndroid Build Coastguard Worker         case kRGB_F16F16F16x_SkColorType:
151*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(srcInfo.isOpaque());
152*c8dee2aaSAndroid Build Coastguard Worker             return makeTargetInfo(makeRgb16Info(srcInfo), transform_scanline_F16F16F16x);
153*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_F32_SkColorType:
154*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
155*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
156*c8dee2aaSAndroid Build Coastguard Worker                 case kUnpremul_SkAlphaType:
157*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo), transform_scanline_F32);
158*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
159*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo), transform_scanline_F32_premul);
160*c8dee2aaSAndroid Build Coastguard Worker                 default:
161*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
162*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
163*c8dee2aaSAndroid Build Coastguard Worker             }
164*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_1010102_SkColorType:
165*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
166*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
167*c8dee2aaSAndroid Build Coastguard Worker                 case kUnpremul_SkAlphaType:
168*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo), transform_scanline_1010102);
169*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
170*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo),
171*c8dee2aaSAndroid Build Coastguard Worker                                           transform_scanline_1010102_premul);
172*c8dee2aaSAndroid Build Coastguard Worker                 default:
173*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
174*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
175*c8dee2aaSAndroid Build Coastguard Worker             }
176*c8dee2aaSAndroid Build Coastguard Worker         case kBGRA_1010102_SkColorType:
177*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
178*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
179*c8dee2aaSAndroid Build Coastguard Worker                 case kUnpremul_SkAlphaType:
180*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo), transform_scanline_bgra_1010102);
181*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
182*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo),
183*c8dee2aaSAndroid Build Coastguard Worker                                           transform_scanline_bgra_1010102_premul);
184*c8dee2aaSAndroid Build Coastguard Worker                 default:
185*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
186*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
187*c8dee2aaSAndroid Build Coastguard Worker             }
188*c8dee2aaSAndroid Build Coastguard Worker         case kRGB_101010x_SkColorType:
189*c8dee2aaSAndroid Build Coastguard Worker             return makeTargetInfo(makeRgb16Info(srcInfo), transform_scanline_101010x);
190*c8dee2aaSAndroid Build Coastguard Worker         case kBGR_101010x_SkColorType:
191*c8dee2aaSAndroid Build Coastguard Worker             return makeTargetInfo(makeRgb16Info(srcInfo), transform_scanline_bgr_101010x);
192*c8dee2aaSAndroid Build Coastguard Worker         case kBGR_101010x_XR_SkColorType:
193*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
194*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
195*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgb16Info(srcInfo),
196*c8dee2aaSAndroid Build Coastguard Worker                                           transform_scanline_bgr_101010x_xr);
197*c8dee2aaSAndroid Build Coastguard Worker                 default:
198*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unsupported color type");
199*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
200*c8dee2aaSAndroid Build Coastguard Worker             }
201*c8dee2aaSAndroid Build Coastguard Worker         case kBGRA_10101010_XR_SkColorType:
202*c8dee2aaSAndroid Build Coastguard Worker             switch (srcInfo.alphaType()) {
203*c8dee2aaSAndroid Build Coastguard Worker                 case kOpaque_SkAlphaType:
204*c8dee2aaSAndroid Build Coastguard Worker                 case kUnpremul_SkAlphaType:
205*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo),
206*c8dee2aaSAndroid Build Coastguard Worker                                           transform_scanline_bgra_10101010_xr);
207*c8dee2aaSAndroid Build Coastguard Worker                 case kPremul_SkAlphaType:
208*c8dee2aaSAndroid Build Coastguard Worker                     return makeTargetInfo(makeRgba16Info(srcInfo),
209*c8dee2aaSAndroid Build Coastguard Worker                                           transform_scanline_bgra_10101010_xr_premul);
210*c8dee2aaSAndroid Build Coastguard Worker                 default:
211*c8dee2aaSAndroid Build Coastguard Worker                     SkDEBUGFAIL("unknown alpha type");
212*c8dee2aaSAndroid Build Coastguard Worker                     return std::nullopt;
213*c8dee2aaSAndroid Build Coastguard Worker             }
214*c8dee2aaSAndroid Build Coastguard Worker         case kAlpha_8_SkColorType:
215*c8dee2aaSAndroid Build Coastguard Worker             return makeTargetInfo(makeGrayAlpha8Info(srcInfo), transform_scanline_A8_to_GrayAlpha);
216*c8dee2aaSAndroid Build Coastguard Worker         case kR8G8_unorm_SkColorType:
217*c8dee2aaSAndroid Build Coastguard Worker         case kR16G16_unorm_SkColorType:
218*c8dee2aaSAndroid Build Coastguard Worker         case kR16G16_float_SkColorType:
219*c8dee2aaSAndroid Build Coastguard Worker         case kA16_unorm_SkColorType:
220*c8dee2aaSAndroid Build Coastguard Worker         case kA16_float_SkColorType:
221*c8dee2aaSAndroid Build Coastguard Worker         case kR16G16B16A16_unorm_SkColorType:
222*c8dee2aaSAndroid Build Coastguard Worker         case kR8_unorm_SkColorType:
223*c8dee2aaSAndroid Build Coastguard Worker         case kRGBA_10x6_SkColorType:
224*c8dee2aaSAndroid Build Coastguard Worker             return std::nullopt;
225*c8dee2aaSAndroid Build Coastguard Worker     }
226*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGFAIL("unsupported color type");
227*c8dee2aaSAndroid Build Coastguard Worker     return std::nullopt;
228*c8dee2aaSAndroid Build Coastguard Worker }
229*c8dee2aaSAndroid Build Coastguard Worker 
SkPngEncoderBase(TargetInfo targetInfo,const SkPixmap & src)230*c8dee2aaSAndroid Build Coastguard Worker SkPngEncoderBase::SkPngEncoderBase(TargetInfo targetInfo, const SkPixmap& src)
231*c8dee2aaSAndroid Build Coastguard Worker         : SkEncoder(src, targetInfo.fDstRowSize), fTargetInfo(std::move(targetInfo)) {
232*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fTargetInfo.fTransformProc);
233*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fTargetInfo.fDstRowSize > 0);
234*c8dee2aaSAndroid Build Coastguard Worker }
235*c8dee2aaSAndroid Build Coastguard Worker 
onEncodeRows(int numRows)236*c8dee2aaSAndroid Build Coastguard Worker bool SkPngEncoderBase::onEncodeRows(int numRows) {
237*c8dee2aaSAndroid Build Coastguard Worker     // https://www.w3.org/TR/png-3/#11IHDR says that "zero is an invalid value"
238*c8dee2aaSAndroid Build Coastguard Worker     // for width and height.
239*c8dee2aaSAndroid Build Coastguard Worker     if (fSrc.width() == 0 || fSrc.height() == 0) {
240*c8dee2aaSAndroid Build Coastguard Worker         return false;
241*c8dee2aaSAndroid Build Coastguard Worker     }
242*c8dee2aaSAndroid Build Coastguard Worker 
243*c8dee2aaSAndroid Build Coastguard Worker     if (numRows < 0) {
244*c8dee2aaSAndroid Build Coastguard Worker         return false;
245*c8dee2aaSAndroid Build Coastguard Worker     }
246*c8dee2aaSAndroid Build Coastguard Worker 
247*c8dee2aaSAndroid Build Coastguard Worker     while (numRows > 0) {
248*c8dee2aaSAndroid Build Coastguard Worker         if (fCurrRow == fSrc.height()) {
249*c8dee2aaSAndroid Build Coastguard Worker             return false;
250*c8dee2aaSAndroid Build Coastguard Worker         }
251*c8dee2aaSAndroid Build Coastguard Worker 
252*c8dee2aaSAndroid Build Coastguard Worker         const void* srcRow = fSrc.addr(0, fCurrRow);
253*c8dee2aaSAndroid Build Coastguard Worker         sk_msan_assert_initialized(srcRow,
254*c8dee2aaSAndroid Build Coastguard Worker                                    (const uint8_t*)srcRow + (fSrc.width() << fSrc.shiftPerPixel()));
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker         fTargetInfo.fTransformProc((char*)fStorage.get(),
257*c8dee2aaSAndroid Build Coastguard Worker                                    (const char*)srcRow,
258*c8dee2aaSAndroid Build Coastguard Worker                                    fSrc.width(),
259*c8dee2aaSAndroid Build Coastguard Worker                                    SkColorTypeBytesPerPixel(fSrc.colorType()));
260*c8dee2aaSAndroid Build Coastguard Worker 
261*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const uint8_t> rowToEncode(fStorage.get(), fTargetInfo.fDstRowSize);
262*c8dee2aaSAndroid Build Coastguard Worker         if (!this->onEncodeRow(rowToEncode)) {
263*c8dee2aaSAndroid Build Coastguard Worker             return false;
264*c8dee2aaSAndroid Build Coastguard Worker         }
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker         fCurrRow++;
267*c8dee2aaSAndroid Build Coastguard Worker         numRows--;
268*c8dee2aaSAndroid Build Coastguard Worker     }
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker     if (fCurrRow == fSrc.height() && !fFinishedEncoding) {
271*c8dee2aaSAndroid Build Coastguard Worker         fFinishedEncoding = true;
272*c8dee2aaSAndroid Build Coastguard Worker         return this->onFinishEncoding();
273*c8dee2aaSAndroid Build Coastguard Worker     }
274*c8dee2aaSAndroid Build Coastguard Worker 
275*c8dee2aaSAndroid Build Coastguard Worker     return true;
276*c8dee2aaSAndroid Build Coastguard Worker }
277