Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / images / SkScaledBitmapSampler.cpp
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
17 static 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
28 static SkScaledBitmapSampler::RowProc
29 get_gray_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
30     // Dither, unpremul, and skipZeroes have no effect
31     return Sample_Gray_D8888;
32 }
33
34 static 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
45 static SkScaledBitmapSampler::RowProc
46 get_RGBx_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
47     // Dither, unpremul, and skipZeroes have no effect
48     return Sample_RGBx_D8888;
49 }
50
51 static 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
65 static 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
80 static 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
97 static SkScaledBitmapSampler::RowProc
98 get_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
114 static 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
125 static 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
137 static SkScaledBitmapSampler::RowProc
138 get_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
146 static 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
157 static 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
170 static SkScaledBitmapSampler::RowProc
171 get_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
180 static 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
192 static SkScaledBitmapSampler::RowProc
193 get_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
200 static 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
212 static 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
225 static SkScaledBitmapSampler::RowProc
226 get_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
234 static 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
245 static 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
259 static SkScaledBitmapSampler::RowProc
260 get_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
268 static 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
284 static 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
304 static 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
322 static 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
342 static SkScaledBitmapSampler::RowProc
343 get_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
364 static 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
379 static 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
397 static SkScaledBitmapSampler::RowProc
398 get_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
409 static 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
421 static 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
437 static SkScaledBitmapSampler::RowProc
438 get_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
446 static 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
461 static 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
478 static 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
495 static 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
514 static SkScaledBitmapSampler::RowProc
515 get_index_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
516     // Unpremul not allowed
517     if (!opts.fPremultiplyAlpha) {
518         return NULL;
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
532 static 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
547 static SkScaledBitmapSampler::RowProc
548 get_index_to_index_proc(const SkScaledBitmapSampler::Options& opts) {
549     // Unpremul not allowed
550     if (!opts.fPremultiplyAlpha) {
551         return NULL;
552     }
553     // Ignore dither and skip zeroes
554     return Sample_Index_DI;
555 }
556
557 // A8
558 static 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 */ NULL);
567     return true;
568 }
569
570 static SkScaledBitmapSampler::RowProc
571 get_gray_to_A8_proc(const SkScaledBitmapSampler::Options& opts) {
572     if (!opts.fPremultiplyAlpha) {
573         return NULL;
574     }
575     // Ignore skip and dither.
576     return Sample_Gray_DA8;
577 }
578
579 typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&);
580 ///////////////////////////////////////////////////////////////////////////////
581
582 #include "SkScaledBitmapSampler.h"
583
584 SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
585                                              int sampleSize) {
586     fCTable = NULL;
587     fDstRow = NULL;
588     fRowProc = NULL;
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
626 bool 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         NULL, // 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         NULL, // 565 to 4444
647
648         NULL, // gray to index
649         NULL, // rgbx to index
650         NULL, // rgba to index
651         get_index_to_index_proc,
652         NULL, // 565 to index
653
654         get_gray_to_A8_proc,
655         NULL, // rgbx to a8
656         NULL, // rgba to a8
657         NULL, // index to a8
658         NULL, // 565 to a8
659     };
660
661     // The jump between dst configs in the table
662     static const int gProcDstConfigSpan = 5;
663     SK_COMPILE_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 (NULL == chooser) {
720         fRowProc = NULL;
721     } else {
722         fRowProc = chooser(opts);
723     }
724     fDstRow = (char*)dst->getPixels();
725     fDstRowBytes = dst->rowBytes();
726     fCurrY = 0;
727     return fRowProc != NULL;
728 }
729
730 bool 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
736 bool 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
748 bool 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     SkASSERT(dstY < fScaledHeight);
766     char* dstRow = fDstRow + dstY * fDstRowBytes;
767     return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
768                     fDX * fSrcPixelSize, dstY, fCTable);
769 }
770
771 #ifdef SK_DEBUG
772 // The following code is for a test to ensure that changing the method to get the right row proc
773 // did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp
774
775 // friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc.
776 class RowProcTester {
777 public:
778     static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) {
779         return sampler.fRowProc;
780     }
781 };
782
783
784 // Table showing the expected RowProc for each combination of inputs.
785 // Table formated as follows:
786 // Each group of 5 consecutive rows represents sampling from a single
787 // SkScaledBitmapSampler::SrcConfig.
788 // Within each set, each row represents a different destination SkBitmap::Config
789 // Each column represents a different combination of dither and unpremul.
790 // D = dither   ~D = no dither
791 // U = unpremul ~U = no unpremul
792 //  ~D~U                D~U                     ~DU                         DU
793 SkScaledBitmapSampler::RowProc gTestProcs[] = {
794     // Gray
795     Sample_Gray_DA8,    Sample_Gray_DA8,        NULL,                       NULL,                       // to A8
796     NULL,               NULL,                   NULL,                       NULL,                       // to Index8
797     Sample_Gray_D565,   Sample_Gray_D565_D,     Sample_Gray_D565,           Sample_Gray_D565_D,         // to 565
798     Sample_Gray_D4444,  Sample_Gray_D4444_D,    Sample_Gray_D4444,          Sample_Gray_D4444_D,        // to 4444
799     Sample_Gray_D8888,  Sample_Gray_D8888,      Sample_Gray_D8888,          Sample_Gray_D8888,          // to 8888
800     // Index
801     NULL,               NULL,                   NULL,                       NULL,                       // to A8
802     Sample_Index_DI,    Sample_Index_DI,        NULL,                       NULL,                       // to Index8
803     Sample_Index_D565,  Sample_Index_D565_D,    Sample_Index_D565,          Sample_Index_D565_D,        // to 565
804     Sample_Index_D4444, Sample_Index_D4444_D,   NULL,                       NULL,                       // to 4444
805     Sample_Index_D8888, Sample_Index_D8888,     Sample_Index_D8888,         Sample_Index_D8888,         // to 8888
806     // RGB
807     NULL,               NULL,                   NULL,                       NULL,                       // to A8
808     NULL,               NULL,                   NULL,                       NULL,                       // to Index8
809     Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
810     Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
811     Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
812     // RGBx is the same as RGB
813     NULL,               NULL,                   NULL,                       NULL,                       // to A8
814     NULL,               NULL,                   NULL,                       NULL,                       // to Index8
815     Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
816     Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
817     Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
818     // RGBA
819     NULL,               NULL,                   NULL,                       NULL,                       // to A8
820     NULL,               NULL,                   NULL,                       NULL,                       // to Index8
821     Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
822     Sample_RGBA_D4444,  Sample_RGBA_D4444_D,    NULL,                       NULL,                       // to 4444
823     Sample_RGBA_D8888,  Sample_RGBA_D8888,      Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888
824     // RGB_565
825     NULL,               NULL,                   NULL,                       NULL,                       // to A8
826     NULL,               NULL,                   NULL,                       NULL,                       // to Index8
827     Sample_D565_D565,   Sample_D565_D565,       Sample_D565_D565,           Sample_D565_D565,           // to 565
828     NULL,               NULL,                   NULL,                       NULL,                       // to 4444
829     NULL,               NULL,                   NULL,                       NULL,                       // to 8888
830 };
831
832 // Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields.
833 class DummyDecoder : public SkImageDecoder {
834 public:
835     DummyDecoder() {}
836 protected:
837     virtual Result onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE {
838         return kFailure;
839     }
840 };
841
842 void test_row_proc_choice();
843 void test_row_proc_choice() {
844     const SkColorType colorTypes[] = {
845         kAlpha_8_SkColorType, kIndex_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType,
846         kN32_SkColorType
847     };
848
849     SkBitmap dummyBitmap;
850     DummyDecoder dummyDecoder;
851     size_t procCounter = 0;
852     for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) {
853         for (size_t c = 0; c < SK_ARRAY_COUNT(colorTypes); ++c) {
854             for (int unpremul = 0; unpremul <= 1; ++unpremul) {
855                 for (int dither = 0; dither <= 1; ++dither) {
856                     // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to
857                     // be considered valid.
858                     SkScaledBitmapSampler sampler(10, 10, 1);
859                     dummyBitmap.setInfo(SkImageInfo::Make(10, 10,
860                                                           colorTypes[c], kPremul_SkAlphaType));
861                     dummyDecoder.setDitherImage(SkToBool(dither));
862                     dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul));
863                     sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc,
864                                   dummyDecoder);
865                     SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter];
866                     SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler);
867                     SkASSERT(expected == actual);
868                     procCounter++;
869                 }
870             }
871         }
872     }
873     SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter);
874 }
875 #endif // SK_DEBUG