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 NULL;
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    if (!opts.fPremultiplyAlpha) {
400        // Unpremultiplied is not supported for an index source.
401        return NULL;
402    }
403    // Dither makes no difference
404    if (opts.fSkipZeros) {
405        return Sample_Index_D8888_SkipZ;
406    }
407    return Sample_Index_D8888;
408}
409
410static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
411                               const uint8_t* SK_RESTRICT src,
412                       int width, int deltaSrc, int, const SkPMColor ctable[]) {
413
414    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
415    for (int x = 0; x < width; x++) {
416        dst[x] = SkPixel32ToPixel16(ctable[*src]);
417        src += deltaSrc;
418    }
419    return false;
420}
421
422static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
423                                const uint8_t* SK_RESTRICT src, int width,
424                                int deltaSrc, int y, const SkPMColor ctable[]) {
425
426    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
427    DITHER_565_SCAN(y);
428
429    for (int x = 0; x < width; x++) {
430        SkPMColor c = ctable[*src];
431        dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c),
432                                  SkGetPackedB32(c), DITHER_VALUE(x));
433        src += deltaSrc;
434    }
435    return false;
436}
437
438static SkScaledBitmapSampler::RowProc
439get_index_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
440    // Unpremultiplied and skip zeroes make no difference
441    if (opts.fDither) {
442        return Sample_Index_D565_D;
443    }
444    return Sample_Index_D565;
445}
446
447static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
448                               const uint8_t* SK_RESTRICT src, int width,
449                               int deltaSrc, int y, const SkPMColor ctable[]) {
450
451    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
452    SkPMColor cc = A32_MASK_IN_PLACE;
453    for (int x = 0; x < width; x++) {
454        SkPMColor c = ctable[*src];
455        cc &= c;
456        dst[x] = SkPixel32ToPixel4444(c);
457        src += deltaSrc;
458    }
459    return cc != A32_MASK_IN_PLACE;
460}
461
462static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
463                                 const uint8_t* SK_RESTRICT src, int width,
464                                int deltaSrc, int y, const SkPMColor ctable[]) {
465
466    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
467    SkPMColor cc = A32_MASK_IN_PLACE;
468    DITHER_4444_SCAN(y);
469
470    for (int x = 0; x < width; x++) {
471        SkPMColor c = ctable[*src];
472        cc &= c;
473        dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
474        src += deltaSrc;
475    }
476    return cc != A32_MASK_IN_PLACE;
477}
478
479static bool Sample_Index_D4444_SkipZ(void* SK_RESTRICT dstRow,
480                                     const uint8_t* SK_RESTRICT src, int width,
481                                     int deltaSrc, int y, const SkPMColor ctable[]) {
482
483    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
484    SkPMColor cc = A32_MASK_IN_PLACE;
485    for (int x = 0; x < width; x++) {
486        SkPMColor c = ctable[*src];
487        cc &= c;
488        if (c != 0) {
489            dst[x] = SkPixel32ToPixel4444(c);
490        }
491        src += deltaSrc;
492    }
493    return cc != A32_MASK_IN_PLACE;
494}
495
496static bool Sample_Index_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
497                                       const uint8_t* SK_RESTRICT src, int width,
498                                       int deltaSrc, int y, const SkPMColor ctable[]) {
499
500    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
501    SkPMColor cc = A32_MASK_IN_PLACE;
502    DITHER_4444_SCAN(y);
503
504    for (int x = 0; x < width; x++) {
505        SkPMColor c = ctable[*src];
506        cc &= c;
507        if (c != 0) {
508            dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
509        }
510        src += deltaSrc;
511    }
512    return cc != A32_MASK_IN_PLACE;
513}
514
515static SkScaledBitmapSampler::RowProc
516get_index_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
517    // Unpremul not allowed
518    if (!opts.fPremultiplyAlpha) {
519        return NULL;
520    }
521    if (opts.fSkipZeros) {
522        if (opts.fDither) {
523            return Sample_Index_D4444_D_SkipZ;
524        }
525        return Sample_Index_D4444_SkipZ;
526    }
527    if (opts.fDither) {
528        return Sample_Index_D4444_D;
529    }
530    return Sample_Index_D4444;
531}
532
533static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
534                            const uint8_t* SK_RESTRICT src,
535                            int width, int deltaSrc, int, const SkPMColor[]) {
536    if (1 == deltaSrc) {
537        memcpy(dstRow, src, width);
538    } else {
539        uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow;
540        for (int x = 0; x < width; x++) {
541            dst[x] = src[0];
542            src += deltaSrc;
543        }
544    }
545    return false;
546}
547
548static SkScaledBitmapSampler::RowProc
549get_index_to_index_proc(const SkScaledBitmapSampler::Options& opts) {
550    // Unpremul not allowed
551    if (!opts.fPremultiplyAlpha) {
552        return NULL;
553    }
554    // Ignore dither and skip zeroes
555    return Sample_Index_DI;
556}
557
558// A8
559static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow,
560                            const uint8_t* SK_RESTRICT src,
561                            int width, int deltaSrc, int,
562                            const SkPMColor[]) {
563    // Sampling Gray to A8 uses the same function as Index to Index8,
564    // except we assume that there is alpha for speed, since an A8
565    // bitmap with no alpha is not interesting.
566    (void) Sample_Index_DI(dstRow, src, width, deltaSrc, /* y unused */ 0,
567                           /* ctable unused */ NULL);
568    return true;
569}
570
571static SkScaledBitmapSampler::RowProc
572get_gray_to_A8_proc(const SkScaledBitmapSampler::Options& opts) {
573    if (!opts.fPremultiplyAlpha) {
574        return NULL;
575    }
576    // Ignore skip and dither.
577    return Sample_Gray_DA8;
578}
579
580typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&);
581///////////////////////////////////////////////////////////////////////////////
582
583#include "SkScaledBitmapSampler.h"
584
585SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
586                                             int sampleSize) {
587    fCTable = NULL;
588    fDstRow = NULL;
589    fRowProc = NULL;
590
591    if (width <= 0 || height <= 0) {
592        sk_throw();
593    }
594
595    SkDEBUGCODE(fSampleMode = kUninitialized_SampleMode);
596
597    if (sampleSize <= 1) {
598        fScaledWidth = width;
599        fScaledHeight = height;
600        fX0 = fY0 = 0;
601        fDX = fDY = 1;
602        return;
603    }
604
605    int dx = SkMin32(sampleSize, width);
606    int dy = SkMin32(sampleSize, height);
607
608    fScaledWidth = width / dx;
609    fScaledHeight = height / dy;
610
611    SkASSERT(fScaledWidth > 0);
612    SkASSERT(fScaledHeight > 0);
613
614    fX0 = dx >> 1;
615    fY0 = dy >> 1;
616
617    SkASSERT(fX0 >= 0 && fX0 < width);
618    SkASSERT(fY0 >= 0 && fY0 < height);
619
620    fDX = dx;
621    fDY = dy;
622
623    SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width);
624    SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
625}
626
627bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
628                                  const Options& opts,
629                                  const SkPMColor ctable[]) {
630    static const RowProcChooser gProcChoosers[] = {
631        get_gray_to_8888_proc,
632        get_RGBx_to_8888_proc,
633        get_RGBA_to_8888_proc,
634        get_index_to_8888_proc,
635        NULL, // 565 to 8888
636
637        get_gray_to_565_proc,
638        get_RGBx_to_565_proc,
639        get_RGBx_to_565_proc, // The source alpha will be ignored.
640        get_index_to_565_proc,
641        get_565_to_565_proc,
642
643        get_gray_to_4444_proc,
644        get_RGBx_to_4444_proc,
645        get_RGBA_to_4444_proc,
646        get_index_to_4444_proc,
647        NULL, // 565 to 4444
648
649        NULL, // gray to index
650        NULL, // rgbx to index
651        NULL, // rgba to index
652        get_index_to_index_proc,
653        NULL, // 565 to index
654
655        get_gray_to_A8_proc,
656        NULL, // rgbx to a8
657        NULL, // rgba to a8
658        NULL, // index to a8
659        NULL, // 565 to a8
660    };
661
662    // The jump between dst configs in the table
663    static const int gProcDstConfigSpan = 5;
664    SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan,
665                      gProcs_has_the_wrong_number_of_entries);
666
667    fCTable = ctable;
668
669    int index = 0;
670    switch (sc) {
671        case SkScaledBitmapSampler::kGray:
672            fSrcPixelSize = 1;
673            index += 0;
674            break;
675        case SkScaledBitmapSampler::kRGB:
676            fSrcPixelSize = 3;
677            index += 1;
678            break;
679        case SkScaledBitmapSampler::kRGBX:
680            fSrcPixelSize = 4;
681            index += 1;
682            break;
683        case SkScaledBitmapSampler::kRGBA:
684            fSrcPixelSize = 4;
685            index += 2;
686            break;
687        case SkScaledBitmapSampler::kIndex:
688            fSrcPixelSize = 1;
689            index += 3;
690            break;
691        case SkScaledBitmapSampler::kRGB_565:
692            fSrcPixelSize = 2;
693            index += 4;
694            break;
695        default:
696            return false;
697    }
698
699    switch (dst->colorType()) {
700        case kN32_SkColorType:
701            index += 0 * gProcDstConfigSpan;
702            break;
703        case kRGB_565_SkColorType:
704            index += 1 * gProcDstConfigSpan;
705            break;
706        case kARGB_4444_SkColorType:
707            index += 2 * gProcDstConfigSpan;
708            break;
709        case kIndex_8_SkColorType:
710            index += 3 * gProcDstConfigSpan;
711            break;
712        case kAlpha_8_SkColorType:
713            index += 4 * gProcDstConfigSpan;
714            break;
715        default:
716            return false;
717    }
718
719    RowProcChooser chooser = gProcChoosers[index];
720    if (NULL == chooser) {
721        fRowProc = NULL;
722    } else {
723        fRowProc = chooser(opts);
724    }
725    fDstRow = (char*)dst->getPixels();
726    fDstRowBytes = dst->rowBytes();
727    fCurrY = 0;
728    return fRowProc != NULL;
729}
730
731bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
732                                  const SkImageDecoder& decoder,
733                                  const SkPMColor ctable[]) {
734    return this->begin(dst, sc, Options(decoder), ctable);
735}
736
737bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
738    SkASSERT(kInterlaced_SampleMode != fSampleMode);
739    SkDEBUGCODE(fSampleMode = kConsecutive_SampleMode);
740    SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
741
742    bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
743                             fDX * fSrcPixelSize, fCurrY, fCTable);
744    fDstRow += fDstRowBytes;
745    fCurrY += 1;
746    return hadAlpha;
747}
748
749bool SkScaledBitmapSampler::sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY) {
750    SkASSERT(kConsecutive_SampleMode != fSampleMode);
751    SkDEBUGCODE(fSampleMode = kInterlaced_SampleMode);
752    // Any line that should be a part of the destination can be created by the formula:
753    // fY0 + (some multiplier) * fDY
754    // so if srcY - fY0 is not an integer multiple of fDY that srcY will be skipped.
755    const int srcYMinusY0 = srcY - fY0;
756    if (srcYMinusY0 % fDY != 0) {
757        // This line is not part of the output, so return false for alpha, since we have
758        // not added an alpha to the output.
759        return false;
760    }
761    // Unlike in next(), where the data is used sequentially, this function skips around,
762    // so fDstRow and fCurrY are never updated. fDstRow must always be the starting point
763    // of the destination bitmap's pixels, which is used to calculate the destination row
764    // each time this function is called.
765    const int dstY = srcYMinusY0 / fDY;
766    SkASSERT(dstY < fScaledHeight);
767    char* dstRow = fDstRow + dstY * fDstRowBytes;
768    return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
769                    fDX * fSrcPixelSize, dstY, fCTable);
770}
771
772#ifdef SK_DEBUG
773// The following code is for a test to ensure that changing the method to get the right row proc
774// did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp
775
776// friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc.
777class RowProcTester {
778public:
779    static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) {
780        return sampler.fRowProc;
781    }
782};
783
784
785// Table showing the expected RowProc for each combination of inputs.
786// Table formated as follows:
787// Each group of 5 consecutive rows represents sampling from a single
788// SkScaledBitmapSampler::SrcConfig.
789// Within each set, each row represents a different destination SkBitmap::Config
790// Each column represents a different combination of dither and unpremul.
791// D = dither   ~D = no dither
792// U = unpremul ~U = no unpremul
793//  ~D~U                D~U                     ~DU                         DU
794SkScaledBitmapSampler::RowProc gTestProcs[] = {
795    // Gray
796    Sample_Gray_DA8,    Sample_Gray_DA8,        NULL,                       NULL,                       // to A8
797    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
798    Sample_Gray_D565,   Sample_Gray_D565_D,     Sample_Gray_D565,           Sample_Gray_D565_D,         // to 565
799    Sample_Gray_D4444,  Sample_Gray_D4444_D,    Sample_Gray_D4444,          Sample_Gray_D4444_D,        // to 4444
800    Sample_Gray_D8888,  Sample_Gray_D8888,      Sample_Gray_D8888,          Sample_Gray_D8888,          // to 8888
801    // Index
802    NULL,               NULL,                   NULL,                       NULL,                       // to A8
803    Sample_Index_DI,    Sample_Index_DI,        NULL,                       NULL,                       // to Index8
804    Sample_Index_D565,  Sample_Index_D565_D,    Sample_Index_D565,          Sample_Index_D565_D,        // to 565
805    Sample_Index_D4444, Sample_Index_D4444_D,   NULL,                       NULL,                       // to 4444
806    Sample_Index_D8888, Sample_Index_D8888,     NULL,                       NULL,                       // to 8888
807    // RGB
808    NULL,               NULL,                   NULL,                       NULL,                       // to A8
809    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
810    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
811    Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
812    Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
813    // RGBx is the same as RGB
814    NULL,               NULL,                   NULL,                       NULL,                       // to A8
815    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
816    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
817    Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
818    Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
819    // RGBA
820    NULL,               NULL,                   NULL,                       NULL,                       // to A8
821    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
822    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
823    Sample_RGBA_D4444,  Sample_RGBA_D4444_D,    NULL,                       NULL,                       // to 4444
824    Sample_RGBA_D8888,  Sample_RGBA_D8888,      Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888
825    // RGB_565
826    NULL,               NULL,                   NULL,                       NULL,                       // to A8
827    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
828    Sample_D565_D565,   Sample_D565_D565,       Sample_D565_D565,           Sample_D565_D565,           // to 565
829    NULL,               NULL,                   NULL,                       NULL,                       // to 4444
830    NULL,               NULL,                   NULL,                       NULL,                       // to 8888
831};
832
833// Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields.
834class DummyDecoder : public SkImageDecoder {
835public:
836    DummyDecoder() {}
837protected:
838    virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE {
839        return false;
840    }
841};
842
843void test_row_proc_choice();
844void test_row_proc_choice() {
845    const SkColorType colorTypes[] = {
846        kAlpha_8_SkColorType, kIndex_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType,
847        kN32_SkColorType
848    };
849
850    SkBitmap dummyBitmap;
851    DummyDecoder dummyDecoder;
852    size_t procCounter = 0;
853    for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) {
854        for (size_t c = 0; c < SK_ARRAY_COUNT(colorTypes); ++c) {
855            for (int unpremul = 0; unpremul <= 1; ++unpremul) {
856                for (int dither = 0; dither <= 1; ++dither) {
857                    // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to
858                    // be considered valid.
859                    SkScaledBitmapSampler sampler(10, 10, 1);
860                    dummyBitmap.setInfo(SkImageInfo::Make(10, 10,
861                                                          colorTypes[c], kPremul_SkAlphaType));
862                    dummyDecoder.setDitherImage(SkToBool(dither));
863                    dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul));
864                    sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc,
865                                  dummyDecoder);
866                    SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter];
867                    SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler);
868                    SkASSERT(expected == actual);
869                    procCounter++;
870                }
871            }
872        }
873    }
874    SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter);
875}
876#endif // SK_DEBUG
877