blob: 15633d3a63bd8c74e4f997981cdeb097c27f9bc3 [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) {
vandebo@chromium.orga728e352012-03-28 20:29:38 +0000298 fCTable = NULL;
299 fDstRow = NULL;
300 fRowProc = NULL;
301
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302 if (width <= 0 || height <= 0) {
303 sk_throw();
304 }
305
306 if (sampleSize <= 1) {
307 fScaledWidth = width;
308 fScaledHeight = height;
309 fX0 = fY0 = 0;
310 fDX = fDY = 1;
311 return;
312 }
313
314 int dx = SkMin32(sampleSize, width);
315 int dy = SkMin32(sampleSize, height);
316
317 fScaledWidth = width / dx;
318 fScaledHeight = height / dy;
319
320 SkASSERT(fScaledWidth > 0);
321 SkASSERT(fScaledHeight > 0);
322
323 fX0 = dx >> 1;
324 fY0 = dy >> 1;
325
326 SkASSERT(fX0 >= 0 && fX0 < width);
327 SkASSERT(fY0 >= 0 && fY0 < height);
328
329 fDX = dx;
330 fDY = dy;
331
332 SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width);
333 SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334}
335
reed@android.com11344262009-07-08 20:09:23 +0000336bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
337 const SkPMColor ctable[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 static const RowProc gProcs[] = {
339 // 8888 (no dither distinction)
340 Sample_Gray_D8888, Sample_Gray_D8888,
341 Sample_RGBx_D8888, Sample_RGBx_D8888,
342 Sample_RGBA_D8888, Sample_RGBA_D8888,
reed@android.com11344262009-07-08 20:09:23 +0000343 Sample_Index_D8888, Sample_Index_D8888,
djsollen@google.com57f49692011-02-23 20:46:31 +0000344 NULL, NULL,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 // 565 (no alpha distinction)
346 Sample_Gray_D565, Sample_Gray_D565_D,
347 Sample_RGBx_D565, Sample_RGBx_D565_D,
348 Sample_RGBx_D565, Sample_RGBx_D565_D,
reed@android.com11344262009-07-08 20:09:23 +0000349 Sample_Index_D565, Sample_Index_D565_D,
djsollen@google.com57f49692011-02-23 20:46:31 +0000350 Sample_D565_D565, Sample_D565_D565,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 // 4444
352 Sample_Gray_D4444, Sample_Gray_D4444_D,
353 Sample_RGBx_D4444, Sample_RGBx_D4444_D,
354 Sample_RGBA_D4444, Sample_RGBA_D4444_D,
reed@android.com11344262009-07-08 20:09:23 +0000355 Sample_Index_D4444, Sample_Index_D4444_D,
djsollen@google.com57f49692011-02-23 20:46:31 +0000356 NULL, NULL,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 // Index8
358 NULL, NULL,
359 NULL, NULL,
360 NULL, NULL,
361 Sample_Index_DI, Sample_Index_DI,
djsollen@google.com57f49692011-02-23 20:46:31 +0000362 NULL, NULL,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 };
364
reed@android.com11344262009-07-08 20:09:23 +0000365 fCTable = ctable;
366
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 int index = 0;
368 if (dither) {
369 index += 1;
370 }
371 switch (sc) {
372 case SkScaledBitmapSampler::kGray:
373 fSrcPixelSize = 1;
374 index += 0;
375 break;
376 case SkScaledBitmapSampler::kRGB:
377 fSrcPixelSize = 3;
378 index += 2;
379 break;
380 case SkScaledBitmapSampler::kRGBX:
381 fSrcPixelSize = 4;
382 index += 2;
383 break;
384 case SkScaledBitmapSampler::kRGBA:
385 fSrcPixelSize = 4;
386 index += 4;
387 break;
388 case SkScaledBitmapSampler::kIndex:
389 fSrcPixelSize = 1;
390 index += 6;
391 break;
djsollen@google.com57f49692011-02-23 20:46:31 +0000392 case SkScaledBitmapSampler::kRGB_565:
393 fSrcPixelSize = 2;
394 index += 8;
395 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396 default:
397 return false;
398 }
399
400 switch (dst->config()) {
401 case SkBitmap::kARGB_8888_Config:
402 index += 0;
403 break;
404 case SkBitmap::kRGB_565_Config:
djsollen@google.com57f49692011-02-23 20:46:31 +0000405 index += 10;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 break;
407 case SkBitmap::kARGB_4444_Config:
djsollen@google.com57f49692011-02-23 20:46:31 +0000408 index += 20;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 break;
410 case SkBitmap::kIndex8_Config:
djsollen@google.com57f49692011-02-23 20:46:31 +0000411 index += 30;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412 break;
413 default:
414 return false;
415 }
416
417 fRowProc = gProcs[index];
418 fDstRow = (char*)dst->getPixels();
419 fDstRowBytes = dst->rowBytes();
420 fCurrY = 0;
421 return fRowProc != NULL;
422}
423
424bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
425 SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
426
427 bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
reed@android.com11344262009-07-08 20:09:23 +0000428 fDX * fSrcPixelSize, fCurrY, fCTable);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 fDstRow += fDstRowBytes;
430 fCurrY += 1;
431 return hadAlpha;
432}