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