| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkBitmapDevice.h" | 8 #include "SkBitmapDevice.h" |
| 9 #include "SkCanvas.h" | 9 #include "SkCanvas.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 | 53 |
| 54 static SkPMColor getBitmapColor(int x, int y, int w) { | 54 static SkPMColor getBitmapColor(int x, int y, int w) { |
| 55 int n = y * w + x; | 55 int n = y * w + x; |
| 56 | 56 |
| 57 U8CPU b = n & 0xff; | 57 U8CPU b = n & 0xff; |
| 58 U8CPU g = (n >> 8) & 0xff; | 58 U8CPU g = (n >> 8) & 0xff; |
| 59 U8CPU r = (n >> 16) & 0xff; | 59 U8CPU r = (n >> 16) & 0xff; |
| 60 return SkPackARGB32(0xff, r, g , b); | 60 return SkPackARGB32(0xff, r, g , b); |
| 61 } | 61 } |
| 62 | 62 |
| 63 static SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888, | 63 static SkPMColor convertToPMColor(SkColorType ct, SkAlphaType at, const uint32_t
* addr, |
| 64 uint32_t color, | 64 bool* doUnpremul) { |
| 65 bool* premul) { | 65 *doUnpremul = (kUnpremul_SkAlphaType == at); |
| 66 const uint8_t* c = reinterpret_cast<uint8_t*>(&color); | 66 |
| 67 const uint8_t* c = reinterpret_cast<const uint8_t*>(addr); |
| 67 U8CPU a,r,g,b; | 68 U8CPU a,r,g,b; |
| 68 *premul = false; | 69 switch (ct) { |
| 69 switch (config8888) { | 70 case kBGRA_8888_SkColorType: |
| 70 case SkCanvas::kNative_Premul_Config8888: | 71 b = static_cast<U8CPU>(c[0]); |
| 71 return color; | 72 g = static_cast<U8CPU>(c[1]); |
| 72 case SkCanvas::kNative_Unpremul_Config8888: | 73 r = static_cast<U8CPU>(c[2]); |
| 73 *premul = true; | 74 a = static_cast<U8CPU>(c[3]); |
| 74 a = SkGetPackedA32(color); | |
| 75 r = SkGetPackedR32(color); | |
| 76 g = SkGetPackedG32(color); | |
| 77 b = SkGetPackedB32(color); | |
| 78 break; | 75 break; |
| 79 case SkCanvas::kBGRA_Unpremul_Config8888: | 76 case kRGBA_8888_SkColorType: |
| 80 *premul = true; // fallthru | |
| 81 case SkCanvas::kBGRA_Premul_Config8888: | |
| 82 a = static_cast<U8CPU>(c[3]); | |
| 83 r = static_cast<U8CPU>(c[2]); | |
| 84 g = static_cast<U8CPU>(c[1]); | |
| 85 b = static_cast<U8CPU>(c[0]); | |
| 86 break; | |
| 87 case SkCanvas::kRGBA_Unpremul_Config8888: | |
| 88 *premul = true; // fallthru | |
| 89 case SkCanvas::kRGBA_Premul_Config8888: | |
| 90 a = static_cast<U8CPU>(c[3]); | |
| 91 r = static_cast<U8CPU>(c[0]); | 77 r = static_cast<U8CPU>(c[0]); |
| 92 g = static_cast<U8CPU>(c[1]); | 78 g = static_cast<U8CPU>(c[1]); |
| 93 b = static_cast<U8CPU>(c[2]); | 79 b = static_cast<U8CPU>(c[2]); |
| 80 a = static_cast<U8CPU>(c[3]); |
| 94 break; | 81 break; |
| 95 default: | 82 default: |
| 96 SkDEBUGFAIL("Unexpected Config8888"); | 83 SkDEBUGFAIL("Unexpected colortype"); |
| 97 return 0; | 84 return 0; |
| 98 } | 85 } |
| 99 if (*premul) { | 86 |
| 87 if (*doUnpremul) { |
| 100 r = SkMulDiv255Ceiling(r, a); | 88 r = SkMulDiv255Ceiling(r, a); |
| 101 g = SkMulDiv255Ceiling(g, a); | 89 g = SkMulDiv255Ceiling(g, a); |
| 102 b = SkMulDiv255Ceiling(b, a); | 90 b = SkMulDiv255Ceiling(b, a); |
| 103 } | 91 } |
| 104 return SkPackARGB32(a, r, g, b); | 92 return SkPackARGB32(a, r, g, b); |
| 105 } | 93 } |
| 106 | 94 |
| 107 static void fillCanvas(SkCanvas* canvas) { | 95 static void fillCanvas(SkCanvas* canvas) { |
| 108 static SkBitmap bmp; | 96 static SkBitmap bmp; |
| 109 if (bmp.isNull()) { | 97 if (bmp.isNull()) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 SkAbs32(aB - bB) <= 1; | 149 SkAbs32(aB - bB) <= 1; |
| 162 } | 150 } |
| 163 | 151 |
| 164 // checks the bitmap contains correct pixels after the readPixels | 152 // checks the bitmap contains correct pixels after the readPixels |
| 165 // if the bitmap was prefilled with pixels it checks that these weren't | 153 // if the bitmap was prefilled with pixels it checks that these weren't |
| 166 // overwritten in the area outside the readPixels. | 154 // overwritten in the area outside the readPixels. |
| 167 static bool checkRead(skiatest::Reporter* reporter, | 155 static bool checkRead(skiatest::Reporter* reporter, |
| 168 const SkBitmap& bitmap, | 156 const SkBitmap& bitmap, |
| 169 int x, int y, | 157 int x, int y, |
| 170 bool checkCanvasPixels, | 158 bool checkCanvasPixels, |
| 171 bool checkBitmapPixels, | 159 bool checkBitmapPixels) { |
| 172 SkCanvas::Config8888 config8888) { | 160 SkASSERT(4 == bitmap.bytesPerPixel()); |
| 173 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); | |
| 174 SkASSERT(!bitmap.isNull()); | 161 SkASSERT(!bitmap.isNull()); |
| 175 SkASSERT(checkCanvasPixels || checkBitmapPixels); | 162 SkASSERT(checkCanvasPixels || checkBitmapPixels); |
| 176 | 163 |
| 164 const SkColorType ct = bitmap.colorType(); |
| 165 const SkAlphaType at = bitmap.alphaType(); |
| 166 |
| 177 int bw = bitmap.width(); | 167 int bw = bitmap.width(); |
| 178 int bh = bitmap.height(); | 168 int bh = bitmap.height(); |
| 179 | 169 |
| 180 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh); | 170 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh); |
| 181 SkIRect clippedSrcRect = DEV_RECT; | 171 SkIRect clippedSrcRect = DEV_RECT; |
| 182 if (!clippedSrcRect.intersect(srcRect)) { | 172 if (!clippedSrcRect.intersect(srcRect)) { |
| 183 clippedSrcRect.setEmpty(); | 173 clippedSrcRect.setEmpty(); |
| 184 } | 174 } |
| 185 SkAutoLockPixels alp(bitmap); | 175 SkAutoLockPixels alp(bitmap); |
| 186 intptr_t pixels = reinterpret_cast<intptr_t>(bitmap.getPixels()); | |
| 187 for (int by = 0; by < bh; ++by) { | 176 for (int by = 0; by < bh; ++by) { |
| 188 for (int bx = 0; bx < bw; ++bx) { | 177 for (int bx = 0; bx < bw; ++bx) { |
| 189 int devx = bx + srcRect.fLeft; | 178 int devx = bx + srcRect.fLeft; |
| 190 int devy = by + srcRect.fTop; | 179 int devy = by + srcRect.fTop; |
| 191 | 180 |
| 192 uint32_t pixel = *reinterpret_cast<SkPMColor*>(pixels + by * bitmap.
rowBytes() + bx * bitmap.bytesPerPixel()); | 181 const uint32_t* pixel = bitmap.getAddr32(bx, by); |
| 193 | 182 |
| 194 if (clippedSrcRect.contains(devx, devy)) { | 183 if (clippedSrcRect.contains(devx, devy)) { |
| 195 if (checkCanvasPixels) { | 184 if (checkCanvasPixels) { |
| 196 SkPMColor canvasPixel = getCanvasColor(devx, devy); | 185 SkPMColor canvasPixel = getCanvasColor(devx, devy); |
| 197 bool didPremul; | 186 bool didPremul; |
| 198 SkPMColor pmPixel = convertConfig8888ToPMColor(config8888, p
ixel, &didPremul); | 187 SkPMColor pmPixel = convertToPMColor(ct, at, pixel, &didPrem
ul); |
| 199 bool check; | 188 bool check; |
| 200 REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvas
Pixel, didPremul)); | 189 REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvas
Pixel, didPremul)); |
| 201 if (!check) { | 190 if (!check) { |
| 202 return false; | 191 return false; |
| 203 } | 192 } |
| 204 } | 193 } |
| 205 } else if (checkBitmapPixels) { | 194 } else if (checkBitmapPixels) { |
| 206 REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw) == pixel); | 195 REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw) == *pixel); |
| 207 if (getBitmapColor(bx, by, bw) != pixel) { | 196 if (getBitmapColor(bx, by, bw) != *pixel) { |
| 208 return false; | 197 return false; |
| 209 } | 198 } |
| 210 } | 199 } |
| 211 } | 200 } |
| 212 } | 201 } |
| 213 return true; | 202 return true; |
| 214 } | 203 } |
| 215 | 204 |
| 216 enum BitmapInit { | 205 enum BitmapInit { |
| 217 kFirstBitmapInit = 0, | 206 kFirstBitmapInit = 0, |
| 218 | 207 |
| 219 kNoPixels_BitmapInit = kFirstBitmapInit, | 208 kNoPixels_BitmapInit = kFirstBitmapInit, |
| 220 kTight_BitmapInit, | 209 kTight_BitmapInit, |
| 221 kRowBytes_BitmapInit, | 210 kRowBytes_BitmapInit, |
| 222 | 211 |
| 223 kBitmapInitCnt | 212 kBitmapInitCnt |
| 224 }; | 213 }; |
| 225 | 214 |
| 226 static BitmapInit nextBMI(BitmapInit bmi) { | 215 static BitmapInit nextBMI(BitmapInit bmi) { |
| 227 int x = bmi; | 216 int x = bmi; |
| 228 return static_cast<BitmapInit>(++x); | 217 return static_cast<BitmapInit>(++x); |
| 229 } | 218 } |
| 230 | 219 |
| 231 static void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init)
{ | 220 static void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init,
SkColorType ct, |
| 232 SkImageInfo info = SkImageInfo::MakeN32Premul(rect.width(), rect.height()); | 221 SkAlphaType at) { |
| 222 SkImageInfo info = SkImageInfo::Make(rect.width(), rect.height(), ct, at); |
| 233 size_t rowBytes = 0; | 223 size_t rowBytes = 0; |
| 234 bool alloc = true; | 224 bool alloc = true; |
| 235 switch (init) { | 225 switch (init) { |
| 236 case kNoPixels_BitmapInit: | 226 case kNoPixels_BitmapInit: |
| 237 alloc = false; | 227 alloc = false; |
| 238 case kTight_BitmapInit: | 228 case kTight_BitmapInit: |
| 239 break; | 229 break; |
| 240 case kRowBytes_BitmapInit: | 230 case kRowBytes_BitmapInit: |
| 241 rowBytes = (info.width() + 16) * sizeof(SkPMColor); | 231 rowBytes = (info.width() + 16) * sizeof(SkPMColor); |
| 242 break; | 232 break; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 GrAutoScratchTexture ast(context, desc, GrContext::kExact_Scratc
hTexMatch); | 323 GrAutoScratchTexture ast(context, desc, GrContext::kExact_Scratc
hTexMatch); |
| 334 SkAutoTUnref<GrTexture> tex(ast.detach()); | 324 SkAutoTUnref<GrTexture> tex(ast.detach()); |
| 335 device.reset(new SkGpuDevice(context, tex)); | 325 device.reset(new SkGpuDevice(context, tex)); |
| 336 #else | 326 #else |
| 337 continue; | 327 continue; |
| 338 #endif | 328 #endif |
| 339 } | 329 } |
| 340 SkCanvas canvas(device); | 330 SkCanvas canvas(device); |
| 341 fillCanvas(&canvas); | 331 fillCanvas(&canvas); |
| 342 | 332 |
| 343 static const SkCanvas::Config8888 gReadConfigs[] = { | 333 static const struct { |
| 344 SkCanvas::kNative_Premul_Config8888, | 334 SkColorType fColorType; |
| 345 SkCanvas::kNative_Unpremul_Config8888, | 335 SkAlphaType fAlphaType; |
| 346 | 336 } gReadConfigs[] = { |
| 347 SkCanvas::kBGRA_Premul_Config8888, | 337 { kRGBA_8888_SkColorType, kPremul_SkAlphaType }, |
| 348 SkCanvas::kBGRA_Unpremul_Config8888, | 338 { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType }, |
| 349 | 339 { kBGRA_8888_SkColorType, kPremul_SkAlphaType }, |
| 350 SkCanvas::kRGBA_Premul_Config8888, | 340 { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType }, |
| 351 SkCanvas::kRGBA_Unpremul_Config8888, | |
| 352 }; | 341 }; |
| 353 for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) { | 342 for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) { |
| 354 const SkIRect& srcRect = testRects[rect]; | 343 const SkIRect& srcRect = testRects[rect]; |
| 355 for (BitmapInit bmi = kFirstBitmapInit; | 344 for (BitmapInit bmi = kFirstBitmapInit; bmi < kBitmapInitCnt; bm
i = nextBMI(bmi)) { |
| 356 bmi < kBitmapInitCnt; | |
| 357 bmi = nextBMI(bmi)) { | |
| 358 for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) { | 345 for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) { |
| 359 SkCanvas::Config8888 config8888 = gReadConfigs[c]; | |
| 360 SkBitmap bmp; | 346 SkBitmap bmp; |
| 361 init_bitmap(&bmp, srcRect, bmi); | 347 init_bitmap(&bmp, srcRect, bmi, |
| 348 gReadConfigs[c].fColorType, gReadConfigs[c].
fAlphaType); |
| 362 | 349 |
| 363 // if the bitmap has pixels allocated before the readPix
els, | 350 // if the bitmap has pixels allocated before the readPix
els, |
| 364 // note that and fill them with pattern | 351 // note that and fill them with pattern |
| 365 bool startsWithPixels = !bmp.isNull(); | 352 bool startsWithPixels = !bmp.isNull(); |
| 366 if (startsWithPixels) { | 353 if (startsWithPixels) { |
| 367 fillBitmap(&bmp); | 354 fillBitmap(&bmp); |
| 368 } | 355 } |
| 369 uint32_t idBefore = canvas.getDevice()->accessBitmap(fal
se).getGenerationID(); | 356 uint32_t idBefore = canvas.getDevice()->accessBitmap(fal
se).getGenerationID(); |
| 370 bool success = | 357 bool success = canvas.readPixels(&bmp, srcRect.fLeft, sr
cRect.fTop); |
| 371 canvas.readPixels(&bmp, srcRect.fLeft, | |
| 372 srcRect.fTop, config8888); | |
| 373 uint32_t idAfter = canvas.getDevice()->accessBitmap(fals
e).getGenerationID(); | 358 uint32_t idAfter = canvas.getDevice()->accessBitmap(fals
e).getGenerationID(); |
| 374 | 359 |
| 375 // we expect to succeed when the read isn't fully clippe
d | 360 // we expect to succeed when the read isn't fully clippe
d |
| 376 // out. | 361 // out. |
| 377 bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RE
CT); | 362 bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RE
CT); |
| 378 // determine whether we expected the read to succeed. | 363 // determine whether we expected the read to succeed. |
| 379 REPORTER_ASSERT(reporter, success == expectSuccess); | 364 REPORTER_ASSERT(reporter, success == expectSuccess); |
| 380 // read pixels should never change the gen id | 365 // read pixels should never change the gen id |
| 381 REPORTER_ASSERT(reporter, idBefore == idAfter); | 366 REPORTER_ASSERT(reporter, idBefore == idAfter); |
| 382 | 367 |
| 383 if (success || startsWithPixels) { | 368 if (success || startsWithPixels) { |
| 384 checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop
, | 369 checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop
, |
| 385 success, startsWithPixels, config8888); | 370 success, startsWithPixels); |
| 386 } else { | 371 } else { |
| 387 // if we had no pixels beforehand and the readPixels | 372 // if we had no pixels beforehand and the readPixels |
| 388 // failed then our bitmap should still not have pixe
ls | 373 // failed then our bitmap should still not have pixe
ls |
| 389 REPORTER_ASSERT(reporter, bmp.isNull()); | 374 REPORTER_ASSERT(reporter, bmp.isNull()); |
| 390 } | 375 } |
| 391 } | 376 } |
| 392 // check the old webkit version of readPixels that clips the | 377 // check the old webkit version of readPixels that clips the |
| 393 // bitmap size | 378 // bitmap size |
| 394 SkBitmap wkbmp; | 379 SkBitmap wkbmp; |
| 395 bool success = canvas.readPixels(srcRect, &wkbmp); | 380 bool success = canvas.readPixels(srcRect, &wkbmp); |
| 396 SkIRect clippedRect = DEV_RECT; | 381 SkIRect clippedRect = DEV_RECT; |
| 397 if (clippedRect.intersect(srcRect)) { | 382 if (clippedRect.intersect(srcRect)) { |
| 398 REPORTER_ASSERT(reporter, success); | 383 REPORTER_ASSERT(reporter, success); |
| 384 REPORTER_ASSERT(reporter, kPMColor_SkColorType == wkbmp.
colorType()); |
| 385 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == wkbmp.a
lphaType()); |
| 399 checkRead(reporter, wkbmp, clippedRect.fLeft, | 386 checkRead(reporter, wkbmp, clippedRect.fLeft, |
| 400 clippedRect.fTop, true, false, | 387 clippedRect.fTop, true, false); |
| 401 SkCanvas::kNative_Premul_Config8888); | |
| 402 } else { | 388 } else { |
| 403 REPORTER_ASSERT(reporter, !success); | 389 REPORTER_ASSERT(reporter, !success); |
| 404 } | 390 } |
| 405 } | 391 } |
| 406 } | 392 } |
| 407 } | 393 } |
| 408 } | 394 } |
| 409 } | 395 } |
| OLD | NEW |