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 
Sample_Gray_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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
get_gray_to_8888_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_RGBx_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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
get_RGBx_to_8888_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_RGBA_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_RGBA_D8888_Unpremul(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_RGBA_D8888_SkipZ(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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
get_RGBA_to_8888_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_Gray_D565(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_Gray_D565_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])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
get_gray_to_565_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_RGBx_D565(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_RGBx_D565_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])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
get_RGBx_to_565_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_D565_D565(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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
get_565_to_565_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_Gray_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_Gray_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])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
get_gray_to_4444_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_RGBx_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_RGBx_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])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
get_RGBx_to_4444_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_RGBA_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_RGBA_D4444_SkipZ(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 
Sample_RGBA_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])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 
Sample_RGBA_D4444_D_SkipZ(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])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
get_RGBA_to_4444_proc(const SkScaledBitmapSampler::Options & opts)343 get_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 
Sample_Index_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor ctable[])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 
Sample_Index_D8888_SkipZ(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor ctable[])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
get_index_to_8888_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_Index_D565(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor ctable[])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 
Sample_Index_D565_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])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
get_index_to_565_proc(const SkScaledBitmapSampler::Options & opts)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 
Sample_Index_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])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 
Sample_Index_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])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 
Sample_Index_D4444_SkipZ(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])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 
Sample_Index_D4444_D_SkipZ(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])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
get_index_to_4444_proc(const SkScaledBitmapSampler::Options & opts)515 get_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 
Sample_Index_DI(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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
get_index_to_index_proc(const SkScaledBitmapSampler::Options & opts)548 get_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
Sample_Gray_DA8(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])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 */ nullptr);
567     return true;
568 }
569 
570 static SkScaledBitmapSampler::RowProc
get_gray_to_A8_proc(const SkScaledBitmapSampler::Options & opts)571 get_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 
579 typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&);
580 ///////////////////////////////////////////////////////////////////////////////
581 
582 #include "SkScaledBitmapSampler.h"
583 
SkScaledBitmapSampler(int width,int height,int sampleSize)584 SkScaledBitmapSampler::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 
begin(SkBitmap * dst,SrcConfig sc,const Options & opts,const SkPMColor ctable[])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         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 
begin(SkBitmap * dst,SrcConfig sc,const SkImageDecoder & decoder,const SkPMColor ctable[])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 
next(const uint8_t * SK_RESTRICT src)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 
sampleInterlaced(const uint8_t * SK_RESTRICT src,int srcY)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     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.
778 class RowProcTester {
779 public:
getRowProc(const SkScaledBitmapSampler & sampler)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
795 SkScaledBitmapSampler::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.
835 class DummyDecoder : public SkImageDecoder {
836 public:
DummyDecoder()837     DummyDecoder() {}
838 protected:
onDecode(SkStream *,SkBitmap *,SkImageDecoder::Mode)839     Result onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) override {
840         return kFailure;
841     }
842 };
843 
844 void test_row_proc_choice();
test_row_proc_choice()845 void 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