1/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#include "SkScaledBitmapSampler.h"
10#include "SkBitmap.h"
11#include "SkColorPriv.h"
12#include "SkDither.h"
13#include "SkTypes.h"
14
15// 8888
16
17static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
18                              const uint8_t* SK_RESTRICT src,
19                              int width, int deltaSrc, int, const SkPMColor[]) {
20    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
21    for (int x = 0; x < width; x++) {
22        dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]);
23        src += deltaSrc;
24    }
25    return false;
26}
27
28static SkScaledBitmapSampler::RowProc
29get_gray_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
30    // Dither, unpremul, and skipZeroes have no effect
31    return Sample_Gray_D8888;
32}
33
34static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
35                              const uint8_t* SK_RESTRICT src,
36                              int width, int deltaSrc, int, const SkPMColor[]) {
37    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
38    for (int x = 0; x < width; x++) {
39        dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
40        src += deltaSrc;
41    }
42    return false;
43}
44
45static SkScaledBitmapSampler::RowProc
46get_RGBx_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
47    // Dither, unpremul, and skipZeroes have no effect
48    return Sample_RGBx_D8888;
49}
50
51static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
52                              const uint8_t* SK_RESTRICT src,
53                              int width, int deltaSrc, int, const SkPMColor[]) {
54    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
55    unsigned alphaMask = 0xFF;
56    for (int x = 0; x < width; x++) {
57        unsigned alpha = src[3];
58        dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
59        src += deltaSrc;
60        alphaMask &= alpha;
61    }
62    return alphaMask != 0xFF;
63}
64
65static bool Sample_RGBA_D8888_Unpremul(void* SK_RESTRICT dstRow,
66                                       const uint8_t* SK_RESTRICT src,
67                                       int width, int deltaSrc, int,
68                                       const SkPMColor[]) {
69    uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
70    unsigned alphaMask = 0xFF;
71    for (int x = 0; x < width; x++) {
72        unsigned alpha = src[3];
73        dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
74        src += deltaSrc;
75        alphaMask &= alpha;
76    }
77    return alphaMask != 0xFF;
78}
79
80static bool Sample_RGBA_D8888_SkipZ(void* SK_RESTRICT dstRow,
81                                    const uint8_t* SK_RESTRICT src,
82                                    int width, int deltaSrc, int,
83                                    const SkPMColor[]) {
84    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
85    unsigned alphaMask = 0xFF;
86    for (int x = 0; x < width; x++) {
87        unsigned alpha = src[3];
88        if (0 != alpha) {
89            dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
90        }
91        src += deltaSrc;
92        alphaMask &= alpha;
93    }
94    return alphaMask != 0xFF;
95}
96
97static SkScaledBitmapSampler::RowProc
98get_RGBA_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
99    // Dither has no effect.
100    if (!opts.fPremultiplyAlpha) {
101        // We could check each component for a zero, at the expense of extra checks.
102        // For now, just return unpremul.
103        return Sample_RGBA_D8888_Unpremul;
104    }
105    // Supply the versions that premultiply the colors
106    if (opts.fSkipZeros) {
107        return Sample_RGBA_D8888_SkipZ;
108    }
109    return Sample_RGBA_D8888;
110}
111
112// 565
113
114static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
115                             const uint8_t* SK_RESTRICT src,
116                             int width, int deltaSrc, int, const SkPMColor[]) {
117    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
118    for (int x = 0; x < width; x++) {
119        dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]);
120        src += deltaSrc;
121    }
122    return false;
123}
124
125static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
126                               const uint8_t* SK_RESTRICT src,
127                           int width, int deltaSrc, int y, const SkPMColor[]) {
128    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
129    DITHER_565_SCAN(y);
130    for (int x = 0; x < width; x++) {
131        dst[x] = SkDitherRGBTo565(src[0], src[0], src[0], DITHER_VALUE(x));
132        src += deltaSrc;
133    }
134    return false;
135}
136
137static SkScaledBitmapSampler::RowProc
138get_gray_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
139    // Unpremul and skip zeroes make no difference
140    if (opts.fDither) {
141        return Sample_Gray_D565_D;
142    }
143    return Sample_Gray_D565;
144}
145
146static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
147                             const uint8_t* SK_RESTRICT src,
148                             int width, int deltaSrc, int, const SkPMColor[]) {
149    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
150    for (int x = 0; x < width; x++) {
151        dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]);
152        src += deltaSrc;
153    }
154    return false;
155}
156
157static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
158                               const uint8_t* SK_RESTRICT src,
159                               int width, int deltaSrc, int y,
160                               const SkPMColor[]) {
161    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
162    DITHER_565_SCAN(y);
163    for (int x = 0; x < width; x++) {
164        dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x));
165        src += deltaSrc;
166    }
167    return false;
168}
169
170static SkScaledBitmapSampler::RowProc
171get_RGBx_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
172    // Unpremul and skip zeroes make no difference
173    if (opts.fDither) {
174        return Sample_RGBx_D565_D;
175    }
176    return Sample_RGBx_D565;
177}
178
179
180static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
181                             const uint8_t* SK_RESTRICT src,
182                             int width, int deltaSrc, int, const SkPMColor[]) {
183    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
184    uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src;
185    for (int x = 0; x < width; x++) {
186        dst[x] = castedSrc[0];
187        castedSrc += deltaSrc >> 1;
188    }
189    return false;
190}
191
192static SkScaledBitmapSampler::RowProc
193get_565_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
194    // Unpremul, dither, and skip zeroes have no effect
195    return Sample_D565_D565;
196}
197
198// 4444
199
200static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
201                              const uint8_t* SK_RESTRICT src,
202                              int width, int deltaSrc, int, const SkPMColor[]) {
203    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
204    for (int x = 0; x < width; x++) {
205        unsigned gray = src[0] >> 4;
206        dst[x] = SkPackARGB4444(0xF, gray, gray, gray);
207        src += deltaSrc;
208    }
209    return false;
210}
211
212static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
213                                const uint8_t* SK_RESTRICT src,
214                            int width, int deltaSrc, int y, const SkPMColor[]) {
215    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
216    DITHER_4444_SCAN(y);
217    for (int x = 0; x < width; x++) {
218        dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[0], src[0],
219                                      DITHER_VALUE(x));
220        src += deltaSrc;
221    }
222    return false;
223}
224
225static SkScaledBitmapSampler::RowProc
226get_gray_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
227    // Skip zeroes and unpremul make no difference
228    if (opts.fDither) {
229        return Sample_Gray_D4444_D;
230    }
231    return Sample_Gray_D4444;
232}
233
234static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
235                              const uint8_t* SK_RESTRICT src,
236                              int width, int deltaSrc, int, const SkPMColor[]) {
237    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
238    for (int x = 0; x < width; x++) {
239        dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4);
240        src += deltaSrc;
241    }
242    return false;
243}
244
245static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
246                                const uint8_t* SK_RESTRICT src,
247                            int width, int deltaSrc, int y, const SkPMColor[]) {
248    SkPMColor16* dst = (SkPMColor16*)dstRow;
249    DITHER_4444_SCAN(y);
250
251    for (int x = 0; x < width; x++) {
252        dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[1], src[2],
253                                      DITHER_VALUE(x));
254        src += deltaSrc;
255    }
256    return false;
257}
258
259static SkScaledBitmapSampler::RowProc
260get_RGBx_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
261    // Skip zeroes and unpremul make no difference
262    if (opts.fDither) {
263        return Sample_RGBx_D4444_D;
264    }
265    return Sample_RGBx_D4444;
266}
267
268static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
269                              const uint8_t* SK_RESTRICT src,
270                              int width, int deltaSrc, int, const SkPMColor[]) {
271    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
272    unsigned alphaMask = 0xFF;
273
274    for (int x = 0; x < width; x++) {
275        unsigned alpha = src[3];
276        SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
277        dst[x] = SkPixel32ToPixel4444(c);
278        src += deltaSrc;
279        alphaMask &= alpha;
280    }
281    return alphaMask != 0xFF;
282}
283
284static bool Sample_RGBA_D4444_SkipZ(void* SK_RESTRICT dstRow,
285                                    const uint8_t* SK_RESTRICT src,
286                                    int width, int deltaSrc, int,
287                                    const SkPMColor[]) {
288    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
289    unsigned alphaMask = 0xFF;
290
291    for (int x = 0; x < width; x++) {
292        unsigned alpha = src[3];
293        if (alpha != 0) {
294            SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
295            dst[x] = SkPixel32ToPixel4444(c);
296        }
297        src += deltaSrc;
298        alphaMask &= alpha;
299    }
300    return alphaMask != 0xFF;
301}
302
303
304static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
305                                const uint8_t* SK_RESTRICT src,
306                                int width, int deltaSrc, int y,
307                                const SkPMColor[]) {
308    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
309    unsigned alphaMask = 0xFF;
310    DITHER_4444_SCAN(y);
311
312    for (int x = 0; x < width; x++) {
313        unsigned alpha = src[3];
314        SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
315        dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
316        src += deltaSrc;
317        alphaMask &= alpha;
318    }
319    return alphaMask != 0xFF;
320}
321
322static bool Sample_RGBA_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
323                                      const uint8_t* SK_RESTRICT src,
324                                      int width, int deltaSrc, int y,
325                                      const SkPMColor[]) {
326    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
327    unsigned alphaMask = 0xFF;
328    DITHER_4444_SCAN(y);
329
330    for (int x = 0; x < width; x++) {
331        unsigned alpha = src[3];
332        if (alpha != 0) {
333            SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
334            dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
335        }
336        src += deltaSrc;
337        alphaMask &= alpha;
338    }
339    return alphaMask != 0xFF;
340}
341
342static SkScaledBitmapSampler::RowProc
343get_RGBA_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
344    if (!opts.fPremultiplyAlpha) {
345        // Unpremultiplied is not supported for 4444
346        return nullptr;
347    }
348    if (opts.fSkipZeros) {
349        if (opts.fDither) {
350            return Sample_RGBA_D4444_D_SkipZ;
351        }
352        return Sample_RGBA_D4444_SkipZ;
353    }
354    if (opts.fDither) {
355        return Sample_RGBA_D4444_D;
356    }
357    return Sample_RGBA_D4444;
358}
359
360// Index
361
362#define A32_MASK_IN_PLACE   (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
363
364static bool Sample_Index_D8888(void* SK_RESTRICT dstRow,
365                               const uint8_t* SK_RESTRICT src,
366                       int width, int deltaSrc, int, const SkPMColor ctable[]) {
367
368    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
369    SkPMColor cc = A32_MASK_IN_PLACE;
370    for (int x = 0; x < width; x++) {
371        SkPMColor c = ctable[*src];
372        cc &= c;
373        dst[x] = c;
374        src += deltaSrc;
375    }
376    return cc != A32_MASK_IN_PLACE;
377}
378
379static bool Sample_Index_D8888_SkipZ(void* SK_RESTRICT dstRow,
380                                     const uint8_t* SK_RESTRICT src,
381                                     int width, int deltaSrc, int,
382                                     const SkPMColor ctable[]) {
383
384    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
385    SkPMColor cc = A32_MASK_IN_PLACE;
386    for (int x = 0; x < width; x++) {
387        SkPMColor c = ctable[*src];
388        cc &= c;
389        if (c != 0) {
390            dst[x] = c;
391        }
392        src += deltaSrc;
393    }
394    return cc != A32_MASK_IN_PLACE;
395}
396
397static SkScaledBitmapSampler::RowProc
398get_index_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
399    // The caller is expected to have created the source colortable
400    // properly with respect to opts.fPremultiplyAlpha, so premul makes
401    // no difference here.
402    // Dither makes no difference
403    if (opts.fSkipZeros) {
404        return Sample_Index_D8888_SkipZ;
405    }
406    return Sample_Index_D8888;
407}
408
409static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
410                               const uint8_t* SK_RESTRICT src,
411                       int width, int deltaSrc, int, const SkPMColor ctable[]) {
412
413    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
414    for (int x = 0; x < width; x++) {
415        dst[x] = SkPixel32ToPixel16(ctable[*src]);
416        src += deltaSrc;
417    }
418    return false;
419}
420
421static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
422                                const uint8_t* SK_RESTRICT src, int width,
423                                int deltaSrc, int y, const SkPMColor ctable[]) {
424
425    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
426    DITHER_565_SCAN(y);
427
428    for (int x = 0; x < width; x++) {
429        SkPMColor c = ctable[*src];
430        dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c),
431                                  SkGetPackedB32(c), DITHER_VALUE(x));
432        src += deltaSrc;
433    }
434    return false;
435}
436
437static SkScaledBitmapSampler::RowProc
438get_index_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
439    // Unpremultiplied and skip zeroes make no difference
440    if (opts.fDither) {
441        return Sample_Index_D565_D;
442    }
443    return Sample_Index_D565;
444}
445
446static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
447                               const uint8_t* SK_RESTRICT src, int width,
448                               int deltaSrc, int y, const SkPMColor ctable[]) {
449
450    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
451    SkPMColor cc = A32_MASK_IN_PLACE;
452    for (int x = 0; x < width; x++) {
453        SkPMColor c = ctable[*src];
454        cc &= c;
455        dst[x] = SkPixel32ToPixel4444(c);
456        src += deltaSrc;
457    }
458    return cc != A32_MASK_IN_PLACE;
459}
460
461static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
462                                 const uint8_t* SK_RESTRICT src, int width,
463                                int deltaSrc, int y, const SkPMColor ctable[]) {
464
465    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
466    SkPMColor cc = A32_MASK_IN_PLACE;
467    DITHER_4444_SCAN(y);
468
469    for (int x = 0; x < width; x++) {
470        SkPMColor c = ctable[*src];
471        cc &= c;
472        dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
473        src += deltaSrc;
474    }
475    return cc != A32_MASK_IN_PLACE;
476}
477
478static bool Sample_Index_D4444_SkipZ(void* SK_RESTRICT dstRow,
479                                     const uint8_t* SK_RESTRICT src, int width,
480                                     int deltaSrc, int y, const SkPMColor ctable[]) {
481
482    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
483    SkPMColor cc = A32_MASK_IN_PLACE;
484    for (int x = 0; x < width; x++) {
485        SkPMColor c = ctable[*src];
486        cc &= c;
487        if (c != 0) {
488            dst[x] = SkPixel32ToPixel4444(c);
489        }
490        src += deltaSrc;
491    }
492    return cc != A32_MASK_IN_PLACE;
493}
494
495static bool Sample_Index_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
496                                       const uint8_t* SK_RESTRICT src, int width,
497                                       int deltaSrc, int y, const SkPMColor ctable[]) {
498
499    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
500    SkPMColor cc = A32_MASK_IN_PLACE;
501    DITHER_4444_SCAN(y);
502
503    for (int x = 0; x < width; x++) {
504        SkPMColor c = ctable[*src];
505        cc &= c;
506        if (c != 0) {
507            dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
508        }
509        src += deltaSrc;
510    }
511    return cc != A32_MASK_IN_PLACE;
512}
513
514static SkScaledBitmapSampler::RowProc
515get_index_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
516    // Unpremul not allowed
517    if (!opts.fPremultiplyAlpha) {
518        return nullptr;
519    }
520    if (opts.fSkipZeros) {
521        if (opts.fDither) {
522            return Sample_Index_D4444_D_SkipZ;
523        }
524        return Sample_Index_D4444_SkipZ;
525    }
526    if (opts.fDither) {
527        return Sample_Index_D4444_D;
528    }
529    return Sample_Index_D4444;
530}
531
532static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
533                            const uint8_t* SK_RESTRICT src,
534                            int width, int deltaSrc, int, const SkPMColor[]) {
535    if (1 == deltaSrc) {
536        memcpy(dstRow, src, width);
537    } else {
538        uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow;
539        for (int x = 0; x < width; x++) {
540            dst[x] = src[0];
541            src += deltaSrc;
542        }
543    }
544    return false;
545}
546
547static SkScaledBitmapSampler::RowProc
548get_index_to_index_proc(const SkScaledBitmapSampler::Options& opts) {
549    // Unpremul not allowed
550    if (!opts.fPremultiplyAlpha) {
551        return nullptr;
552    }
553    // Ignore dither and skip zeroes
554    return Sample_Index_DI;
555}
556
557// A8
558static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow,
559                            const uint8_t* SK_RESTRICT src,
560                            int width, int deltaSrc, int,
561                            const SkPMColor[]) {
562    // Sampling Gray to A8 uses the same function as Index to Index8,
563    // except we assume that there is alpha for speed, since an A8
564    // bitmap with no alpha is not interesting.
565    (void) Sample_Index_DI(dstRow, src, width, deltaSrc, /* y unused */ 0,
566                           /* ctable unused */ nullptr);
567    return true;
568}
569
570static SkScaledBitmapSampler::RowProc
571get_gray_to_A8_proc(const SkScaledBitmapSampler::Options& opts) {
572    if (!opts.fPremultiplyAlpha) {
573        return nullptr;
574    }
575    // Ignore skip and dither.
576    return Sample_Gray_DA8;
577}
578
579typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&);
580///////////////////////////////////////////////////////////////////////////////
581
582#include "SkScaledBitmapSampler.h"
583
584SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
585                                             int sampleSize) {
586    fCTable = nullptr;
587    fDstRow = nullptr;
588    fRowProc = nullptr;
589
590    if (width <= 0 || height <= 0) {
591        sk_throw();
592    }
593
594    SkDEBUGCODE(fSampleMode = kUninitialized_SampleMode);
595
596    if (sampleSize <= 1) {
597        fScaledWidth = width;
598        fScaledHeight = height;
599        fX0 = fY0 = 0;
600        fDX = fDY = 1;
601        return;
602    }
603
604    int dx = SkMin32(sampleSize, width);
605    int dy = SkMin32(sampleSize, height);
606
607    fScaledWidth = width / dx;
608    fScaledHeight = height / dy;
609
610    SkASSERT(fScaledWidth > 0);
611    SkASSERT(fScaledHeight > 0);
612
613    fX0 = dx >> 1;
614    fY0 = dy >> 1;
615
616    SkASSERT(fX0 >= 0 && fX0 < width);
617    SkASSERT(fY0 >= 0 && fY0 < height);
618
619    fDX = dx;
620    fDY = dy;
621
622    SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width);
623    SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
624}
625
626bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
627                                  const Options& opts,
628                                  const SkPMColor ctable[]) {
629    static const RowProcChooser gProcChoosers[] = {
630        get_gray_to_8888_proc,
631        get_RGBx_to_8888_proc,
632        get_RGBA_to_8888_proc,
633        get_index_to_8888_proc,
634        nullptr, // 565 to 8888
635
636        get_gray_to_565_proc,
637        get_RGBx_to_565_proc,
638        get_RGBx_to_565_proc, // The source alpha will be ignored.
639        get_index_to_565_proc,
640        get_565_to_565_proc,
641
642        get_gray_to_4444_proc,
643        get_RGBx_to_4444_proc,
644        get_RGBA_to_4444_proc,
645        get_index_to_4444_proc,
646        nullptr, // 565 to 4444
647
648        nullptr, // gray to index
649        nullptr, // rgbx to index
650        nullptr, // rgba to index
651        get_index_to_index_proc,
652        nullptr, // 565 to index
653
654        get_gray_to_A8_proc,
655        nullptr, // rgbx to a8
656        nullptr, // rgba to a8
657        nullptr, // index to a8
658        nullptr, // 565 to a8
659    };
660
661    // The jump between dst configs in the table
662    static const int gProcDstConfigSpan = 5;
663    static_assert(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan,
664                  "gProcs_has_the_wrong_number_of_entries");
665
666    fCTable = ctable;
667
668    int index = 0;
669    switch (sc) {
670        case SkScaledBitmapSampler::kGray:
671            fSrcPixelSize = 1;
672            index += 0;
673            break;
674        case SkScaledBitmapSampler::kRGB:
675            fSrcPixelSize = 3;
676            index += 1;
677            break;
678        case SkScaledBitmapSampler::kRGBX:
679            fSrcPixelSize = 4;
680            index += 1;
681            break;
682        case SkScaledBitmapSampler::kRGBA:
683            fSrcPixelSize = 4;
684            index += 2;
685            break;
686        case SkScaledBitmapSampler::kIndex:
687            fSrcPixelSize = 1;
688            index += 3;
689            break;
690        case SkScaledBitmapSampler::kRGB_565:
691            fSrcPixelSize = 2;
692            index += 4;
693            break;
694        default:
695            return false;
696    }
697
698    switch (dst->colorType()) {
699        case kN32_SkColorType:
700            index += 0 * gProcDstConfigSpan;
701            break;
702        case kRGB_565_SkColorType:
703            index += 1 * gProcDstConfigSpan;
704            break;
705        case kARGB_4444_SkColorType:
706            index += 2 * gProcDstConfigSpan;
707            break;
708        case kIndex_8_SkColorType:
709            index += 3 * gProcDstConfigSpan;
710            break;
711        case kAlpha_8_SkColorType:
712            index += 4 * gProcDstConfigSpan;
713            break;
714        default:
715            return false;
716    }
717
718    RowProcChooser chooser = gProcChoosers[index];
719    if (nullptr == chooser) {
720        fRowProc = nullptr;
721    } else {
722        fRowProc = chooser(opts);
723    }
724    fDstRow = (char*)dst->getPixels();
725    fDstRowBytes = dst->rowBytes();
726    fCurrY = 0;
727    return fRowProc != nullptr;
728}
729
730bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
731                                  const SkImageDecoder& decoder,
732                                  const SkPMColor ctable[]) {
733    return this->begin(dst, sc, Options(decoder), ctable);
734}
735
736bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
737    SkASSERT(kInterlaced_SampleMode != fSampleMode);
738    SkDEBUGCODE(fSampleMode = kConsecutive_SampleMode);
739    SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
740
741    bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
742                             fDX * fSrcPixelSize, fCurrY, fCTable);
743    fDstRow += fDstRowBytes;
744    fCurrY += 1;
745    return hadAlpha;
746}
747
748bool SkScaledBitmapSampler::sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY) {
749    SkASSERT(kConsecutive_SampleMode != fSampleMode);
750    SkDEBUGCODE(fSampleMode = kInterlaced_SampleMode);
751    // Any line that should be a part of the destination can be created by the formula:
752    // fY0 + (some multiplier) * fDY
753    // so if srcY - fY0 is not an integer multiple of fDY that srcY will be skipped.
754    const int srcYMinusY0 = srcY - fY0;
755    if (srcYMinusY0 % fDY != 0) {
756        // This line is not part of the output, so return false for alpha, since we have
757        // not added an alpha to the output.
758        return false;
759    }
760    // Unlike in next(), where the data is used sequentially, this function skips around,
761    // so fDstRow and fCurrY are never updated. fDstRow must always be the starting point
762    // of the destination bitmap's pixels, which is used to calculate the destination row
763    // each time this function is called.
764    const int dstY = srcYMinusY0 / fDY;
765    if (dstY >= fScaledHeight) {
766        return false;
767    }
768    char* dstRow = fDstRow + dstY * fDstRowBytes;
769    return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
770                    fDX * fSrcPixelSize, dstY, fCTable);
771}
772
773#ifdef SK_DEBUG
774// The following code is for a test to ensure that changing the method to get the right row proc
775// did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp
776
777// friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc.
778class RowProcTester {
779public:
780    static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) {
781        return sampler.fRowProc;
782    }
783};
784
785
786// Table showing the expected RowProc for each combination of inputs.
787// Table formated as follows:
788// Each group of 5 consecutive rows represents sampling from a single
789// SkScaledBitmapSampler::SrcConfig.
790// Within each set, each row represents a different destination SkBitmap::Config
791// Each column represents a different combination of dither and unpremul.
792// D = dither   ~D = no dither
793// U = unpremul ~U = no unpremul
794//  ~D~U                D~U                     ~DU                         DU
795SkScaledBitmapSampler::RowProc gTestProcs[] = {
796    // Gray
797    Sample_Gray_DA8,    Sample_Gray_DA8,        nullptr,                       nullptr,                       // to A8
798    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to Index8
799    Sample_Gray_D565,   Sample_Gray_D565_D,     Sample_Gray_D565,           Sample_Gray_D565_D,         // to 565
800    Sample_Gray_D4444,  Sample_Gray_D4444_D,    Sample_Gray_D4444,          Sample_Gray_D4444_D,        // to 4444
801    Sample_Gray_D8888,  Sample_Gray_D8888,      Sample_Gray_D8888,          Sample_Gray_D8888,          // to 8888
802    // Index
803    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to A8
804    Sample_Index_DI,    Sample_Index_DI,        nullptr,                       nullptr,                       // to Index8
805    Sample_Index_D565,  Sample_Index_D565_D,    Sample_Index_D565,          Sample_Index_D565_D,        // to 565
806    Sample_Index_D4444, Sample_Index_D4444_D,   nullptr,                       nullptr,                       // to 4444
807    Sample_Index_D8888, Sample_Index_D8888,     Sample_Index_D8888,         Sample_Index_D8888,         // to 8888
808    // RGB
809    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to A8
810    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to Index8
811    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
812    Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
813    Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
814    // RGBx is the same as RGB
815    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to A8
816    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to Index8
817    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
818    Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
819    Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
820    // RGBA
821    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to A8
822    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to Index8
823    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
824    Sample_RGBA_D4444,  Sample_RGBA_D4444_D,    nullptr,                       nullptr,                       // to 4444
825    Sample_RGBA_D8888,  Sample_RGBA_D8888,      Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888
826    // RGB_565
827    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to A8
828    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to Index8
829    Sample_D565_D565,   Sample_D565_D565,       Sample_D565_D565,           Sample_D565_D565,           // to 565
830    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to 4444
831    nullptr,               nullptr,                   nullptr,                       nullptr,                       // to 8888
832};
833
834// Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields.
835class DummyDecoder : public SkImageDecoder {
836public:
837    DummyDecoder() {}
838protected:
839    Result onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) override {
840        return kFailure;
841    }
842};
843
844void test_row_proc_choice();
845void test_row_proc_choice() {
846    const SkColorType colorTypes[] = {
847        kAlpha_8_SkColorType, kIndex_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType,
848        kN32_SkColorType
849    };
850
851    SkBitmap dummyBitmap;
852    DummyDecoder dummyDecoder;
853    size_t procCounter = 0;
854    for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) {
855        for (size_t c = 0; c < SK_ARRAY_COUNT(colorTypes); ++c) {
856            for (int unpremul = 0; unpremul <= 1; ++unpremul) {
857                for (int dither = 0; dither <= 1; ++dither) {
858                    // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to
859                    // be considered valid.
860                    SkScaledBitmapSampler sampler(10, 10, 1);
861                    dummyBitmap.setInfo(SkImageInfo::Make(10, 10,
862                                                          colorTypes[c], kPremul_SkAlphaType));
863                    dummyDecoder.setDitherImage(SkToBool(dither));
864                    dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul));
865                    sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc,
866                                  dummyDecoder);
867                    SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter];
868                    SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler);
869                    SkASSERT(expected == actual);
870                    procCounter++;
871                }
872            }
873        }
874    }
875    SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter);
876}
877#endif // SK_DEBUG
878