|
1 /* |
|
2 * Copyright 2007 The Android Open Source Project |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 |
|
9 #include "SkScaledBitmapSampler.h" |
|
10 #include "SkBitmap.h" |
|
11 #include "SkColorPriv.h" |
|
12 #include "SkDither.h" |
|
13 #include "SkTypes.h" |
|
14 |
|
15 // 8888 |
|
16 |
|
17 static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow, |
|
18 const uint8_t* SK_RESTRICT src, |
|
19 int width, int deltaSrc, int, const SkPMColor[]) { |
|
20 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; |
|
21 for (int x = 0; x < width; x++) { |
|
22 dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]); |
|
23 src += deltaSrc; |
|
24 } |
|
25 return false; |
|
26 } |
|
27 |
|
28 static SkScaledBitmapSampler::RowProc get_gray_to_8888_proc(const SkImageDecoder& decoder) { |
|
29 // Dither, unpremul, and skipZeroes have no effect |
|
30 return Sample_Gray_D8888; |
|
31 } |
|
32 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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: |
|
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: |
|
818 DummyDecoder() {} |
|
819 protected: |
|
820 virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE { |
|
821 return false; |
|
822 } |
|
823 }; |
|
824 |
|
825 void 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 |