1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include "Test.h" 10 #include "SkCanvas.h" 11 #include "SkColorPriv.h" 12 #include "SkDevice.h" 13 #include "SkMathPriv.h" 14 #include "SkRegion.h" 15 #if SK_SUPPORT_GPU 16 #include "SkGpuDevice.h" 17 #endif 18 19 20 static const int DEV_W = 100, DEV_H = 100; 21 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H); 22 static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1, 23 DEV_H * SK_Scalar1); 24 25 namespace { 26 SkPMColor getCanvasColor(int x, int y) { 27 SkASSERT(x >= 0 && x < DEV_W); 28 SkASSERT(y >= 0 && y < DEV_H); 29 30 U8CPU r = x; 31 U8CPU g = y; 32 U8CPU b = 0xc; 33 34 U8CPU a = 0xff; 35 switch ((x+y) % 5) { 36 case 0: 37 a = 0xff; 38 break; 39 case 1: 40 a = 0x80; 41 break; 42 case 2: 43 a = 0xCC; 44 break; 45 case 4: 46 a = 0x01; 47 break; 48 case 3: 49 a = 0x00; 50 break; 51 } 52 return SkPremultiplyARGBInline(a, r, g, b); 53 } 54 55 SkPMColor getBitmapColor(int x, int y, int w, int h) { 56 int n = y * w + x; 57 58 U8CPU b = n & 0xff; 59 U8CPU g = (n >> 8) & 0xff; 60 U8CPU r = (n >> 16) & 0xff; 61 return SkPackARGB32(0xff, r, g , b); 62 } 63 64 SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888, 65 uint32_t color, 66 bool* premul) { 67 const uint8_t* c = reinterpret_cast<uint8_t*>(&color); 68 U8CPU a,r,g,b; 69 *premul = false; 70 switch (config8888) { 71 case SkCanvas::kNative_Premul_Config8888: 72 return color; 73 case SkCanvas::kNative_Unpremul_Config8888: 74 *premul = true; 75 a = SkGetPackedA32(color); 76 r = SkGetPackedR32(color); 77 g = SkGetPackedG32(color); 78 b = SkGetPackedB32(color); 79 break; 80 case SkCanvas::kBGRA_Unpremul_Config8888: 81 *premul = true; // fallthru 82 case SkCanvas::kBGRA_Premul_Config8888: 83 a = static_cast<U8CPU>(c[3]); 84 r = static_cast<U8CPU>(c[2]); 85 g = static_cast<U8CPU>(c[1]); 86 b = static_cast<U8CPU>(c[0]); 87 break; 88 case SkCanvas::kRGBA_Unpremul_Config8888: 89 *premul = true; // fallthru 90 case SkCanvas::kRGBA_Premul_Config8888: 91 a = static_cast<U8CPU>(c[3]); 92 r = static_cast<U8CPU>(c[0]); 93 g = static_cast<U8CPU>(c[1]); 94 b = static_cast<U8CPU>(c[2]); 95 break; 96 default: 97 SkDEBUGFAIL("Unexpected Config8888"); 98 return 0; 99 } 100 if (*premul) { 101 r = SkMulDiv255Ceiling(r, a); 102 g = SkMulDiv255Ceiling(g, a); 103 b = SkMulDiv255Ceiling(b, a); 104 } 105 return SkPackARGB32(a, r, g, b); 106 } 107 108 void fillCanvas(SkCanvas* canvas) { 109 static SkBitmap bmp; 110 if (bmp.isNull()) { 111 bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H); 112 SkDEBUGCODE(bool alloc =) bmp.allocPixels(); 113 SkASSERT(alloc); 114 SkAutoLockPixels alp(bmp); 115 intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels()); 116 for (int y = 0; y < DEV_H; ++y) { 117 for (int x = 0; x < DEV_W; ++x) { 118 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel()); 119 *pixel = getCanvasColor(x, y); 120 } 121 } 122 } 123 canvas->save(); 124 canvas->setMatrix(SkMatrix::I()); 125 canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op); 126 SkPaint paint; 127 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 128 canvas->drawBitmap(bmp, 0, 0, &paint); 129 canvas->restore(); 130 } 131 132 void fillBitmap(SkBitmap* bitmap) { 133 SkASSERT(bitmap->lockPixelsAreWritable()); 134 SkAutoLockPixels alp(*bitmap); 135 int w = bitmap->width(); 136 int h = bitmap->height(); 137 intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels()); 138 for (int y = 0; y < h; ++y) { 139 for (int x = 0; x < w; ++x) { 140 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel()); 141 *pixel = getBitmapColor(x, y, w, h); 142 } 143 } 144 } 145 146 bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) { 147 if (!didPremulConversion) { 148 return a == b; 149 } 150 int32_t aA = static_cast<int32_t>(SkGetPackedA32(a)); 151 int32_t aR = static_cast<int32_t>(SkGetPackedR32(a)); 152 int32_t aG = static_cast<int32_t>(SkGetPackedG32(a)); 153 int32_t aB = SkGetPackedB32(a); 154 155 int32_t bA = static_cast<int32_t>(SkGetPackedA32(b)); 156 int32_t bR = static_cast<int32_t>(SkGetPackedR32(b)); 157 int32_t bG = static_cast<int32_t>(SkGetPackedG32(b)); 158 int32_t bB = static_cast<int32_t>(SkGetPackedB32(b)); 159 160 return aA == bA && 161 SkAbs32(aR - bR) <= 1 && 162 SkAbs32(aG - bG) <= 1 && 163 SkAbs32(aB - bB) <= 1; 164 } 165 166 // checks the bitmap contains correct pixels after the readPixels 167 // if the bitmap was prefilled with pixels it checks that these weren't 168 // overwritten in the area outside the readPixels. 169 bool checkRead(skiatest::Reporter* reporter, 170 const SkBitmap& bitmap, 171 int x, int y, 172 bool checkCanvasPixels, 173 bool checkBitmapPixels, 174 SkCanvas::Config8888 config8888) { 175 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 176 SkASSERT(!bitmap.isNull()); 177 SkASSERT(checkCanvasPixels || checkBitmapPixels); 178 179 int bw = bitmap.width(); 180 int bh = bitmap.height(); 181 182 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh); 183 SkIRect clippedSrcRect = DEV_RECT; 184 if (!clippedSrcRect.intersect(srcRect)) { 185 clippedSrcRect.setEmpty(); 186 } 187 SkAutoLockPixels alp(bitmap); 188 intptr_t pixels = reinterpret_cast<intptr_t>(bitmap.getPixels()); 189 for (int by = 0; by < bh; ++by) { 190 for (int bx = 0; bx < bw; ++bx) { 191 int devx = bx + srcRect.fLeft; 192 int devy = by + srcRect.fTop; 193 194 uint32_t pixel = *reinterpret_cast<SkPMColor*>(pixels + by * bitmap.rowBytes() + bx * bitmap.bytesPerPixel()); 195 196 if (clippedSrcRect.contains(devx, devy)) { 197 if (checkCanvasPixels) { 198 SkPMColor canvasPixel = getCanvasColor(devx, devy); 199 bool didPremul; 200 SkPMColor pmPixel = convertConfig8888ToPMColor(config8888, pixel, &didPremul); 201 bool check; 202 REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvasPixel, didPremul)); 203 if (!check) { 204 return false; 205 } 206 } 207 } else if (checkBitmapPixels) { 208 REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw, bh) == pixel); 209 if (getBitmapColor(bx, by, bw, bh) != pixel) { 210 return false; 211 } 212 } 213 } 214 } 215 return true; 216 } 217 218 enum BitmapInit { 219 kFirstBitmapInit = 0, 220 221 kNoPixels_BitmapInit = kFirstBitmapInit, 222 kTight_BitmapInit, 223 kRowBytes_BitmapInit, 224 225 kBitmapInitCnt 226 }; 227 228 BitmapInit nextBMI(BitmapInit bmi) { 229 int x = bmi; 230 return static_cast<BitmapInit>(++x); 231 } 232 233 234 void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init) { 235 int w = rect.width(); 236 int h = rect.height(); 237 int rowBytes = 0; 238 bool alloc = true; 239 switch (init) { 240 case kNoPixels_BitmapInit: 241 alloc = false; 242 case kTight_BitmapInit: 243 break; 244 case kRowBytes_BitmapInit: 245 rowBytes = w * sizeof(SkPMColor) + 16 * sizeof(SkPMColor); 246 break; 247 default: 248 SkASSERT(0); 249 break; 250 } 251 bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes); 252 if (alloc) { 253 bitmap->allocPixels(); 254 } 255 } 256 257 void ReadPixelsTest(skiatest::Reporter* reporter, GrContext* context) { 258 const SkIRect testRects[] = { 259 // entire thing 260 DEV_RECT, 261 // larger on all sides 262 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10), 263 // fully contained 264 SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4), 265 // outside top left 266 SkIRect::MakeLTRB(-10, -10, -1, -1), 267 // touching top left corner 268 SkIRect::MakeLTRB(-10, -10, 0, 0), 269 // overlapping top left corner 270 SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4), 271 // overlapping top left and top right corners 272 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4), 273 // touching entire top edge 274 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0), 275 // overlapping top right corner 276 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4), 277 // contained in x, overlapping top edge 278 SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4), 279 // outside top right corner 280 SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1), 281 // touching top right corner 282 SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0), 283 // overlapping top left and bottom left corners 284 SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10), 285 // touching entire left edge 286 SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10), 287 // overlapping bottom left corner 288 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10), 289 // contained in y, overlapping left edge 290 SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4), 291 // outside bottom left corner 292 SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10), 293 // touching bottom left corner 294 SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10), 295 // overlapping bottom left and bottom right corners 296 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), 297 // touching entire left edge 298 SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10), 299 // overlapping bottom right corner 300 SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), 301 // overlapping top right and bottom right corners 302 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10), 303 }; 304 305 for (int dtype = 0; dtype < 2; ++dtype) { 306 SkAutoTUnref<SkDevice> device; 307 if (0 == dtype) { 308 device.reset(new SkDevice(SkBitmap::kARGB_8888_Config, 309 DEV_W, 310 DEV_H, 311 false)); 312 } else { 313 // GPU device known not to work in the fixed pt build. 314 #if defined(SK_SCALAR_IS_FIXED) || !SK_SUPPORT_GPU 315 continue; 316 #else 317 device.reset(new SkGpuDevice(context, 318 SkBitmap::kARGB_8888_Config, 319 DEV_W, 320 DEV_H)); 321 #endif 322 } 323 SkCanvas canvas(device); 324 fillCanvas(&canvas); 325 326 static const SkCanvas::Config8888 gReadConfigs[] = { 327 SkCanvas::kNative_Premul_Config8888, 328 SkCanvas::kNative_Unpremul_Config8888, 329 /** 330 * There is a bug in Ganesh (http://code.google.com/p/skia/issues/detail?id=438) 331 * that causes the readback of pixels from BGRA canvas to an RGBA bitmap to 332 * fail. This should be removed as soon as the issue above is resolved. 333 */ 334 #if !defined(SK_BUILD_FOR_ANDROID) 335 SkCanvas::kBGRA_Premul_Config8888, 336 SkCanvas::kBGRA_Unpremul_Config8888, 337 #endif 338 SkCanvas::kRGBA_Premul_Config8888, 339 SkCanvas::kRGBA_Unpremul_Config8888, 340 }; 341 for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) { 342 const SkIRect& srcRect = testRects[rect]; 343 for (BitmapInit bmi = kFirstBitmapInit; 344 bmi < kBitmapInitCnt; 345 bmi = nextBMI(bmi)) { 346 for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) { 347 SkCanvas::Config8888 config8888 = gReadConfigs[c]; 348 SkBitmap bmp; 349 init_bitmap(&bmp, srcRect, bmi); 350 351 // if the bitmap has pixels allocated before the readPixels, 352 // note that and fill them with pattern 353 bool startsWithPixels = !bmp.isNull(); 354 if (startsWithPixels) { 355 fillBitmap(&bmp); 356 } 357 uint32_t idBefore = canvas.getDevice()->accessBitmap(false).getGenerationID(); 358 bool success = 359 canvas.readPixels(&bmp, srcRect.fLeft, 360 srcRect.fTop, config8888); 361 uint32_t idAfter = canvas.getDevice()->accessBitmap(false).getGenerationID(); 362 363 // we expect to succeed when the read isn't fully clipped 364 // out. 365 bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RECT); 366 // determine whether we expected the read to succeed. 367 REPORTER_ASSERT(reporter, success == expectSuccess); 368 // read pixels should never change the gen id 369 REPORTER_ASSERT(reporter, idBefore == idAfter); 370 371 if (success || startsWithPixels) { 372 checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop, 373 success, startsWithPixels, config8888); 374 } else { 375 // if we had no pixels beforehand and the readPixels 376 // failed then our bitmap should still not have pixels 377 REPORTER_ASSERT(reporter, bmp.isNull()); 378 } 379 } 380 // check the old webkit version of readPixels that clips the 381 // bitmap size 382 SkBitmap wkbmp; 383 bool success = canvas.readPixels(srcRect, &wkbmp); 384 SkIRect clippedRect = DEV_RECT; 385 if (clippedRect.intersect(srcRect)) { 386 REPORTER_ASSERT(reporter, success); 387 checkRead(reporter, wkbmp, clippedRect.fLeft, 388 clippedRect.fTop, true, false, 389 SkCanvas::kNative_Premul_Config8888); 390 } else { 391 REPORTER_ASSERT(reporter, !success); 392 } 393 } 394 } 395 } 396 } 397 } 398 399 #include "TestClassDef.h" 400 DEFINE_GPUTESTCLASS("ReadPixels", ReadPixelsTestClass, ReadPixelsTest) 401