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