blob: 3ba38f7b16df8795c05a4a8988463a9b76650502 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2 * Copyright 2007, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SkScaledBitmapSampler.h"
18#include "SkBitmap.h"
19#include "SkColorPriv.h"
20#include "SkDither.h"
21
22// 8888
23
24static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
25 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000026 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000027 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
28 for (int x = 0; x < width; x++) {
29 dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]);
30 src += deltaSrc;
31 }
32 return false;
33}
34
35static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
36 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000037 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
39 for (int x = 0; x < width; x++) {
40 dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
41 src += deltaSrc;
42 }
43 return false;
44}
45
46static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
47 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000048 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
50 unsigned alphaMask = 0xFF;
51 for (int x = 0; x < width; x++) {
52 unsigned alpha = src[3];
53 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
54 src += deltaSrc;
55 alphaMask &= alpha;
56 }
57 return alphaMask != 0xFF;
58}
59
60// 565
61
62static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
63 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000064 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
66 for (int x = 0; x < width; x++) {
67 dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]);
68 src += deltaSrc;
69 }
70 return false;
71}
72
73static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
74 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000075 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
77 DITHER_565_SCAN(y);
78 for (int x = 0; x < width; x++) {
79 dst[x] = SkDitherRGBTo565(src[0], src[0], src[0], DITHER_VALUE(x));
80 src += deltaSrc;
81 }
82 return false;
83}
84
85static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
86 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000087 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
89 for (int x = 0; x < width; x++) {
90 dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]);
91 src += deltaSrc;
92 }
93 return false;
94}
95
96static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
97 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +000098 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
100 DITHER_565_SCAN(y);
101 for (int x = 0; x < width; x++) {
102 dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x));
103 src += deltaSrc;
104 }
105 return false;
106}
107
108// 4444
109
110static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
111 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000112 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
114 for (int x = 0; x < width; x++) {
115 unsigned gray = src[0] >> 4;
116 dst[x] = SkPackARGB4444(0xF, gray, gray, gray);
117 src += deltaSrc;
118 }
119 return false;
120}
121
122static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
123 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000124 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
126 DITHER_4444_SCAN(y);
127 for (int x = 0; x < width; x++) {
128 dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[0], src[0],
129 DITHER_VALUE(x));
130 src += deltaSrc;
131 }
132 return false;
133}
134
135static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
136 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000137 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
139 for (int x = 0; x < width; x++) {
140 dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4);
141 src += deltaSrc;
142 }
143 return false;
144}
145
146static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
147 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000148 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 SkPMColor16* dst = (SkPMColor16*)dstRow;
150 DITHER_4444_SCAN(y);
151
152 for (int x = 0; x < width; x++) {
153 dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[1], src[2],
154 DITHER_VALUE(x));
155 src += deltaSrc;
156 }
157 return false;
158}
159
160static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
161 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000162 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
164 unsigned alphaMask = 0xFF;
165
166 for (int x = 0; x < width; x++) {
167 unsigned alpha = src[3];
168 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
169 dst[x] = SkPixel32ToPixel4444(c);
170 src += deltaSrc;
171 alphaMask &= alpha;
172 }
173 return alphaMask != 0xFF;
174}
175
176static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
177 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000178 int width, int deltaSrc, int y, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
180 unsigned alphaMask = 0xFF;
181 DITHER_4444_SCAN(y);
182
183 for (int x = 0; x < width; x++) {
184 unsigned alpha = src[3];
185 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
186 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
187 src += deltaSrc;
188 alphaMask &= alpha;
189 }
190 return alphaMask != 0xFF;
191}
192
193// Index
194
reed@android.com1cdcb512009-08-24 19:11:00 +0000195#define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
reed@android.com11344262009-07-08 20:09:23 +0000196
197static bool Sample_Index_D8888(void* SK_RESTRICT dstRow,
198 const uint8_t* SK_RESTRICT src,
199 int width, int deltaSrc, int, const SkPMColor ctable[]) {
200
201 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
202 SkPMColor cc = A32_MASK_IN_PLACE;
203 for (int x = 0; x < width; x++) {
204 SkPMColor c = ctable[*src];
205 cc &= c;
206 dst[x] = c;
207 src += deltaSrc;
208 }
209 return cc != A32_MASK_IN_PLACE;
210}
211
212static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
213 const uint8_t* SK_RESTRICT src,
214 int width, int deltaSrc, int, const SkPMColor ctable[]) {
215
216 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
217 for (int x = 0; x < width; x++) {
218 dst[x] = SkPixel32ToPixel16(ctable[*src]);
219 src += deltaSrc;
220 }
221 return false;
222}
223
224static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
225 const uint8_t* SK_RESTRICT src, int width,
226 int deltaSrc, int y, const SkPMColor ctable[]) {
227
228 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
229 DITHER_565_SCAN(y);
230
231 for (int x = 0; x < width; x++) {
232 SkPMColor c = ctable[*src];
233 dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c),
234 SkGetPackedB32(c), DITHER_VALUE(x));
235 src += deltaSrc;
236 }
237 return false;
238}
239
240static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
241 const uint8_t* SK_RESTRICT src, int width,
242 int deltaSrc, int y, const SkPMColor ctable[]) {
243
244 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
245 SkPMColor cc = A32_MASK_IN_PLACE;
246 for (int x = 0; x < width; x++) {
247 SkPMColor c = ctable[*src];
248 cc &= c;
249 dst[x] = SkPixel32ToPixel4444(c);
250 src += deltaSrc;
251 }
252 return cc != A32_MASK_IN_PLACE;
253}
254
255static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
256 const uint8_t* SK_RESTRICT src, int width,
257 int deltaSrc, int y, const SkPMColor ctable[]) {
258
259 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
260 SkPMColor cc = A32_MASK_IN_PLACE;
261 DITHER_4444_SCAN(y);
262
263 for (int x = 0; x < width; x++) {
264 SkPMColor c = ctable[*src];
265 cc &= c;
266 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
267 src += deltaSrc;
268 }
269 return cc != A32_MASK_IN_PLACE;
270}
271
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
273 const uint8_t* SK_RESTRICT src,
reed@android.com11344262009-07-08 20:09:23 +0000274 int width, int deltaSrc, int, const SkPMColor[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 if (1 == deltaSrc) {
276 memcpy(dstRow, src, width);
277 } else {
278 uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow;
279 for (int x = 0; x < width; x++) {
280 dst[x] = src[0];
281 src += deltaSrc;
282 }
283 }
284 return false;
285}
286
287///////////////////////////////////////////////////////////////////////////////
288
289#include "SkScaledBitmapSampler.h"
290
291SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
292 int sampleSize) {
293 if (width <= 0 || height <= 0) {
294 sk_throw();
295 }
296
297 if (sampleSize <= 1) {
298 fScaledWidth = width;
299 fScaledHeight = height;
300 fX0 = fY0 = 0;
301 fDX = fDY = 1;
302 return;
303 }
304
305 int dx = SkMin32(sampleSize, width);
306 int dy = SkMin32(sampleSize, height);
307
308 fScaledWidth = width / dx;
309 fScaledHeight = height / dy;
310
311 SkASSERT(fScaledWidth > 0);
312 SkASSERT(fScaledHeight > 0);
313
314 fX0 = dx >> 1;
315 fY0 = dy >> 1;
316
317 SkASSERT(fX0 >= 0 && fX0 < width);
318 SkASSERT(fY0 >= 0 && fY0 < height);
319
320 fDX = dx;
321 fDY = dy;
322
323 SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width);
324 SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
325
326 fRowProc = NULL;
reed@android.com11344262009-07-08 20:09:23 +0000327 fCTable = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328}
329
reed@android.com11344262009-07-08 20:09:23 +0000330bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
331 const SkPMColor ctable[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332 static const RowProc gProcs[] = {
333 // 8888 (no dither distinction)
334 Sample_Gray_D8888, Sample_Gray_D8888,
335 Sample_RGBx_D8888, Sample_RGBx_D8888,
336 Sample_RGBA_D8888, Sample_RGBA_D8888,
reed@android.com11344262009-07-08 20:09:23 +0000337 Sample_Index_D8888, Sample_Index_D8888,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 // 565 (no alpha distinction)
339 Sample_Gray_D565, Sample_Gray_D565_D,
340 Sample_RGBx_D565, Sample_RGBx_D565_D,
341 Sample_RGBx_D565, Sample_RGBx_D565_D,
reed@android.com11344262009-07-08 20:09:23 +0000342 Sample_Index_D565, Sample_Index_D565_D,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 // 4444
344 Sample_Gray_D4444, Sample_Gray_D4444_D,
345 Sample_RGBx_D4444, Sample_RGBx_D4444_D,
346 Sample_RGBA_D4444, Sample_RGBA_D4444_D,
reed@android.com11344262009-07-08 20:09:23 +0000347 Sample_Index_D4444, Sample_Index_D4444_D,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 // Index8
349 NULL, NULL,
350 NULL, NULL,
351 NULL, NULL,
352 Sample_Index_DI, Sample_Index_DI,
353 };
354
reed@android.com11344262009-07-08 20:09:23 +0000355 fCTable = ctable;
356
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 int index = 0;
358 if (dither) {
359 index += 1;
360 }
361 switch (sc) {
362 case SkScaledBitmapSampler::kGray:
363 fSrcPixelSize = 1;
364 index += 0;
365 break;
366 case SkScaledBitmapSampler::kRGB:
367 fSrcPixelSize = 3;
368 index += 2;
369 break;
370 case SkScaledBitmapSampler::kRGBX:
371 fSrcPixelSize = 4;
372 index += 2;
373 break;
374 case SkScaledBitmapSampler::kRGBA:
375 fSrcPixelSize = 4;
376 index += 4;
377 break;
378 case SkScaledBitmapSampler::kIndex:
379 fSrcPixelSize = 1;
380 index += 6;
381 break;
382 default:
383 return false;
384 }
385
386 switch (dst->config()) {
387 case SkBitmap::kARGB_8888_Config:
388 index += 0;
389 break;
390 case SkBitmap::kRGB_565_Config:
391 index += 8;
392 break;
393 case SkBitmap::kARGB_4444_Config:
394 index += 16;
395 break;
396 case SkBitmap::kIndex8_Config:
397 index += 24;
398 break;
399 default:
400 return false;
401 }
402
403 fRowProc = gProcs[index];
404 fDstRow = (char*)dst->getPixels();
405 fDstRowBytes = dst->rowBytes();
406 fCurrY = 0;
407 return fRowProc != NULL;
408}
409
410bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
411 SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
412
413 bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
reed@android.com11344262009-07-08 20:09:23 +0000414 fDX * fSrcPixelSize, fCurrY, fCTable);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415 fDstRow += fDstRowBytes;
416 fCurrY += 1;
417 return hadAlpha;
418}