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