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