1 /*
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
Sample_Gray_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])24 static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
25 const uint8_t* SK_RESTRICT src,
26 int width, int deltaSrc, int, const SkPMColor[]) {
27 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
Sample_RGBx_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])35 static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
36 const uint8_t* SK_RESTRICT src,
37 int width, int deltaSrc, int, const SkPMColor[]) {
38 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
Sample_RGBA_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])46 static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
47 const uint8_t* SK_RESTRICT src,
48 int width, int deltaSrc, int, const SkPMColor[]) {
49 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
Sample_Gray_D565(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])62 static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
63 const uint8_t* SK_RESTRICT src,
64 int width, int deltaSrc, int, const SkPMColor[]) {
65 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
Sample_Gray_D565_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])73 static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
74 const uint8_t* SK_RESTRICT src,
75 int width, int deltaSrc, int y, const SkPMColor[]) {
76 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
Sample_RGBx_D565(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])85 static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
86 const uint8_t* SK_RESTRICT src,
87 int width, int deltaSrc, int, const SkPMColor[]) {
88 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
Sample_RGBx_D565_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])96 static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
97 const uint8_t* SK_RESTRICT src,
98 int width, int deltaSrc, int y, const SkPMColor[]) {
99 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
Sample_Gray_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])110 static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
111 const uint8_t* SK_RESTRICT src,
112 int width, int deltaSrc, int, const SkPMColor[]) {
113 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
Sample_Gray_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])122 static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
123 const uint8_t* SK_RESTRICT src,
124 int width, int deltaSrc, int y, const SkPMColor[]) {
125 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
Sample_RGBx_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])135 static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
136 const uint8_t* SK_RESTRICT src,
137 int width, int deltaSrc, int, const SkPMColor[]) {
138 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
Sample_RGBx_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])146 static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
147 const uint8_t* SK_RESTRICT src,
148 int width, int deltaSrc, int y, const SkPMColor[]) {
149 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
Sample_RGBA_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])160 static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
161 const uint8_t* SK_RESTRICT src,
162 int width, int deltaSrc, int, const SkPMColor[]) {
163 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
Sample_RGBA_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor[])176 static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
177 const uint8_t* SK_RESTRICT src,
178 int width, int deltaSrc, int y, const SkPMColor[]) {
179 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
195 #define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
196
Sample_Index_D8888(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor ctable[])197 static 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
Sample_Index_D565(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor ctable[])212 static 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
Sample_Index_D565_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])224 static 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
Sample_Index_D4444(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])240 static 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
Sample_Index_D4444_D(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int y,const SkPMColor ctable[])255 static 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
Sample_Index_DI(void * SK_RESTRICT dstRow,const uint8_t * SK_RESTRICT src,int width,int deltaSrc,int,const SkPMColor[])272 static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
273 const uint8_t* SK_RESTRICT src,
274 int width, int deltaSrc, int, const SkPMColor[]) {
275 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
SkScaledBitmapSampler(int width,int height,int sampleSize)291 SkScaledBitmapSampler::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;
327 fCTable = NULL;
328 }
329
begin(SkBitmap * dst,SrcConfig sc,bool dither,const SkPMColor ctable[])330 bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
331 const SkPMColor ctable[]) {
332 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,
337 Sample_Index_D8888, Sample_Index_D8888,
338 // 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,
342 Sample_Index_D565, Sample_Index_D565_D,
343 // 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,
347 Sample_Index_D4444, Sample_Index_D4444_D,
348 // Index8
349 NULL, NULL,
350 NULL, NULL,
351 NULL, NULL,
352 Sample_Index_DI, Sample_Index_DI,
353 };
354
355 fCTable = ctable;
356
357 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
next(const uint8_t * SK_RESTRICT src)410 bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
411 SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
412
413 bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
414 fDX * fSrcPixelSize, fCurrY, fCTable);
415 fDstRow += fDstRowBytes;
416 fCurrY += 1;
417 return hadAlpha;
418 }
419