SkDevice.cpp revision 6850eab42ba4c2a7033a99824b02a2846ce0ef2a
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#include "SkDevice.h" 9#include "SkDraw.h" 10#include "SkMetaData.h" 11#include "SkRect.h" 12 13/////////////////////////////////////////////////////////////////////////////// 14 15SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) { 16 fOrigin.setZero(); 17 fMetaData = NULL; 18} 19 20SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) { 21 fOrigin.setZero(); 22 fMetaData = NULL; 23 24 fBitmap.setConfig(config, width, height); 25 fBitmap.allocPixels(); 26 fBitmap.setIsOpaque(isOpaque); 27 if (!isOpaque) { 28 fBitmap.eraseColor(0); 29 } 30} 31 32SkDevice::~SkDevice() { 33 delete fMetaData; 34} 35 36SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config, 37 int width, int height, 38 bool isOpaque) { 39 return this->onCreateCompatibleDevice(config, width, height, 40 isOpaque, kGeneral_Usage); 41} 42 43SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config, 44 int width, int height, 45 bool isOpaque) { 46 return this->onCreateCompatibleDevice(config, width, height, 47 isOpaque, kSaveLayer_Usage); 48} 49 50SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config, 51 int width, int height, 52 bool isOpaque, 53 Usage usage) { 54 return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque)); 55} 56 57SkMetaData& SkDevice::getMetaData() { 58 // metadata users are rare, so we lazily allocate it. If that changes we 59 // can decide to just make it a field in the device (rather than a ptr) 60 if (NULL == fMetaData) { 61 fMetaData = new SkMetaData; 62 } 63 return *fMetaData; 64} 65 66void SkDevice::lockPixels() { 67 if (fBitmap.lockPixelsAreWritable()) { 68 fBitmap.lockPixels(); 69 } 70} 71 72void SkDevice::unlockPixels() { 73 if (fBitmap.lockPixelsAreWritable()) { 74 fBitmap.unlockPixels(); 75 } 76} 77 78const SkBitmap& SkDevice::accessBitmap(bool changePixels) { 79 this->onAccessBitmap(&fBitmap); 80 if (changePixels) { 81 fBitmap.notifyPixelsChanged(); 82 } 83 return fBitmap; 84} 85 86void SkDevice::getGlobalBounds(SkIRect* bounds) const { 87 if (bounds) { 88 bounds->setXYWH(fOrigin.x(), fOrigin.y(), 89 fBitmap.width(), fBitmap.height()); 90 } 91} 92 93void SkDevice::clear(SkColor color) { 94 fBitmap.eraseColor(color); 95} 96 97void SkDevice::onAccessBitmap(SkBitmap* bitmap) {} 98 99void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region, 100 const SkClipStack& clipStack) { 101} 102 103/////////////////////////////////////////////////////////////////////////////// 104 105bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y, 106 SkCanvas::Config8888 config8888) { 107 if (SkBitmap::kARGB_8888_Config != bitmap->config() || 108 NULL != bitmap->getTexture()) { 109 return false; 110 } 111 112 const SkBitmap& src = this->accessBitmap(false); 113 114 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(), 115 bitmap->height()); 116 SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height()); 117 if (!srcRect.intersect(devbounds)) { 118 return false; 119 } 120 121 SkBitmap tmp; 122 SkBitmap* bmp; 123 if (bitmap->isNull()) { 124 tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(), 125 bitmap->height()); 126 if (!tmp.allocPixels()) { 127 return false; 128 } 129 bmp = &tmp; 130 } else { 131 bmp = bitmap; 132 } 133 134 SkIRect subrect = srcRect; 135 subrect.offset(-x, -y); 136 SkBitmap bmpSubset; 137 bmp->extractSubset(&bmpSubset, subrect); 138 139 bool result = this->onReadPixels(bmpSubset, 140 srcRect.fLeft, 141 srcRect.fTop, 142 config8888); 143 if (result && bmp == &tmp) { 144 tmp.swap(*bitmap); 145 } 146 return result; 147} 148 149#ifdef SK_CPU_LENDIAN 150 #if 24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \ 151 8 == SK_G32_SHIFT && 0 == SK_B32_SHIFT 152 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 153 SkCanvas::kBGRA_Premul_Config8888; 154 #elif 24 == SK_A32_SHIFT && 0 == SK_R32_SHIFT && \ 155 8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT 156 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 157 SkCanvas::kRGBA_Premul_Config8888; 158 #else 159 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 160 (SkCanvas::Config8888) -1; 161 #endif 162 static const int NATIVE_A_IDX = SK_A32_SHIFT / 8; 163 static const int NATIVE_R_IDX = SK_R32_SHIFT / 8; 164 static const int NATIVE_G_IDX = SK_G32_SHIFT / 8; 165 static const int NATIVE_B_IDX = SK_B32_SHIFT / 8; 166#else 167 #if 0 == SK_A32_SHIFT && 8 == SK_R32_SHIFT && \ 168 16 == SK_G32_SHIFT && 24 == SK_B32_SHIFT 169 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 170 SkCanvas::kBGRA_Premul_Config8888; 171 #elif 0 == SK_A32_SHIFT && 24 == SK_R32_SHIFT && \ 172 16 == SK_G32_SHIFT && 8 == SK_B32_SHIFT 173 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 174 SkCanvas::kRGBA_Premul_Config8888; 175 #else 176 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 177 (SkCanvas::Config8888) -1; 178 #endif 179 static const int NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8); 180 static const int NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8); 181 static const int NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8); 182 static const int NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8); 183#endif 184 185#include <SkColorPriv.h> 186 187namespace { 188 189template <int A_IDX, int R_IDX, int G_IDX, int B_IDX> 190inline uint32_t pack_config8888(uint32_t a, uint32_t r, 191 uint32_t g, uint32_t b) { 192#ifdef SK_CPU_LENDIAN 193 return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) | 194 (g << (G_IDX * 8)) | (b << (B_IDX * 8)); 195#else 196 return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) | 197 (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8)); 198#endif 199} 200 201template <bool UNPM, int A_IDX, int R_IDX, int G_IDX, int B_IDX> 202inline void bitmap_copy_to_config8888(const SkBitmap& srcBmp, 203 uint32_t* dstPixels, 204 size_t dstRowBytes) { 205 SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config()); 206 SkAutoLockPixels alp(srcBmp); 207 int w = srcBmp.width(); 208 int h = srcBmp.height(); 209 size_t srcRowBytes = srcBmp.rowBytes(); 210 211 intptr_t src = reinterpret_cast<intptr_t>(srcBmp.getPixels()); 212 intptr_t dst = reinterpret_cast<intptr_t>(dstPixels); 213 214 for (int y = 0; y < h; ++y) { 215 const SkPMColor* srcRow = reinterpret_cast<SkPMColor*>(src); 216 uint32_t* dstRow = reinterpret_cast<uint32_t*>(dst); 217 for (int x = 0; x < w; ++x) { 218 SkPMColor pmcolor = srcRow[x]; 219 if (UNPM) { 220 U8CPU a, r, g, b; 221 a = SkGetPackedA32(pmcolor); 222 if (a) { 223 // We're doing the explicit divide to match WebKit layout 224 // test expectations. We can modify and rebaseline if there 225 // it can be shown that there is a more performant way to 226 // unpremul. 227 r = SkGetPackedR32(pmcolor) * 0xff / a; 228 g = SkGetPackedG32(pmcolor) * 0xff / a; 229 b = SkGetPackedB32(pmcolor) * 0xff / a; 230 dstRow[x] = pack_config8888<A_IDX, R_IDX, 231 G_IDX, B_IDX>(a, r, g, b); 232 } else { 233 dstRow[x] = 0; 234 } 235 } else { 236 dstRow[x] = pack_config8888<A_IDX, R_IDX, 237 G_IDX, B_IDX>( 238 SkGetPackedA32(pmcolor), 239 SkGetPackedR32(pmcolor), 240 SkGetPackedG32(pmcolor), 241 SkGetPackedB32(pmcolor)); 242 } 243 } 244 dst += dstRowBytes; 245 src += srcRowBytes; 246 } 247} 248 249inline void bitmap_copy_to_native(const SkBitmap& srcBmp, 250 uint32_t* dstPixels, 251 size_t dstRowBytes) { 252 SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config()); 253 254 SkAutoLockPixels alp(srcBmp); 255 256 int w = srcBmp.width(); 257 int h = srcBmp.height(); 258 size_t srcRowBytes = srcBmp.rowBytes(); 259 260 size_t tightRowBytes = w * 4; 261 262 char* src = reinterpret_cast<char*>(srcBmp.getPixels()); 263 char* dst = reinterpret_cast<char*>(dstPixels); 264 265 if (tightRowBytes == srcRowBytes && 266 tightRowBytes == dstRowBytes) { 267 memcpy(dst, src, tightRowBytes * h); 268 } else { 269 for (int y = 0; y < h; ++y) { 270 memcpy(dst, src, tightRowBytes); 271 dst += dstRowBytes; 272 src += srcRowBytes; 273 } 274 } 275} 276 277} 278 279bool SkDevice::onReadPixels(const SkBitmap& bitmap, 280 int x, int y, 281 SkCanvas::Config8888 config8888) { 282 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 283 SkASSERT(!bitmap.isNull()); 284 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))); 285 286 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), 287 bitmap.height()); 288 const SkBitmap& src = this->accessBitmap(false); 289 290 SkBitmap subset; 291 if (!src.extractSubset(&subset, srcRect)) { 292 return false; 293 } 294 if (SkBitmap::kARGB_8888_Config != subset.config()) { 295 // It'd be preferable to do this directly to bitmap. 296 subset.copyTo(&subset, SkBitmap::kARGB_8888_Config); 297 } 298 SkAutoLockPixels alp(bitmap); 299 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); 300 if ((SkCanvas::kNative_Premul_Config8888 == config8888 || 301 kPMColorAlias == config8888)) { 302 bitmap_copy_to_native(subset, bmpPixels, bitmap.rowBytes()); 303 } else { 304 switch (config8888) { 305 case SkCanvas::kNative_Premul_Config8888: 306 bitmap_copy_to_config8888<false, 307 NATIVE_A_IDX, NATIVE_R_IDX, 308 NATIVE_G_IDX, NATIVE_B_IDX>( 309 subset, 310 bmpPixels, 311 bitmap.rowBytes()); 312 break; 313 case SkCanvas::kNative_Unpremul_Config8888: 314 bitmap_copy_to_config8888<true, 315 NATIVE_A_IDX, NATIVE_R_IDX, 316 NATIVE_G_IDX, NATIVE_B_IDX>( 317 subset, 318 bmpPixels, 319 bitmap.rowBytes()); 320 break; 321 case SkCanvas::kBGRA_Premul_Config8888: 322 bitmap_copy_to_config8888<false, 3, 2, 1, 0> ( 323 subset, bmpPixels, bitmap.rowBytes()); 324 break; 325 case SkCanvas::kBGRA_Unpremul_Config8888: 326 bitmap_copy_to_config8888<true, 3, 2, 1, 0> ( 327 subset, bmpPixels, bitmap.rowBytes()); 328 break; 329 case SkCanvas::kRGBA_Premul_Config8888: 330 bitmap_copy_to_config8888<false, 3, 0, 1, 2> ( 331 subset, bmpPixels, bitmap.rowBytes()); 332 break; 333 case SkCanvas::kRGBA_Unpremul_Config8888: 334 bitmap_copy_to_config8888<true, 3, 0, 1, 2> ( 335 subset, bmpPixels, bitmap.rowBytes()); 336 break; 337 default: 338 SkASSERT(false && "unexpected Config8888"); 339 break; 340 } 341 } 342 return true; 343} 344 345void SkDevice::writePixels(const SkBitmap& bitmap, int x, int y) { 346 SkPaint paint; 347 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 348 349 SkCanvas canvas(this); 350 canvas.drawSprite(bitmap, x, y, &paint); 351} 352 353/////////////////////////////////////////////////////////////////////////////// 354 355void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 356 draw.drawPaint(paint); 357} 358 359void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 360 const SkPoint pts[], const SkPaint& paint) { 361 draw.drawPoints(mode, count, pts, paint); 362} 363 364void SkDevice::drawRect(const SkDraw& draw, const SkRect& r, 365 const SkPaint& paint) { 366 draw.drawRect(r, paint); 367} 368 369void SkDevice::drawPath(const SkDraw& draw, const SkPath& path, 370 const SkPaint& paint, const SkMatrix* prePathMatrix, 371 bool pathIsMutable) { 372 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 373} 374 375void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 376 const SkIRect* srcRect, 377 const SkMatrix& matrix, const SkPaint& paint) { 378 SkBitmap tmp; // storage if we need a subset of bitmap 379 const SkBitmap* bitmapPtr = &bitmap; 380 381 if (srcRect) { 382 if (!bitmap.extractSubset(&tmp, *srcRect)) { 383 return; // extraction failed 384 } 385 bitmapPtr = &tmp; 386 } 387 draw.drawBitmap(*bitmapPtr, matrix, paint); 388} 389 390void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 391 int x, int y, const SkPaint& paint) { 392 draw.drawSprite(bitmap, x, y, paint); 393} 394 395void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len, 396 SkScalar x, SkScalar y, const SkPaint& paint) { 397 draw.drawText((const char*)text, len, x, y, paint); 398} 399 400void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 401 const SkScalar xpos[], SkScalar y, 402 int scalarsPerPos, const SkPaint& paint) { 403 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); 404} 405 406void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text, 407 size_t len, const SkPath& path, 408 const SkMatrix* matrix, 409 const SkPaint& paint) { 410 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); 411} 412 413#ifdef ANDROID 414void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len, 415 const SkPoint pos[], const SkPaint& paint, 416 const SkPath& path, const SkMatrix* matrix) { 417 draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix); 418} 419#endif 420 421void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 422 int vertexCount, 423 const SkPoint verts[], const SkPoint textures[], 424 const SkColor colors[], SkXfermode* xmode, 425 const uint16_t indices[], int indexCount, 426 const SkPaint& paint) { 427 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 428 indices, indexCount, paint); 429} 430 431void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device, 432 int x, int y, const SkPaint& paint) { 433 draw.drawSprite(device->accessBitmap(false), x, y, paint); 434} 435 436/////////////////////////////////////////////////////////////////////////////// 437 438bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 439 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 440 // we're cool with the paint as is 441 return false; 442 } 443 444 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || 445 paint.getShader() || 446 paint.getXfermode() || // unless its srcover 447 paint.getMaskFilter() || 448 paint.getRasterizer() || 449 paint.getColorFilter() || 450 paint.getPathEffect() || 451 paint.isFakeBoldText() || 452 paint.getStyle() != SkPaint::kFill_Style) { 453 // turn off lcd 454 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 455 flags->fHinting = paint.getHinting(); 456 return true; 457 } 458 // we're cool with the paint as is 459 return false; 460} 461 462