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 bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow, 29 const uint8_t* SK_RESTRICT src, 30 int width, int deltaSrc, int, const SkPMColor[]) { 31 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 39 static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow, 40 const uint8_t* SK_RESTRICT src, 41 int width, int deltaSrc, int, const SkPMColor[]) { 42 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 55 static bool Sample_Gray_D565(void* SK_RESTRICT dstRow, 56 const uint8_t* SK_RESTRICT src, 57 int width, int deltaSrc, int, const SkPMColor[]) { 58 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 66 static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow, 67 const uint8_t* SK_RESTRICT src, 68 int width, int deltaSrc, int y, const SkPMColor[]) { 69 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 78 static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow, 79 const uint8_t* SK_RESTRICT src, 80 int width, int deltaSrc, int, const SkPMColor[]) { 81 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 89 static 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 101 static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow, 102 const uint8_t* SK_RESTRICT src, 103 int width, int deltaSrc, int y, const SkPMColor[]) { 104 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 115 static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow, 116 const uint8_t* SK_RESTRICT src, 117 int width, int deltaSrc, int, const SkPMColor[]) { 118 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 127 static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow, 128 const uint8_t* SK_RESTRICT src, 129 int width, int deltaSrc, int y, const SkPMColor[]) { 130 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 140 static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow, 141 const uint8_t* SK_RESTRICT src, 142 int width, int deltaSrc, int, const SkPMColor[]) { 143 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 151 static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow, 152 const uint8_t* SK_RESTRICT src, 153 int width, int deltaSrc, int y, const SkPMColor[]) { 154 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 165 static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow, 166 const uint8_t* SK_RESTRICT src, 167 int width, int deltaSrc, int, const SkPMColor[]) { 168 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 181 static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow, 182 const uint8_t* SK_RESTRICT src, 183 int width, int deltaSrc, int y, const SkPMColor[]) { 184 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 200 #define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT) 201 202 static 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 217 static 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 229 static 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 245 static 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 260 static 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 277 static bool Sample_Index_DI(void* SK_RESTRICT dstRow, 278 const uint8_t* SK_RESTRICT src, 279 int width, int deltaSrc, int, const SkPMColor[]) { 280 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 // A8 293 static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow, 294 const uint8_t* SK_RESTRICT src, 295 int width, int deltaSrc, int, 296 const SkPMColor[]) { 297 memcpy(dstRow, src, width); 298 return true; 299 } 300 301 // 8888 Unpremul 302 303 static bool Sample_Gray_D8888_Unpremul(void* SK_RESTRICT dstRow, 304 const uint8_t* SK_RESTRICT src, 305 int width, int deltaSrc, int, 306 const SkPMColor[]) { 307 uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow); 308 for (int x = 0; x < width; x++) { 309 dst[x] = SkPackARGB32NoCheck(0xFF, src[0], src[0], src[0]); 310 src += deltaSrc; 311 } 312 return false; 313 } 314 315 // Sample_RGBx_D8888_Unpremul is no different from Sample_RGBx_D8888, since alpha 316 // is 0xFF 317 318 static bool Sample_RGBA_D8888_Unpremul(void* SK_RESTRICT dstRow, 319 const uint8_t* SK_RESTRICT src, 320 int width, int deltaSrc, int, 321 const SkPMColor[]) { 322 uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow); 323 unsigned alphaMask = 0xFF; 324 for (int x = 0; x < width; x++) { 325 unsigned alpha = src[3]; 326 dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); 327 src += deltaSrc; 328 alphaMask &= alpha; 329 } 330 return alphaMask != 0xFF; 331 } 332 333 // Sample_Index_D8888_Unpremul is the same as Sample_Index_D8888, since the 334 // color table has its colors inserted unpremultiplied. 335 336 /////////////////////////////////////////////////////////////////////////////// 337 338 #include "SkScaledBitmapSampler.h" 339 340 SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height, 341 int sampleSize) { 342 fCTable = NULL; 343 fDstRow = NULL; 344 fRowProc = NULL; 345 346 if (width <= 0 || height <= 0) { 347 sk_throw(); 348 } 349 350 if (sampleSize <= 1) { 351 fScaledWidth = width; 352 fScaledHeight = height; 353 fX0 = fY0 = 0; 354 fDX = fDY = 1; 355 return; 356 } 357 358 int dx = SkMin32(sampleSize, width); 359 int dy = SkMin32(sampleSize, height); 360 361 fScaledWidth = width / dx; 362 fScaledHeight = height / dy; 363 364 SkASSERT(fScaledWidth > 0); 365 SkASSERT(fScaledHeight > 0); 366 367 fX0 = dx >> 1; 368 fY0 = dy >> 1; 369 370 SkASSERT(fX0 >= 0 && fX0 < width); 371 SkASSERT(fY0 >= 0 && fY0 < height); 372 373 fDX = dx; 374 fDY = dy; 375 376 SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width); 377 SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height); 378 } 379 380 bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither, 381 const SkPMColor ctable[], 382 bool requireUnpremul) { 383 static const RowProc gProcs[] = { 384 // 8888 (no dither distinction) 385 Sample_Gray_D8888, Sample_Gray_D8888, 386 Sample_RGBx_D8888, Sample_RGBx_D8888, 387 Sample_RGBA_D8888, Sample_RGBA_D8888, 388 Sample_Index_D8888, Sample_Index_D8888, 389 NULL, NULL, 390 // 565 (no alpha distinction) 391 Sample_Gray_D565, Sample_Gray_D565_D, 392 Sample_RGBx_D565, Sample_RGBx_D565_D, 393 Sample_RGBx_D565, Sample_RGBx_D565_D, 394 Sample_Index_D565, Sample_Index_D565_D, 395 Sample_D565_D565, Sample_D565_D565, 396 // 4444 397 Sample_Gray_D4444, Sample_Gray_D4444_D, 398 Sample_RGBx_D4444, Sample_RGBx_D4444_D, 399 Sample_RGBA_D4444, Sample_RGBA_D4444_D, 400 Sample_Index_D4444, Sample_Index_D4444_D, 401 NULL, NULL, 402 // Index8 403 NULL, NULL, 404 NULL, NULL, 405 NULL, NULL, 406 Sample_Index_DI, Sample_Index_DI, 407 NULL, NULL, 408 // A8 409 Sample_Gray_DA8, Sample_Gray_DA8, 410 NULL, NULL, 411 NULL, NULL, 412 NULL, NULL, 413 NULL, NULL, 414 // 8888 Unpremul (no dither distinction) 415 Sample_Gray_D8888_Unpremul, Sample_Gray_D8888_Unpremul, 416 Sample_RGBx_D8888, Sample_RGBx_D8888, 417 Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, 418 Sample_Index_D8888, Sample_Index_D8888, 419 NULL, NULL, 420 }; 421 // The jump between dst configs in the table 422 static const int gProcDstConfigSpan = 10; 423 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcs) == 6 * gProcDstConfigSpan, 424 gProcs_has_the_wrong_number_of_entries); 425 426 fCTable = ctable; 427 428 int index = 0; 429 if (dither) { 430 index += 1; 431 } 432 switch (sc) { 433 case SkScaledBitmapSampler::kGray: 434 fSrcPixelSize = 1; 435 index += 0; 436 break; 437 case SkScaledBitmapSampler::kRGB: 438 fSrcPixelSize = 3; 439 index += 2; 440 break; 441 case SkScaledBitmapSampler::kRGBX: 442 fSrcPixelSize = 4; 443 index += 2; 444 break; 445 case SkScaledBitmapSampler::kRGBA: 446 fSrcPixelSize = 4; 447 index += 4; 448 break; 449 case SkScaledBitmapSampler::kIndex: 450 fSrcPixelSize = 1; 451 index += 6; 452 break; 453 case SkScaledBitmapSampler::kRGB_565: 454 fSrcPixelSize = 2; 455 index += 8; 456 break; 457 default: 458 return false; 459 } 460 461 switch (dst->config()) { 462 case SkBitmap::kARGB_8888_Config: 463 index += 0 * gProcDstConfigSpan; 464 break; 465 case SkBitmap::kRGB_565_Config: 466 index += 1 * gProcDstConfigSpan; 467 break; 468 case SkBitmap::kARGB_4444_Config: 469 index += 2 * gProcDstConfigSpan; 470 break; 471 case SkBitmap::kIndex8_Config: 472 index += 3 * gProcDstConfigSpan; 473 break; 474 case SkBitmap::kA8_Config: 475 index += 4 * gProcDstConfigSpan; 476 break; 477 default: 478 return false; 479 } 480 481 if (requireUnpremul) { 482 if (dst->config() != SkBitmap::kARGB_8888_Config) { 483 return false; 484 } 485 index += 5 * gProcDstConfigSpan; 486 } 487 488 fRowProc = gProcs[index]; 489 fDstRow = (char*)dst->getPixels(); 490 fDstRowBytes = dst->rowBytes(); 491 fCurrY = 0; 492 return fRowProc != NULL; 493 } 494 495 bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) { 496 SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight); 497 498 bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth, 499 fDX * fSrcPixelSize, fCurrY, fCTable); 500 fDstRow += fDstRowBytes; 501 fCurrY += 1; 502 return hadAlpha; 503 } 504