blob: 1af433dac66d401ba35b049afc3ab47ba5721a7f [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2007 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkScaledBitmapSampler.h"
11#include "SkBitmap.h"
12#include "SkColorPriv.h"
13#include "SkDither.h"
14
15// 8888
16
17static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
18 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000019 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000020 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
28static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
29 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000030 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
32 for (int x = 0; x < width; x++) {
33 dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
34 src += deltaSrc;
35 }
36 return false;
37}
38
39static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
40 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000041 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000042 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
43 unsigned alphaMask = 0xFF;
44 for (int x = 0; x < width; x++) {
45 unsigned alpha = src[3];
46 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
47 src += deltaSrc;
48 alphaMask &= alpha;
49 }
50 return alphaMask != 0xFF;
51}
52
53// 565
54
55static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
56 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000057 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
59 for (int x = 0; x < width; x++) {
60 dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]);
61 src += deltaSrc;
62 }
63 return false;
64}
65
66static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
67 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000068 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
70 DITHER_565_SCAN(y);
71 for (int x = 0; x < width; x++) {
72 dst[x] = SkDitherRGBTo565(src[0], src[0], src[0], DITHER_VALUE(x));
73 src += deltaSrc;
74 }
75 return false;
76}
77
78static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
79 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000080 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
82 for (int x = 0; x < width; x++) {
83 dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]);
84 src += deltaSrc;
85 }
86 return false;
87}
88
djsollen@google.com57f49692011-02-23 20:46:31 +000089static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
90 const uint8_t* SK_RESTRICT src,
91 int width, int deltaSrc, int, const SkPMColor[]) {
92 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
93 uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src;
94 for (int x = 0; x < width; x++) {
95 dst[x] = castedSrc[0];
96 castedSrc += deltaSrc >> 1;
97 }
98 return false;
99}
100
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
102 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000103 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
105 DITHER_565_SCAN(y);
106 for (int x = 0; x < width; x++) {
107 dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x));
108 src += deltaSrc;
109 }
110 return false;
111}
112
113// 4444
114
115static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
116 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000117 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
119 for (int x = 0; x < width; x++) {
120 unsigned gray = src[0] >> 4;
121 dst[x] = SkPackARGB4444(0xF, gray, gray, gray);
122 src += deltaSrc;
123 }
124 return false;
125}
126
127static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
128 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000129 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
131 DITHER_4444_SCAN(y);
132 for (int x = 0; x < width; x++) {
133 dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[0], src[0],
134 DITHER_VALUE(x));
135 src += deltaSrc;
136 }
137 return false;
138}
139
140static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
141 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000142 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
144 for (int x = 0; x < width; x++) {
145 dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4);
146 src += deltaSrc;
147 }
148 return false;
149}
150
151static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
152 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000153 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 SkPMColor16* dst = (SkPMColor16*)dstRow;
155 DITHER_4444_SCAN(y);
156
157 for (int x = 0; x < width; x++) {
158 dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[1], src[2],
159 DITHER_VALUE(x));
160 src += deltaSrc;
161 }
162 return false;
163}
164
165static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
166 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000167 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
169 unsigned alphaMask = 0xFF;
170
171 for (int x = 0; x < width; x++) {
172 unsigned alpha = src[3];
173 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
174 dst[x] = SkPixel32ToPixel4444(c);
175 src += deltaSrc;
176 alphaMask &= alpha;
177 }
178 return alphaMask != 0xFF;
179}
180
181static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
182 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000183 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
185 unsigned alphaMask = 0xFF;
186 DITHER_4444_SCAN(y);
187
188 for (int x = 0; x < width; x++) {
189 unsigned alpha = src[3];
190 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
191 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
192 src += deltaSrc;
193 alphaMask &= alpha;
194 }
195 return alphaMask != 0xFF;
196}
197
198// Index
199
reed@android.com1cdcb512009-08-24 19:11:00 +0000200#define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
reed@android.com11344262009-07-08 20:09:23 +0000201
202static bool Sample_Index_D8888(void* SK_RESTRICT dstRow,
203 const uint8_t* SK_RESTRICT src,
204 int width, int deltaSrc, int, const SkPMColor ctable[]) {
205
206 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
207 SkPMColor cc = A32_MASK_IN_PLACE;
208 for (int x = 0; x < width; x++) {
209 SkPMColor c = ctable[*src];
210 cc &= c;
211 dst[x] = c;
212 src += deltaSrc;
213 }
214 return cc != A32_MASK_IN_PLACE;
215}
216
217static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
218 const uint8_t* SK_RESTRICT src,
219 int width, int deltaSrc, int, const SkPMColor ctable[]) {
220
221 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
222 for (int x = 0; x < width; x++) {
223 dst[x] = SkPixel32ToPixel16(ctable[*src]);
224 src += deltaSrc;
225 }
226 return false;
227}
228
229static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
230 const uint8_t* SK_RESTRICT src, int width,
231 int deltaSrc, int y, const SkPMColor ctable[]) {
232
233 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
234 DITHER_565_SCAN(y);
235
236 for (int x = 0; x < width; x++) {
237 SkPMColor c = ctable[*src];
238 dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c),
239 SkGetPackedB32(c), DITHER_VALUE(x));
240 src += deltaSrc;
241 }
242 return false;
243}
244
245static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
246 const uint8_t* SK_RESTRICT src, int width,
247 int deltaSrc, int y, const SkPMColor ctable[]) {
248
249 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
250 SkPMColor cc = A32_MASK_IN_PLACE;
251 for (int x = 0; x < width; x++) {
252 SkPMColor c = ctable[*src];
253 cc &= c;
254 dst[x] = SkPixel32ToPixel4444(c);
255 src += deltaSrc;
256 }
257 return cc != A32_MASK_IN_PLACE;
258}
259
260static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
261 const uint8_t* SK_RESTRICT src, int width,
262 int deltaSrc, int y, const SkPMColor ctable[]) {
263
264 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
265 SkPMColor cc = A32_MASK_IN_PLACE;
266 DITHER_4444_SCAN(y);
267
268 for (int x = 0; x < width; x++) {
269 SkPMColor c = ctable[*src];
270 cc &= c;
271 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
272 src += deltaSrc;
273 }
274 return cc != A32_MASK_IN_PLACE;
275}
276
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
278 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000279 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 if (1 == deltaSrc) {
281 memcpy(dstRow, src, width);
282 } else {
283 uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow;
284 for (int x = 0; x < width; x++) {
285 dst[x] = src[0];
286 src += deltaSrc;
287 }
288 }
289 return false;
290}
291
292///////////////////////////////////////////////////////////////////////////////
293
294#include "SkScaledBitmapSampler.h"
295
296SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
297 int sampleSize) {
298 if (width <= 0 || height <= 0) {
299 sk_throw();
300 }
301
302 if (sampleSize <= 1) {
303 fScaledWidth = width;
304 fScaledHeight = height;
305 fX0 = fY0 = 0;
306 fDX = fDY = 1;
307 return;
308 }
309
310 int dx = SkMin32(sampleSize, width);
311 int dy = SkMin32(sampleSize, height);
312
313 fScaledWidth = width / dx;
314 fScaledHeight = height / dy;
315
316 SkASSERT(fScaledWidth > 0);
317 SkASSERT(fScaledHeight > 0);
318
319 fX0 = dx >> 1;
320 fY0 = dy >> 1;
321
322 SkASSERT(fX0 >= 0 && fX0 < width);
323 SkASSERT(fY0 >= 0 && fY0 < height);
324
325 fDX = dx;
326 fDY = dy;
327
328 SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width);
329 SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
330
331 fRowProc = NULL;
reed@android.com11344262009-07-08 20:09:23 +0000332 fCTable = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333}
334
reed@android.com11344262009-07-08 20:09:23 +0000335bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
336 const SkPMColor ctable[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 static const RowProc gProcs[] = {
338 // 8888 (no dither distinction)
339 Sample_Gray_D8888, Sample_Gray_D8888,
340 Sample_RGBx_D8888, Sample_RGBx_D8888,
341 Sample_RGBA_D8888, Sample_RGBA_D8888,
reed@android.com11344262009-07-08 20:09:23 +0000342 Sample_Index_D8888, Sample_Index_D8888,
djsollen@google.com57f49692011-02-23 20:46:31 +0000343 NULL, NULL,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 // 565 (no alpha distinction)
345 Sample_Gray_D565, Sample_Gray_D565_D,
346 Sample_RGBx_D565, Sample_RGBx_D565_D,
347 Sample_RGBx_D565, Sample_RGBx_D565_D,
reed@android.com11344262009-07-08 20:09:23 +0000348 Sample_Index_D565, Sample_Index_D565_D,
djsollen@google.com57f49692011-02-23 20:46:31 +0000349 Sample_D565_D565, Sample_D565_D565,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 // 4444
351 Sample_Gray_D4444, Sample_Gray_D4444_D,
352 Sample_RGBx_D4444, Sample_RGBx_D4444_D,
353 Sample_RGBA_D4444, Sample_RGBA_D4444_D,
reed@android.com11344262009-07-08 20:09:23 +0000354 Sample_Index_D4444, Sample_Index_D4444_D,
djsollen@google.com57f49692011-02-23 20:46:31 +0000355 NULL, NULL,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 // Index8
357 NULL, NULL,
358 NULL, NULL,
359 NULL, NULL,
360 Sample_Index_DI, Sample_Index_DI,
djsollen@google.com57f49692011-02-23 20:46:31 +0000361 NULL, NULL,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 };
363
reed@android.com11344262009-07-08 20:09:23 +0000364 fCTable = ctable;
365
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366 int index = 0;
367 if (dither) {
368 index += 1;
369 }
370 switch (sc) {
371 case SkScaledBitmapSampler::kGray:
372 fSrcPixelSize = 1;
373 index += 0;
374 break;
375 case SkScaledBitmapSampler::kRGB:
376 fSrcPixelSize = 3;
377 index += 2;
378 break;
379 case SkScaledBitmapSampler::kRGBX:
380 fSrcPixelSize = 4;
381 index += 2;
382 break;
383 case SkScaledBitmapSampler::kRGBA:
384 fSrcPixelSize = 4;
385 index += 4;
386 break;
387 case SkScaledBitmapSampler::kIndex:
388 fSrcPixelSize = 1;
389 index += 6;
390 break;
djsollen@google.com57f49692011-02-23 20:46:31 +0000391 case SkScaledBitmapSampler::kRGB_565:
392 fSrcPixelSize = 2;
393 index += 8;
394 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395 default:
396 return false;
397 }
398
399 switch (dst->config()) {
400 case SkBitmap::kARGB_8888_Config:
401 index += 0;
402 break;
403 case SkBitmap::kRGB_565_Config:
djsollen@google.com57f49692011-02-23 20:46:31 +0000404 index += 10;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405 break;
406 case SkBitmap::kARGB_4444_Config:
djsollen@google.com57f49692011-02-23 20:46:31 +0000407 index += 20;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408 break;
409 case SkBitmap::kIndex8_Config:
djsollen@google.com57f49692011-02-23 20:46:31 +0000410 index += 30;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411 break;
412 default:
413 return false;
414 }
415
416 fRowProc = gProcs[index];
417 fDstRow = (char*)dst->getPixels();
418 fDstRowBytes = dst->rowBytes();
419 fCurrY = 0;
420 return fRowProc != NULL;
421}
422
423bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
424 SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
425
426 bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
reed@android.com11344262009-07-08 20:09:23 +0000427 fDX * fSrcPixelSize, fCurrY, fCTable);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000428 fDstRow += fDstRowBytes;
429 fCurrY += 1;
430 return hadAlpha;
431}