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 "SkDeferredCanvas.h" 10 11 #include "SkPaint.h" 12 #include "SkShader.h" 13 #include "SkColorFilter.h" 14 #include "SkDrawFilter.h" 15 16 namespace { 17 18 bool isPaintOpaque(const SkPaint* paint, 19 const SkBitmap* bmpReplacesShader = NULL) { 20 // TODO: SkXfermode should have a virtual isOpaque method, which would 21 // make it possible to test modes that do not have a Coeff representation. 22 23 if (!paint) { 24 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true; 25 } 26 27 SkXfermode::Coeff srcCoeff, dstCoeff; 28 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){ 29 switch (dstCoeff) { 30 case SkXfermode::kZero_Coeff: 31 return true; 32 case SkXfermode::kISA_Coeff: 33 if (paint->getAlpha() != 255) { 34 break; 35 } 36 if (bmpReplacesShader) { 37 if (!bmpReplacesShader->isOpaque()) { 38 break; 39 } 40 } else if (paint->getShader() && !paint->getShader()->isOpaque()) { 41 break; 42 } 43 if (paint->getColorFilter() && 44 ((paint->getColorFilter()->getFlags() & 45 SkColorFilter::kAlphaUnchanged_Flag) == 0)) { 46 break; 47 } 48 return true; 49 case SkXfermode::kSA_Coeff: 50 if (paint->getAlpha() != 0) { 51 break; 52 } 53 if (paint->getColorFilter() && 54 ((paint->getColorFilter()->getFlags() & 55 SkColorFilter::kAlphaUnchanged_Flag) == 0)) { 56 break; 57 } 58 return true; 59 case SkXfermode::kSC_Coeff: 60 if (paint->getColor() != 0) { // all components must be 0 61 break; 62 } 63 if (bmpReplacesShader || paint->getShader()) { 64 break; 65 } 66 if (paint->getColorFilter() && ( 67 (paint->getColorFilter()->getFlags() & 68 SkColorFilter::kAlphaUnchanged_Flag) == 0)) { 69 break; 70 } 71 return true; 72 default: 73 break; 74 } 75 } 76 return false; 77 } 78 79 } // unnamed namespace 80 81 SkDeferredCanvas::SkDeferredCanvas() { 82 init(); 83 } 84 85 SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) { 86 init(); 87 setDevice(device); 88 } 89 90 SkDeferredCanvas::SkDeferredCanvas(SkDevice* device, 91 DeviceContext* deviceContext) { 92 init(); 93 setDevice(device); 94 setDeviceContext(deviceContext); 95 } 96 97 void SkDeferredCanvas::init() { 98 fDeferredDrawing = true; // On by default 99 } 100 101 void SkDeferredCanvas::validate() const { 102 SkASSERT(getDevice()); 103 } 104 105 SkCanvas* SkDeferredCanvas::drawingCanvas() const { 106 validate(); 107 return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() : 108 getDeferredDevice()->immediateCanvas(); 109 } 110 111 void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap) { 112 validate(); 113 if (fDeferredDrawing) { 114 getDeferredDevice()->flushIfNeeded(bitmap); 115 } 116 } 117 118 SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const { 119 return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice()); 120 } 121 122 void SkDeferredCanvas::setDeferredDrawing(bool val) { 123 validate(); // Must set device before calling this method 124 SkASSERT(drawingCanvas()->getSaveCount() == 1); 125 if (val != fDeferredDrawing) { 126 if (fDeferredDrawing) { 127 // Going live. 128 getDeferredDevice()->flushPending(); 129 } 130 fDeferredDrawing = val; 131 } 132 } 133 134 SkDeferredCanvas::~SkDeferredCanvas() { 135 } 136 137 SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) { 138 INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref(); 139 return device; 140 } 141 142 SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext( 143 DeviceContext* deviceContext) { 144 145 DeferredDevice* deferredDevice = getDeferredDevice(); 146 SkASSERT(deferredDevice); 147 if (deferredDevice) { 148 deferredDevice->setDeviceContext(deviceContext); 149 } 150 return deviceContext; 151 } 152 153 bool SkDeferredCanvas::isFullFrame(const SkRect* rect, 154 const SkPaint* paint) const { 155 SkCanvas* canvas = drawingCanvas(); 156 SkISize canvasSize = getDeviceSize(); 157 if (rect) { 158 if (!canvas->getTotalMatrix().rectStaysRect()) { 159 return false; // conservative 160 } 161 162 SkRect transformedRect; 163 canvas->getTotalMatrix().mapRect(&transformedRect, *rect); 164 165 if (paint) { 166 SkPaint::Style paintStyle = paint->getStyle(); 167 if (!(paintStyle == SkPaint::kFill_Style || 168 paintStyle == SkPaint::kStrokeAndFill_Style)) { 169 return false; 170 } 171 if (paint->getMaskFilter() || paint->getLooper() 172 || paint->getPathEffect() || paint->getImageFilter()) { 173 return false; // conservative 174 } 175 } 176 177 // The following test holds with AA enabled, and is conservative 178 // by a 0.5 pixel margin with AA disabled 179 if (transformedRect.fLeft > SkIntToScalar(0) || 180 transformedRect.fTop > SkIntToScalar(0) || 181 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) || 182 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) { 183 return false; 184 } 185 } 186 187 switch (canvas->getClipType()) { 188 case SkCanvas::kRect_ClipType : 189 { 190 SkIRect bounds; 191 canvas->getClipDeviceBounds(&bounds); 192 if (bounds.fLeft > 0 || bounds.fTop > 0 || 193 bounds.fRight < canvasSize.fWidth || 194 bounds.fBottom < canvasSize.fHeight) 195 return false; 196 } 197 break; 198 case SkCanvas::kComplex_ClipType : 199 return false; // conservative 200 case SkCanvas::kEmpty_ClipType: 201 default: 202 break; 203 }; 204 205 return true; 206 } 207 208 int SkDeferredCanvas::save(SaveFlags flags) { 209 drawingCanvas()->save(flags); 210 return this->INHERITED::save(flags); 211 } 212 213 int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 214 SaveFlags flags) { 215 drawingCanvas()->saveLayer(bounds, paint, flags); 216 int count = this->INHERITED::save(flags); 217 this->clipRectBounds(bounds, flags, NULL); 218 return count; 219 } 220 221 void SkDeferredCanvas::restore() { 222 drawingCanvas()->restore(); 223 this->INHERITED::restore(); 224 } 225 226 bool SkDeferredCanvas::isDrawingToLayer() const { 227 return drawingCanvas()->isDrawingToLayer(); 228 } 229 230 bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) { 231 drawingCanvas()->translate(dx, dy); 232 return this->INHERITED::translate(dx, dy); 233 } 234 235 bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) { 236 drawingCanvas()->scale(sx, sy); 237 return this->INHERITED::scale(sx, sy); 238 } 239 240 bool SkDeferredCanvas::rotate(SkScalar degrees) { 241 drawingCanvas()->rotate(degrees); 242 return this->INHERITED::rotate(degrees); 243 } 244 245 bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) { 246 drawingCanvas()->skew(sx, sy); 247 return this->INHERITED::skew(sx, sy); 248 } 249 250 bool SkDeferredCanvas::concat(const SkMatrix& matrix) { 251 drawingCanvas()->concat(matrix); 252 return this->INHERITED::concat(matrix); 253 } 254 255 void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) { 256 drawingCanvas()->setMatrix(matrix); 257 this->INHERITED::setMatrix(matrix); 258 } 259 260 bool SkDeferredCanvas::clipRect(const SkRect& rect, 261 SkRegion::Op op, 262 bool doAntiAlias) { 263 drawingCanvas()->clipRect(rect, op, doAntiAlias); 264 return this->INHERITED::clipRect(rect, op, doAntiAlias); 265 } 266 267 bool SkDeferredCanvas::clipPath(const SkPath& path, 268 SkRegion::Op op, 269 bool doAntiAlias) { 270 drawingCanvas()->clipPath(path, op, doAntiAlias); 271 return this->INHERITED::clipPath(path, op, doAntiAlias); 272 } 273 274 bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn, 275 SkRegion::Op op) { 276 drawingCanvas()->clipRegion(deviceRgn, op); 277 return this->INHERITED::clipRegion(deviceRgn, op); 278 } 279 280 void SkDeferredCanvas::clear(SkColor color) { 281 // purge pending commands 282 if (fDeferredDrawing) { 283 getDeferredDevice()->contentsCleared(); 284 } 285 286 drawingCanvas()->clear(color); 287 } 288 289 void SkDeferredCanvas::drawPaint(const SkPaint& paint) { 290 if (fDeferredDrawing && isFullFrame(NULL, &paint) && 291 isPaintOpaque(&paint)) { 292 getDeferredDevice()->contentsCleared(); 293 } 294 295 drawingCanvas()->drawPaint(paint); 296 } 297 298 void SkDeferredCanvas::drawPoints(PointMode mode, size_t count, 299 const SkPoint pts[], const SkPaint& paint) { 300 drawingCanvas()->drawPoints(mode, count, pts, paint); 301 } 302 303 void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { 304 if (fDeferredDrawing && isFullFrame(&rect, &paint) && 305 isPaintOpaque(&paint)) { 306 getDeferredDevice()->contentsCleared(); 307 } 308 309 drawingCanvas()->drawRect(rect, paint); 310 } 311 312 void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 313 drawingCanvas()->drawPath(path, paint); 314 } 315 316 void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left, 317 SkScalar top, const SkPaint* paint) { 318 SkRect bitmapRect = SkRect::MakeXYWH(left, top, 319 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 320 if (fDeferredDrawing && 321 isFullFrame(&bitmapRect, paint) && 322 isPaintOpaque(paint, &bitmap)) { 323 getDeferredDevice()->contentsCleared(); 324 } 325 326 drawingCanvas()->drawBitmap(bitmap, left, top, paint); 327 flushIfNeeded(bitmap); 328 } 329 330 void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap, 331 const SkIRect* src, 332 const SkRect& dst, 333 const SkPaint* paint) { 334 if (fDeferredDrawing && 335 isFullFrame(&dst, paint) && 336 isPaintOpaque(paint, &bitmap)) { 337 getDeferredDevice()->contentsCleared(); 338 } 339 340 drawingCanvas()->drawBitmapRect(bitmap, src, 341 dst, paint); 342 flushIfNeeded(bitmap); 343 } 344 345 346 void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap, 347 const SkMatrix& m, 348 const SkPaint* paint) { 349 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect 350 // covers canvas entirely and transformed bitmap covers canvas entirely 351 drawingCanvas()->drawBitmapMatrix(bitmap, m, paint); 352 flushIfNeeded(bitmap); 353 } 354 355 void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap, 356 const SkIRect& center, const SkRect& dst, 357 const SkPaint* paint) { 358 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect 359 // covers canvas entirely and dst covers canvas entirely 360 drawingCanvas()->drawBitmapNine(bitmap, center, 361 dst, paint); 362 flushIfNeeded(bitmap); 363 } 364 365 void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, 366 const SkPaint* paint) { 367 SkRect bitmapRect = SkRect::MakeXYWH( 368 SkIntToScalar(left), 369 SkIntToScalar(top), 370 SkIntToScalar(bitmap.width()), 371 SkIntToScalar(bitmap.height())); 372 if (fDeferredDrawing && 373 isFullFrame(&bitmapRect, paint) && 374 isPaintOpaque(paint, &bitmap)) { 375 getDeferredDevice()->contentsCleared(); 376 } 377 378 drawingCanvas()->drawSprite(bitmap, left, top, 379 paint); 380 flushIfNeeded(bitmap); 381 } 382 383 void SkDeferredCanvas::drawText(const void* text, size_t byteLength, 384 SkScalar x, SkScalar y, const SkPaint& paint) { 385 drawingCanvas()->drawText(text, byteLength, x, y, paint); 386 } 387 388 void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength, 389 const SkPoint pos[], const SkPaint& paint) { 390 drawingCanvas()->drawPosText(text, byteLength, pos, paint); 391 } 392 393 void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength, 394 const SkScalar xpos[], SkScalar constY, 395 const SkPaint& paint) { 396 drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint); 397 } 398 399 void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength, 400 const SkPath& path, 401 const SkMatrix* matrix, 402 const SkPaint& paint) { 403 drawingCanvas()->drawTextOnPath(text, byteLength, 404 path, matrix, 405 paint); 406 } 407 408 void SkDeferredCanvas::drawPicture(SkPicture& picture) { 409 drawingCanvas()->drawPicture(picture); 410 } 411 412 void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount, 413 const SkPoint vertices[], 414 const SkPoint texs[], 415 const SkColor colors[], SkXfermode* xmode, 416 const uint16_t indices[], int indexCount, 417 const SkPaint& paint) { 418 drawingCanvas()->drawVertices(vmode, vertexCount, 419 vertices, texs, 420 colors, xmode, 421 indices, indexCount, 422 paint); 423 } 424 425 SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) { 426 drawingCanvas()->setBounder(bounder); 427 return INHERITED::setBounder(bounder); 428 } 429 430 SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) { 431 drawingCanvas()->setDrawFilter(filter); 432 return INHERITED::setDrawFilter(filter); 433 } 434 435 SkCanvas* SkDeferredCanvas::canvasForDrawIter() { 436 return drawingCanvas(); 437 } 438 439 // SkDeferredCanvas::DeferredDevice 440 //------------------------------------ 441 442 SkDeferredCanvas::DeferredDevice::DeferredDevice( 443 SkDevice* immediateDevice, DeviceContext* deviceContext) : 444 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(), 445 immediateDevice->height(), immediateDevice->isOpaque()) 446 , fFreshFrame(true) { 447 448 fDeviceContext = deviceContext; 449 SkSafeRef(fDeviceContext); 450 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas 451 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice)); 452 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(), 453 fImmediateDevice->height(), 0); 454 } 455 456 SkDeferredCanvas::DeferredDevice::~DeferredDevice() { 457 SkSafeUnref(fImmediateCanvas); 458 SkSafeUnref(fDeviceContext); 459 } 460 461 void SkDeferredCanvas::DeferredDevice::setDeviceContext( 462 DeviceContext* deviceContext) { 463 SkRefCnt_SafeAssign(fDeviceContext, deviceContext); 464 } 465 466 void SkDeferredCanvas::DeferredDevice::contentsCleared() { 467 if (!fRecordingCanvas->isDrawingToLayer()) { 468 fFreshFrame = true; 469 470 // TODO: find a way to transfer the state stack and layers 471 // to the new recording canvas. For now, purging only works 472 // with an empty stack. 473 if (fRecordingCanvas->getSaveCount() == 0) { 474 475 // Save state that is trashed by the purge 476 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter(); 477 SkSafeRef(drawFilter); // So that it survives the purge 478 SkMatrix matrix = fRecordingCanvas->getTotalMatrix(); 479 SkRegion clipRegion = fRecordingCanvas->getTotalClip(); 480 481 // beginRecording creates a new recording canvas and discards the 482 // old one, hence purging deferred draw ops. 483 fRecordingCanvas = fPicture.beginRecording( 484 fImmediateDevice->width(), 485 fImmediateDevice->height(), 0); 486 487 // Restore pre-purge state 488 if (!clipRegion.isEmpty()) { 489 fRecordingCanvas->clipRegion(clipRegion, 490 SkRegion::kReplace_Op); 491 } 492 if (!matrix.isIdentity()) { 493 fRecordingCanvas->setMatrix(matrix); 494 } 495 if (drawFilter) { 496 fRecordingCanvas->setDrawFilter(drawFilter)->unref(); 497 } 498 } 499 } 500 } 501 502 bool SkDeferredCanvas::DeferredDevice::isFreshFrame() { 503 bool ret = fFreshFrame; 504 fFreshFrame = false; 505 return ret; 506 } 507 508 void SkDeferredCanvas::DeferredDevice::flushPending() { 509 if (fDeviceContext) { 510 fDeviceContext->prepareForDraw(); 511 } 512 fPicture.draw(fImmediateCanvas); 513 fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(), 514 fImmediateDevice->height(), 0); 515 } 516 517 void SkDeferredCanvas::DeferredDevice::flush() { 518 flushPending(); 519 fImmediateCanvas->flush(); 520 } 521 522 void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap) { 523 if (bitmap.isImmutable()) { 524 return; // safe to deffer without registering a dependency 525 } 526 527 // For now, drawing a writable bitmap triggers a flush 528 // TODO: implement read-only semantics and auto buffer duplication on write 529 // in SkBitmap/SkPixelRef, which will make deferral possible in this case. 530 flushPending(); 531 } 532 533 uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities() { 534 return fImmediateDevice->getDeviceCapabilities(); 535 } 536 537 int SkDeferredCanvas::DeferredDevice::width() const { 538 return fImmediateDevice->width(); 539 } 540 541 int SkDeferredCanvas::DeferredDevice::height() const { 542 return fImmediateDevice->height(); 543 } 544 545 SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget() { 546 flushPending(); 547 return fImmediateDevice->accessRenderTarget(); 548 } 549 550 void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap, 551 int x, int y, SkCanvas::Config8888 config8888) { 552 553 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() && 554 (y + bitmap.height()) >= height()) { 555 contentsCleared(); 556 } 557 558 if (SkBitmap::kARGB_8888_Config == bitmap.config() && 559 SkCanvas::kNative_Premul_Config8888 != config8888 && 560 kPMColorAlias != config8888) { 561 //Special case config: no deferral 562 flushPending(); 563 fImmediateDevice->writePixels(bitmap, x, y, config8888); 564 } 565 566 SkPaint paint; 567 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 568 fRecordingCanvas->drawSprite(bitmap, x, y, &paint); 569 flushIfNeeded(bitmap); 570 } 571 572 const SkBitmap& SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap*) { 573 flushPending(); 574 return fImmediateDevice->accessBitmap(false); 575 } 576 577 SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice( 578 SkBitmap::Config config, int width, int height, bool isOpaque, 579 Usage usage) { 580 581 // Save layer usage not supported, and not required by SkDeferredCanvas. 582 SkASSERT(usage != kSaveLayer_Usage); 583 // Create a compatible non-deferred device. 584 SkDevice* compatibleDevice = 585 fImmediateDevice->createCompatibleDevice(config, width, height, 586 isOpaque); 587 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext)); 588 } 589 590 bool SkDeferredCanvas::DeferredDevice::onReadPixels( 591 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) { 592 flushPending(); 593 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap), 594 x, y, config8888); 595 } 596