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 "SkDeviceProperties.h" 10 #include "SkDraw.h" 11 #include "SkImageFilter.h" 12 #include "SkMetaData.h" 13 #include "SkRasterClip.h" 14 #include "SkRect.h" 15 #include "SkRRect.h" 16 #include "SkShader.h" 17 18 SK_DEFINE_INST_COUNT(SkDevice) 19 20 /////////////////////////////////////////////////////////////////////////////// 21 22 #define CHECK_FOR_NODRAW_ANNOTATION(paint) \ 23 do { if (paint.isNoDrawAnnotation()) { return; } } while (0) 24 25 /////////////////////////////////////////////////////////////////////////////// 26 27 SkDevice::SkDevice(const SkBitmap& bitmap) 28 : fBitmap(bitmap), fLeakyProperties(SkDeviceProperties::MakeDefault()) 29 #ifdef SK_DEBUG 30 , fAttachedToCanvas(false) 31 #endif 32 { 33 fOrigin.setZero(); 34 fMetaData = NULL; 35 36 SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config()); 37 } 38 39 SkDevice::SkDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties) 40 : fBitmap(bitmap), fLeakyProperties(deviceProperties) 41 #ifdef SK_DEBUG 42 , fAttachedToCanvas(false) 43 #endif 44 { 45 fOrigin.setZero(); 46 fMetaData = NULL; 47 } 48 49 SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) 50 : fLeakyProperties(SkDeviceProperties::MakeDefault()) 51 #ifdef SK_DEBUG 52 , fAttachedToCanvas(false) 53 #endif 54 { 55 fOrigin.setZero(); 56 fMetaData = NULL; 57 58 fBitmap.setConfig(config, width, height); 59 fBitmap.allocPixels(); 60 fBitmap.setIsOpaque(isOpaque); 61 if (!isOpaque) { 62 fBitmap.eraseColor(SK_ColorTRANSPARENT); 63 } 64 } 65 66 SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque, 67 const SkDeviceProperties& deviceProperties) 68 : fLeakyProperties(deviceProperties) 69 #ifdef SK_DEBUG 70 , fAttachedToCanvas(false) 71 #endif 72 { 73 fOrigin.setZero(); 74 fMetaData = NULL; 75 76 fBitmap.setConfig(config, width, height); 77 fBitmap.allocPixels(); 78 fBitmap.setIsOpaque(isOpaque); 79 if (!isOpaque) { 80 fBitmap.eraseColor(SK_ColorTRANSPARENT); 81 } 82 } 83 84 SkDevice::~SkDevice() { 85 delete fMetaData; 86 } 87 88 void SkDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { 89 SkASSERT(bm.width() == fBitmap.width()); 90 SkASSERT(bm.height() == fBitmap.height()); 91 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) 92 fBitmap.lockPixels(); 93 } 94 95 SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config, 96 int width, int height, 97 bool isOpaque) { 98 return this->onCreateCompatibleDevice(config, width, height, 99 isOpaque, kGeneral_Usage); 100 } 101 102 SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config, 103 int width, int height, 104 bool isOpaque) { 105 return this->onCreateCompatibleDevice(config, width, height, 106 isOpaque, kSaveLayer_Usage); 107 } 108 109 SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config, 110 int width, int height, 111 bool isOpaque, 112 Usage usage) { 113 return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque, fLeakyProperties)); 114 } 115 116 SkMetaData& SkDevice::getMetaData() { 117 // metadata users are rare, so we lazily allocate it. If that changes we 118 // can decide to just make it a field in the device (rather than a ptr) 119 if (NULL == fMetaData) { 120 fMetaData = new SkMetaData; 121 } 122 return *fMetaData; 123 } 124 125 void SkDevice::lockPixels() { 126 if (fBitmap.lockPixelsAreWritable()) { 127 fBitmap.lockPixels(); 128 } 129 } 130 131 void SkDevice::unlockPixels() { 132 if (fBitmap.lockPixelsAreWritable()) { 133 fBitmap.unlockPixels(); 134 } 135 } 136 137 const SkBitmap& SkDevice::accessBitmap(bool changePixels) { 138 const SkBitmap& bitmap = this->onAccessBitmap(&fBitmap); 139 if (changePixels) { 140 bitmap.notifyPixelsChanged(); 141 } 142 return bitmap; 143 } 144 145 void SkDevice::getGlobalBounds(SkIRect* bounds) const { 146 if (bounds) { 147 bounds->setXYWH(fOrigin.x(), fOrigin.y(), 148 fBitmap.width(), fBitmap.height()); 149 } 150 } 151 152 void SkDevice::clear(SkColor color) { 153 fBitmap.eraseColor(color); 154 } 155 156 const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;} 157 158 void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region, 159 const SkClipStack& clipStack) { 160 } 161 162 bool SkDevice::canHandleImageFilter(SkImageFilter*) { 163 return false; 164 } 165 166 bool SkDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, 167 const SkMatrix& ctm, SkBitmap* result, 168 SkIPoint* offset) { 169 return false; 170 } 171 172 bool SkDevice::allowImageFilter(SkImageFilter*) { 173 return true; 174 } 175 176 /////////////////////////////////////////////////////////////////////////////// 177 178 bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y, 179 SkCanvas::Config8888 config8888) { 180 if (SkBitmap::kARGB_8888_Config != bitmap->config() || 181 NULL != bitmap->getTexture()) { 182 return false; 183 } 184 185 const SkBitmap& src = this->accessBitmap(false); 186 187 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(), 188 bitmap->height()); 189 SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height()); 190 if (!srcRect.intersect(devbounds)) { 191 return false; 192 } 193 194 SkBitmap tmp; 195 SkBitmap* bmp; 196 if (bitmap->isNull()) { 197 tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(), 198 bitmap->height()); 199 if (!tmp.allocPixels()) { 200 return false; 201 } 202 bmp = &tmp; 203 } else { 204 bmp = bitmap; 205 } 206 207 SkIRect subrect = srcRect; 208 subrect.offset(-x, -y); 209 SkBitmap bmpSubset; 210 bmp->extractSubset(&bmpSubset, subrect); 211 212 bool result = this->onReadPixels(bmpSubset, 213 srcRect.fLeft, 214 srcRect.fTop, 215 config8888); 216 if (result && bmp == &tmp) { 217 tmp.swap(*bitmap); 218 } 219 return result; 220 } 221 222 #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) 223 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 224 SkCanvas::kBGRA_Premul_Config8888; 225 #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) 226 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 227 SkCanvas::kRGBA_Premul_Config8888; 228 #else 229 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 230 (SkCanvas::Config8888) -1; 231 #endif 232 233 #include <SkConfig8888.h> 234 235 bool SkDevice::onReadPixels(const SkBitmap& bitmap, 236 int x, int y, 237 SkCanvas::Config8888 config8888) { 238 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 239 SkASSERT(!bitmap.isNull()); 240 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))); 241 242 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), 243 bitmap.height()); 244 const SkBitmap& src = this->accessBitmap(false); 245 246 SkBitmap subset; 247 if (!src.extractSubset(&subset, srcRect)) { 248 return false; 249 } 250 if (SkBitmap::kARGB_8888_Config != subset.config()) { 251 // It'd be preferable to do this directly to bitmap. 252 subset.copyTo(&subset, SkBitmap::kARGB_8888_Config); 253 } 254 SkAutoLockPixels alp(bitmap); 255 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); 256 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); 257 return true; 258 } 259 260 void SkDevice::writePixels(const SkBitmap& bitmap, 261 int x, int y, 262 SkCanvas::Config8888 config8888) { 263 if (bitmap.isNull() || bitmap.getTexture()) { 264 return; 265 } 266 const SkBitmap* sprite = &bitmap; 267 // check whether we have to handle a config8888 that doesn't match SkPMColor 268 if (SkBitmap::kARGB_8888_Config == bitmap.config() && 269 SkCanvas::kNative_Premul_Config8888 != config8888 && 270 kPMColorAlias != config8888) { 271 272 // We're going to have to convert from a config8888 to the native config 273 // First we clip to the device bounds. 274 SkBitmap dstBmp = this->accessBitmap(true); 275 SkIRect spriteRect = SkIRect::MakeXYWH(x, y, 276 bitmap.width(), bitmap.height()); 277 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height()); 278 if (!spriteRect.intersect(devRect)) { 279 return; 280 } 281 282 // write directly to the device if it has pixels and is SkPMColor 283 bool drawSprite; 284 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) { 285 // we can write directly to the dst when doing the conversion 286 dstBmp.extractSubset(&dstBmp, spriteRect); 287 drawSprite = false; 288 } else { 289 // we convert to a temporary bitmap and draw that as a sprite 290 dstBmp.setConfig(SkBitmap::kARGB_8888_Config, 291 spriteRect.width(), 292 spriteRect.height()); 293 if (!dstBmp.allocPixels()) { 294 return; 295 } 296 drawSprite = true; 297 } 298 299 // copy pixels to dstBmp and convert from config8888 to native config. 300 SkAutoLockPixels alp(bitmap); 301 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x, 302 spriteRect.fTop - y); 303 SkCopyConfig8888ToBitmap(dstBmp, 304 srcPixels, 305 bitmap.rowBytes(), 306 config8888); 307 308 if (drawSprite) { 309 // we've clipped the sprite when we made a copy 310 x = spriteRect.fLeft; 311 y = spriteRect.fTop; 312 sprite = &dstBmp; 313 } else { 314 return; 315 } 316 } 317 318 SkPaint paint; 319 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 320 SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height())); 321 SkDraw draw; 322 draw.fRC = &clip; 323 draw.fClip = &clip.bwRgn(); 324 draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap 325 draw.fMatrix = &SkMatrix::I(); 326 this->drawSprite(draw, *sprite, x, y, paint); 327 } 328 329 /////////////////////////////////////////////////////////////////////////////// 330 331 void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 332 draw.drawPaint(paint); 333 } 334 335 void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 336 const SkPoint pts[], const SkPaint& paint) { 337 CHECK_FOR_NODRAW_ANNOTATION(paint); 338 draw.drawPoints(mode, count, pts, paint); 339 } 340 341 void SkDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { 342 CHECK_FOR_NODRAW_ANNOTATION(paint); 343 draw.drawRect(r, paint); 344 } 345 346 void SkDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 347 CHECK_FOR_NODRAW_ANNOTATION(paint); 348 349 SkPath path; 350 path.addOval(oval); 351 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 352 // required to override drawOval. 353 this->drawPath(draw, path, paint, NULL, true); 354 } 355 356 void SkDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { 357 CHECK_FOR_NODRAW_ANNOTATION(paint); 358 359 draw.drawRRect(rrect, paint); 360 } 361 362 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path, 363 const SkPaint& paint, const SkMatrix* prePathMatrix, 364 bool pathIsMutable) { 365 CHECK_FOR_NODRAW_ANNOTATION(paint); 366 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 367 } 368 369 void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 370 const SkMatrix& matrix, const SkPaint& paint) { 371 draw.drawBitmap(bitmap, matrix, paint); 372 } 373 374 void SkDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 375 const SkRect* src, const SkRect& dst, 376 const SkPaint& paint) { 377 SkMatrix matrix; 378 SkRect bitmapBounds, tmpSrc, tmpDst; 379 SkBitmap tmpBitmap; 380 381 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 382 383 // Compute matrix from the two rectangles 384 if (src) { 385 tmpSrc = *src; 386 } else { 387 tmpSrc = bitmapBounds; 388 } 389 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 390 391 const SkRect* dstPtr = &dst; 392 const SkBitmap* bitmapPtr = &bitmap; 393 394 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 395 // needed (if the src was clipped). No check needed if src==null. 396 if (src) { 397 if (!bitmapBounds.contains(*src)) { 398 if (!tmpSrc.intersect(bitmapBounds)) { 399 return; // nothing to draw 400 } 401 // recompute dst, based on the smaller tmpSrc 402 matrix.mapRect(&tmpDst, tmpSrc); 403 dstPtr = &tmpDst; 404 } 405 406 // since we may need to clamp to the borders of the src rect within 407 // the bitmap, we extract a subset. 408 SkIRect srcIR; 409 tmpSrc.roundOut(&srcIR); 410 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 411 return; 412 } 413 bitmapPtr = &tmpBitmap; 414 415 // Since we did an extract, we need to adjust the matrix accordingly 416 SkScalar dx = 0, dy = 0; 417 if (srcIR.fLeft > 0) { 418 dx = SkIntToScalar(srcIR.fLeft); 419 } 420 if (srcIR.fTop > 0) { 421 dy = SkIntToScalar(srcIR.fTop); 422 } 423 if (dx || dy) { 424 matrix.preTranslate(dx, dy); 425 } 426 427 SkRect extractedBitmapBounds; 428 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); 429 if (extractedBitmapBounds == tmpSrc) { 430 // no fractional part in src, we can just call drawBitmap 431 goto USE_DRAWBITMAP; 432 } 433 } else { 434 USE_DRAWBITMAP: 435 // We can go faster by just calling drawBitmap, which will concat the 436 // matrix with the CTM, and try to call drawSprite if it can. If not, 437 // it will make a shader and call drawRect, as we do below. 438 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 439 return; 440 } 441 442 // construct a shader, so we can call drawRect with the dst 443 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, 444 SkShader::kClamp_TileMode, 445 SkShader::kClamp_TileMode); 446 if (NULL == s) { 447 return; 448 } 449 s->setLocalMatrix(matrix); 450 451 SkPaint paintWithShader(paint); 452 paintWithShader.setStyle(SkPaint::kFill_Style); 453 paintWithShader.setShader(s)->unref(); 454 455 // Call ourself, in case the subclass wanted to share this setup code 456 // but handle the drawRect code themselves. 457 this->drawRect(draw, *dstPtr, paintWithShader); 458 } 459 460 void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 461 int x, int y, const SkPaint& paint) { 462 draw.drawSprite(bitmap, x, y, paint); 463 } 464 465 void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len, 466 SkScalar x, SkScalar y, const SkPaint& paint) { 467 draw.drawText((const char*)text, len, x, y, paint); 468 } 469 470 void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 471 const SkScalar xpos[], SkScalar y, 472 int scalarsPerPos, const SkPaint& paint) { 473 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); 474 } 475 476 void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text, 477 size_t len, const SkPath& path, 478 const SkMatrix* matrix, 479 const SkPaint& paint) { 480 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); 481 } 482 483 #ifdef SK_BUILD_FOR_ANDROID 484 void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len, 485 const SkPoint pos[], const SkPaint& paint, 486 const SkPath& path, const SkMatrix* matrix) { 487 draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix); 488 } 489 #endif 490 491 void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 492 int vertexCount, 493 const SkPoint verts[], const SkPoint textures[], 494 const SkColor colors[], SkXfermode* xmode, 495 const uint16_t indices[], int indexCount, 496 const SkPaint& paint) { 497 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 498 indices, indexCount, paint); 499 } 500 501 void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device, 502 int x, int y, const SkPaint& paint) { 503 const SkBitmap& src = device->accessBitmap(false); 504 draw.drawSprite(src, x, y, paint); 505 } 506 507 /////////////////////////////////////////////////////////////////////////////// 508 509 bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 510 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 511 // we're cool with the paint as is 512 return false; 513 } 514 515 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || 516 paint.getRasterizer() || 517 paint.getPathEffect() || 518 paint.isFakeBoldText() || 519 paint.getStyle() != SkPaint::kFill_Style || 520 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { 521 // turn off lcd 522 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 523 flags->fHinting = paint.getHinting(); 524 return true; 525 } 526 // we're cool with the paint as is 527 return false; 528 } 529