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