1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkCanvas.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2583 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2008 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkCanvas.h" 1.14 +#include "SkBitmapDevice.h" 1.15 +#include "SkBounder.h" 1.16 +#include "SkDeviceImageFilterProxy.h" 1.17 +#include "SkDraw.h" 1.18 +#include "SkDrawFilter.h" 1.19 +#include "SkDrawLooper.h" 1.20 +#include "SkMetaData.h" 1.21 +#include "SkPathOps.h" 1.22 +#include "SkPicture.h" 1.23 +#include "SkRasterClip.h" 1.24 +#include "SkRRect.h" 1.25 +#include "SkSmallAllocator.h" 1.26 +#include "SkSurface_Base.h" 1.27 +#include "SkTemplates.h" 1.28 +#include "SkTextFormatParams.h" 1.29 +#include "SkTLazy.h" 1.30 +#include "SkUtils.h" 1.31 + 1.32 +#if SK_SUPPORT_GPU 1.33 +#include "GrRenderTarget.h" 1.34 +#endif 1.35 + 1.36 +// experimental for faster tiled drawing... 1.37 +//#define SK_ENABLE_CLIP_QUICKREJECT 1.38 + 1.39 +//#define SK_TRACE_SAVERESTORE 1.40 + 1.41 +#ifdef SK_TRACE_SAVERESTORE 1.42 + static int gLayerCounter; 1.43 + static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } 1.44 + static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } 1.45 + 1.46 + static int gRecCounter; 1.47 + static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } 1.48 + static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } 1.49 + 1.50 + static int gCanvasCounter; 1.51 + static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } 1.52 + static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } 1.53 +#else 1.54 + #define inc_layer() 1.55 + #define dec_layer() 1.56 + #define inc_rec() 1.57 + #define dec_rec() 1.58 + #define inc_canvas() 1.59 + #define dec_canvas() 1.60 +#endif 1.61 + 1.62 +#ifdef SK_DEBUG 1.63 +#include "SkPixelRef.h" 1.64 + 1.65 +/* 1.66 + * Some pixelref subclasses can support being "locked" from another thread 1.67 + * during the lock-scope of skia calling them. In these instances, this balance 1.68 + * check will fail, but may not be indicative of a problem, so we allow a build 1.69 + * flag to disable this check. 1.70 + * 1.71 + * Potentially another fix would be to have a (debug-only) virtual or flag on 1.72 + * pixelref, which could tell us at runtime if this check is valid. That would 1.73 + * eliminate the need for this heavy-handed build check. 1.74 + */ 1.75 +#ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK 1.76 +class AutoCheckLockCountBalance { 1.77 +public: 1.78 + AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ } 1.79 +}; 1.80 +#else 1.81 +class AutoCheckLockCountBalance { 1.82 +public: 1.83 + AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) { 1.84 + fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0; 1.85 + } 1.86 + ~AutoCheckLockCountBalance() { 1.87 + const int count = fPixelRef ? fPixelRef->getLockCount() : 0; 1.88 + SkASSERT(count == fLockCount); 1.89 + } 1.90 + 1.91 +private: 1.92 + const SkPixelRef* fPixelRef; 1.93 + int fLockCount; 1.94 +}; 1.95 +#endif 1.96 + 1.97 +class AutoCheckNoSetContext { 1.98 +public: 1.99 + AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) { 1.100 + this->assertNoSetContext(fPaint); 1.101 + } 1.102 + ~AutoCheckNoSetContext() { 1.103 + this->assertNoSetContext(fPaint); 1.104 + } 1.105 + 1.106 +private: 1.107 + const SkPaint& fPaint; 1.108 + 1.109 + void assertNoSetContext(const SkPaint& paint) { 1.110 + SkShader* s = paint.getShader(); 1.111 + if (s) { 1.112 + SkASSERT(!s->setContextHasBeenCalled()); 1.113 + } 1.114 + } 1.115 +}; 1.116 + 1.117 +#define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap) 1.118 +#define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext cshsc(paint) 1.119 + 1.120 +#else 1.121 + #define CHECK_LOCKCOUNT_BALANCE(bitmap) 1.122 + #define CHECK_SHADER_NOSETCONTEXT(paint) 1.123 +#endif 1.124 + 1.125 +typedef SkTLazy<SkPaint> SkLazyPaint; 1.126 + 1.127 +void SkCanvas::predrawNotify() { 1.128 + if (fSurfaceBase) { 1.129 + fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode); 1.130 + } 1.131 +} 1.132 + 1.133 +/////////////////////////////////////////////////////////////////////////////// 1.134 + 1.135 +/* This is the record we keep for each SkBaseDevice that the user installs. 1.136 + The clip/matrix/proc are fields that reflect the top of the save/restore 1.137 + stack. Whenever the canvas changes, it marks a dirty flag, and then before 1.138 + these are used (assuming we're not on a layer) we rebuild these cache 1.139 + values: they reflect the top of the save stack, but translated and clipped 1.140 + by the device's XY offset and bitmap-bounds. 1.141 +*/ 1.142 +struct DeviceCM { 1.143 + DeviceCM* fNext; 1.144 + SkBaseDevice* fDevice; 1.145 + SkRasterClip fClip; 1.146 + const SkMatrix* fMatrix; 1.147 + SkPaint* fPaint; // may be null (in the future) 1.148 + 1.149 + DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas) 1.150 + : fNext(NULL) { 1.151 + if (NULL != device) { 1.152 + device->ref(); 1.153 + device->onAttachToCanvas(canvas); 1.154 + } 1.155 + fDevice = device; 1.156 + fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; 1.157 + } 1.158 + 1.159 + ~DeviceCM() { 1.160 + if (NULL != fDevice) { 1.161 + fDevice->onDetachFromCanvas(); 1.162 + fDevice->unref(); 1.163 + } 1.164 + SkDELETE(fPaint); 1.165 + } 1.166 + 1.167 + void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, 1.168 + const SkClipStack& clipStack, SkRasterClip* updateClip) { 1.169 + int x = fDevice->getOrigin().x(); 1.170 + int y = fDevice->getOrigin().y(); 1.171 + int width = fDevice->width(); 1.172 + int height = fDevice->height(); 1.173 + 1.174 + if ((x | y) == 0) { 1.175 + fMatrix = &totalMatrix; 1.176 + fClip = totalClip; 1.177 + } else { 1.178 + fMatrixStorage = totalMatrix; 1.179 + fMatrixStorage.postTranslate(SkIntToScalar(-x), 1.180 + SkIntToScalar(-y)); 1.181 + fMatrix = &fMatrixStorage; 1.182 + 1.183 + totalClip.translate(-x, -y, &fClip); 1.184 + } 1.185 + 1.186 + fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); 1.187 + 1.188 + // intersect clip, but don't translate it (yet) 1.189 + 1.190 + if (updateClip) { 1.191 + updateClip->op(SkIRect::MakeXYWH(x, y, width, height), 1.192 + SkRegion::kDifference_Op); 1.193 + } 1.194 + 1.195 + fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); 1.196 + 1.197 +#ifdef SK_DEBUG 1.198 + if (!fClip.isEmpty()) { 1.199 + SkIRect deviceR; 1.200 + deviceR.set(0, 0, width, height); 1.201 + SkASSERT(deviceR.contains(fClip.getBounds())); 1.202 + } 1.203 +#endif 1.204 + } 1.205 + 1.206 +private: 1.207 + SkMatrix fMatrixStorage; 1.208 +}; 1.209 + 1.210 +/* This is the record we keep for each save/restore level in the stack. 1.211 + Since a level optionally copies the matrix and/or stack, we have pointers 1.212 + for these fields. If the value is copied for this level, the copy is 1.213 + stored in the ...Storage field, and the pointer points to that. If the 1.214 + value is not copied for this level, we ignore ...Storage, and just point 1.215 + at the corresponding value in the previous level in the stack. 1.216 +*/ 1.217 +class SkCanvas::MCRec { 1.218 +public: 1.219 + int fFlags; 1.220 + SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec 1.221 + SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec 1.222 + SkDrawFilter* fFilter; // the current filter (or null) 1.223 + 1.224 + DeviceCM* fLayer; 1.225 + /* If there are any layers in the stack, this points to the top-most 1.226 + one that is at or below this level in the stack (so we know what 1.227 + bitmap/device to draw into from this level. This value is NOT 1.228 + reference counted, since the real owner is either our fLayer field, 1.229 + or a previous one in a lower level.) 1.230 + */ 1.231 + DeviceCM* fTopLayer; 1.232 + 1.233 + MCRec(const MCRec* prev, int flags) : fFlags(flags) { 1.234 + if (NULL != prev) { 1.235 + if (flags & SkCanvas::kMatrix_SaveFlag) { 1.236 + fMatrixStorage = *prev->fMatrix; 1.237 + fMatrix = &fMatrixStorage; 1.238 + } else { 1.239 + fMatrix = prev->fMatrix; 1.240 + } 1.241 + 1.242 + if (flags & SkCanvas::kClip_SaveFlag) { 1.243 + fRasterClipStorage = *prev->fRasterClip; 1.244 + fRasterClip = &fRasterClipStorage; 1.245 + } else { 1.246 + fRasterClip = prev->fRasterClip; 1.247 + } 1.248 + 1.249 + fFilter = prev->fFilter; 1.250 + SkSafeRef(fFilter); 1.251 + 1.252 + fTopLayer = prev->fTopLayer; 1.253 + } else { // no prev 1.254 + fMatrixStorage.reset(); 1.255 + 1.256 + fMatrix = &fMatrixStorage; 1.257 + fRasterClip = &fRasterClipStorage; 1.258 + fFilter = NULL; 1.259 + fTopLayer = NULL; 1.260 + } 1.261 + fLayer = NULL; 1.262 + 1.263 + // don't bother initializing fNext 1.264 + inc_rec(); 1.265 + } 1.266 + ~MCRec() { 1.267 + SkSafeUnref(fFilter); 1.268 + SkDELETE(fLayer); 1.269 + dec_rec(); 1.270 + } 1.271 + 1.272 +private: 1.273 + SkMatrix fMatrixStorage; 1.274 + SkRasterClip fRasterClipStorage; 1.275 +}; 1.276 + 1.277 +class SkDrawIter : public SkDraw { 1.278 +public: 1.279 + SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { 1.280 + canvas = canvas->canvasForDrawIter(); 1.281 + fCanvas = canvas; 1.282 + canvas->updateDeviceCMCache(); 1.283 + 1.284 + fClipStack = &canvas->fClipStack; 1.285 + fBounder = canvas->getBounder(); 1.286 + fCurrLayer = canvas->fMCRec->fTopLayer; 1.287 + fSkipEmptyClips = skipEmptyClips; 1.288 + } 1.289 + 1.290 + bool next() { 1.291 + // skip over recs with empty clips 1.292 + if (fSkipEmptyClips) { 1.293 + while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { 1.294 + fCurrLayer = fCurrLayer->fNext; 1.295 + } 1.296 + } 1.297 + 1.298 + const DeviceCM* rec = fCurrLayer; 1.299 + if (rec && rec->fDevice) { 1.300 + 1.301 + fMatrix = rec->fMatrix; 1.302 + fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW(); 1.303 + fRC = &rec->fClip; 1.304 + fDevice = rec->fDevice; 1.305 + fBitmap = &fDevice->accessBitmap(true); 1.306 + fPaint = rec->fPaint; 1.307 + SkDEBUGCODE(this->validate();) 1.308 + 1.309 + fCurrLayer = rec->fNext; 1.310 + if (fBounder) { 1.311 + fBounder->setClip(fClip); 1.312 + } 1.313 + // fCurrLayer may be NULL now 1.314 + 1.315 + return true; 1.316 + } 1.317 + return false; 1.318 + } 1.319 + 1.320 + SkBaseDevice* getDevice() const { return fDevice; } 1.321 + int getX() const { return fDevice->getOrigin().x(); } 1.322 + int getY() const { return fDevice->getOrigin().y(); } 1.323 + const SkMatrix& getMatrix() const { return *fMatrix; } 1.324 + const SkRegion& getClip() const { return *fClip; } 1.325 + const SkPaint* getPaint() const { return fPaint; } 1.326 + 1.327 +private: 1.328 + SkCanvas* fCanvas; 1.329 + const DeviceCM* fCurrLayer; 1.330 + const SkPaint* fPaint; // May be null. 1.331 + SkBool8 fSkipEmptyClips; 1.332 + 1.333 + typedef SkDraw INHERITED; 1.334 +}; 1.335 + 1.336 +///////////////////////////////////////////////////////////////////////////// 1.337 + 1.338 +class AutoDrawLooper { 1.339 +public: 1.340 + AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, 1.341 + bool skipLayerForImageFilter = false, 1.342 + const SkRect* bounds = NULL) : fOrigPaint(paint) { 1.343 + fCanvas = canvas; 1.344 + fFilter = canvas->getDrawFilter(); 1.345 + fPaint = NULL; 1.346 + fSaveCount = canvas->getSaveCount(); 1.347 + fDoClearImageFilter = false; 1.348 + fDone = false; 1.349 + 1.350 + if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) { 1.351 + SkPaint tmp; 1.352 + tmp.setImageFilter(fOrigPaint.getImageFilter()); 1.353 + (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag, 1.354 + true, SkCanvas::kFullLayer_SaveLayerStrategy); 1.355 + // we'll clear the imageFilter for the actual draws in next(), so 1.356 + // it will only be applied during the restore(). 1.357 + fDoClearImageFilter = true; 1.358 + } 1.359 + 1.360 + if (SkDrawLooper* looper = paint.getLooper()) { 1.361 + void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>( 1.362 + looper->contextSize()); 1.363 + fLooperContext = looper->createContext(canvas, buffer); 1.364 + fIsSimple = false; 1.365 + } else { 1.366 + fLooperContext = NULL; 1.367 + // can we be marked as simple? 1.368 + fIsSimple = !fFilter && !fDoClearImageFilter; 1.369 + } 1.370 + } 1.371 + 1.372 + ~AutoDrawLooper() { 1.373 + if (fDoClearImageFilter) { 1.374 + fCanvas->internalRestore(); 1.375 + } 1.376 + SkASSERT(fCanvas->getSaveCount() == fSaveCount); 1.377 + } 1.378 + 1.379 + const SkPaint& paint() const { 1.380 + SkASSERT(fPaint); 1.381 + return *fPaint; 1.382 + } 1.383 + 1.384 + bool next(SkDrawFilter::Type drawType) { 1.385 + if (fDone) { 1.386 + return false; 1.387 + } else if (fIsSimple) { 1.388 + fDone = true; 1.389 + fPaint = &fOrigPaint; 1.390 + return !fPaint->nothingToDraw(); 1.391 + } else { 1.392 + return this->doNext(drawType); 1.393 + } 1.394 + } 1.395 + 1.396 +private: 1.397 + SkLazyPaint fLazyPaint; 1.398 + SkCanvas* fCanvas; 1.399 + const SkPaint& fOrigPaint; 1.400 + SkDrawFilter* fFilter; 1.401 + const SkPaint* fPaint; 1.402 + int fSaveCount; 1.403 + bool fDoClearImageFilter; 1.404 + bool fDone; 1.405 + bool fIsSimple; 1.406 + SkDrawLooper::Context* fLooperContext; 1.407 + SkSmallAllocator<1, 32> fLooperContextAllocator; 1.408 + 1.409 + bool doNext(SkDrawFilter::Type drawType); 1.410 +}; 1.411 + 1.412 +bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { 1.413 + fPaint = NULL; 1.414 + SkASSERT(!fIsSimple); 1.415 + SkASSERT(fLooperContext || fFilter || fDoClearImageFilter); 1.416 + 1.417 + SkPaint* paint = fLazyPaint.set(fOrigPaint); 1.418 + 1.419 + if (fDoClearImageFilter) { 1.420 + paint->setImageFilter(NULL); 1.421 + } 1.422 + 1.423 + if (fLooperContext && !fLooperContext->next(fCanvas, paint)) { 1.424 + fDone = true; 1.425 + return false; 1.426 + } 1.427 + if (fFilter) { 1.428 + if (!fFilter->filter(paint, drawType)) { 1.429 + fDone = true; 1.430 + return false; 1.431 + } 1.432 + if (NULL == fLooperContext) { 1.433 + // no looper means we only draw once 1.434 + fDone = true; 1.435 + } 1.436 + } 1.437 + fPaint = paint; 1.438 + 1.439 + // if we only came in here for the imagefilter, mark us as done 1.440 + if (!fLooperContext && !fFilter) { 1.441 + fDone = true; 1.442 + } 1.443 + 1.444 + // call this after any possible paint modifiers 1.445 + if (fPaint->nothingToDraw()) { 1.446 + fPaint = NULL; 1.447 + return false; 1.448 + } 1.449 + return true; 1.450 +} 1.451 + 1.452 +/* Stack helper for managing a SkBounder. In the destructor, if we were 1.453 + given a bounder, we call its commit() method, signifying that we are 1.454 + done accumulating bounds for that draw. 1.455 +*/ 1.456 +class SkAutoBounderCommit { 1.457 +public: 1.458 + SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {} 1.459 + ~SkAutoBounderCommit() { 1.460 + if (NULL != fBounder) { 1.461 + fBounder->commit(); 1.462 + } 1.463 + } 1.464 +private: 1.465 + SkBounder* fBounder; 1.466 +}; 1.467 +#define SkAutoBounderCommit(...) SK_REQUIRE_LOCAL_VAR(SkAutoBounderCommit) 1.468 + 1.469 +#include "SkColorPriv.h" 1.470 + 1.471 +////////// macros to place around the internal draw calls ////////////////// 1.472 + 1.473 +#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ 1.474 + this->predrawNotify(); \ 1.475 + AutoDrawLooper looper(this, paint, true); \ 1.476 + while (looper.next(type)) { \ 1.477 + SkAutoBounderCommit ac(fBounder); \ 1.478 + SkDrawIter iter(this); 1.479 + 1.480 +#define LOOPER_BEGIN(paint, type, bounds) \ 1.481 + this->predrawNotify(); \ 1.482 + AutoDrawLooper looper(this, paint, false, bounds); \ 1.483 + while (looper.next(type)) { \ 1.484 + SkAutoBounderCommit ac(fBounder); \ 1.485 + SkDrawIter iter(this); 1.486 + 1.487 +#define LOOPER_END } 1.488 + 1.489 +//////////////////////////////////////////////////////////////////////////// 1.490 + 1.491 +SkBaseDevice* SkCanvas::init(SkBaseDevice* device) { 1.492 + fBounder = NULL; 1.493 + fCachedLocalClipBounds.setEmpty(); 1.494 + fCachedLocalClipBoundsDirty = true; 1.495 + fAllowSoftClip = true; 1.496 + fAllowSimplifyClip = false; 1.497 + fDeviceCMDirty = false; 1.498 + fSaveLayerCount = 0; 1.499 + fCullCount = 0; 1.500 + fMetaData = NULL; 1.501 + 1.502 + fMCRec = (MCRec*)fMCStack.push_back(); 1.503 + new (fMCRec) MCRec(NULL, 0); 1.504 + 1.505 + fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL)); 1.506 + fMCRec->fTopLayer = fMCRec->fLayer; 1.507 + 1.508 + fSurfaceBase = NULL; 1.509 + 1.510 + return this->setRootDevice(device); 1.511 +} 1.512 + 1.513 +SkCanvas::SkCanvas() 1.514 + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 1.515 +{ 1.516 + inc_canvas(); 1.517 + 1.518 + this->init(NULL); 1.519 +} 1.520 + 1.521 +SkCanvas::SkCanvas(int width, int height) 1.522 + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 1.523 +{ 1.524 + inc_canvas(); 1.525 + 1.526 + SkBitmap bitmap; 1.527 + bitmap.setConfig(SkImageInfo::MakeUnknown(width, height)); 1.528 + this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); 1.529 +} 1.530 + 1.531 +SkCanvas::SkCanvas(SkBaseDevice* device) 1.532 + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 1.533 +{ 1.534 + inc_canvas(); 1.535 + 1.536 + this->init(device); 1.537 +} 1.538 + 1.539 +SkCanvas::SkCanvas(const SkBitmap& bitmap) 1.540 + : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 1.541 +{ 1.542 + inc_canvas(); 1.543 + 1.544 + this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); 1.545 +} 1.546 + 1.547 +SkCanvas::~SkCanvas() { 1.548 + // free up the contents of our deque 1.549 + this->restoreToCount(1); // restore everything but the last 1.550 + SkASSERT(0 == fSaveLayerCount); 1.551 + 1.552 + this->internalRestore(); // restore the last, since we're going away 1.553 + 1.554 + SkSafeUnref(fBounder); 1.555 + SkDELETE(fMetaData); 1.556 + 1.557 + dec_canvas(); 1.558 +} 1.559 + 1.560 +SkBounder* SkCanvas::setBounder(SkBounder* bounder) { 1.561 + SkRefCnt_SafeAssign(fBounder, bounder); 1.562 + return bounder; 1.563 +} 1.564 + 1.565 +SkDrawFilter* SkCanvas::getDrawFilter() const { 1.566 + return fMCRec->fFilter; 1.567 +} 1.568 + 1.569 +SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { 1.570 + SkRefCnt_SafeAssign(fMCRec->fFilter, filter); 1.571 + return filter; 1.572 +} 1.573 + 1.574 +SkMetaData& SkCanvas::getMetaData() { 1.575 + // metadata users are rare, so we lazily allocate it. If that changes we 1.576 + // can decide to just make it a field in the device (rather than a ptr) 1.577 + if (NULL == fMetaData) { 1.578 + fMetaData = new SkMetaData; 1.579 + } 1.580 + return *fMetaData; 1.581 +} 1.582 + 1.583 +/////////////////////////////////////////////////////////////////////////////// 1.584 + 1.585 +void SkCanvas::flush() { 1.586 + SkBaseDevice* device = this->getDevice(); 1.587 + if (device) { 1.588 + device->flush(); 1.589 + } 1.590 +} 1.591 + 1.592 +SkISize SkCanvas::getTopLayerSize() const { 1.593 + SkBaseDevice* d = this->getTopDevice(); 1.594 + return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 1.595 +} 1.596 + 1.597 +SkIPoint SkCanvas::getTopLayerOrigin() const { 1.598 + SkBaseDevice* d = this->getTopDevice(); 1.599 + return d ? d->getOrigin() : SkIPoint::Make(0, 0); 1.600 +} 1.601 + 1.602 +SkISize SkCanvas::getBaseLayerSize() const { 1.603 + SkBaseDevice* d = this->getDevice(); 1.604 + return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); 1.605 +} 1.606 + 1.607 +SkBaseDevice* SkCanvas::getDevice() const { 1.608 + // return root device 1.609 + MCRec* rec = (MCRec*) fMCStack.front(); 1.610 + SkASSERT(rec && rec->fLayer); 1.611 + return rec->fLayer->fDevice; 1.612 +} 1.613 + 1.614 +SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { 1.615 + if (updateMatrixClip) { 1.616 + const_cast<SkCanvas*>(this)->updateDeviceCMCache(); 1.617 + } 1.618 + return fMCRec->fTopLayer->fDevice; 1.619 +} 1.620 + 1.621 +SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) { 1.622 + // return root device 1.623 + SkDeque::F2BIter iter(fMCStack); 1.624 + MCRec* rec = (MCRec*)iter.next(); 1.625 + SkASSERT(rec && rec->fLayer); 1.626 + SkBaseDevice* rootDevice = rec->fLayer->fDevice; 1.627 + 1.628 + if (rootDevice == device) { 1.629 + return device; 1.630 + } 1.631 + 1.632 + if (device) { 1.633 + device->onAttachToCanvas(this); 1.634 + } 1.635 + if (rootDevice) { 1.636 + rootDevice->onDetachFromCanvas(); 1.637 + } 1.638 + 1.639 + SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); 1.640 + rootDevice = device; 1.641 + 1.642 + fDeviceCMDirty = true; 1.643 + 1.644 + /* Now we update our initial region to have the bounds of the new device, 1.645 + and then intersect all of the clips in our stack with these bounds, 1.646 + to ensure that we can't draw outside of the device's bounds (and trash 1.647 + memory). 1.648 + 1.649 + NOTE: this is only a partial-fix, since if the new device is larger than 1.650 + the previous one, we don't know how to "enlarge" the clips in our stack, 1.651 + so drawing may be artificially restricted. Without keeping a history of 1.652 + all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly 1.653 + reconstruct the correct clips, so this approximation will have to do. 1.654 + The caller really needs to restore() back to the base if they want to 1.655 + accurately take advantage of the new device bounds. 1.656 + */ 1.657 + 1.658 + SkIRect bounds; 1.659 + if (device) { 1.660 + bounds.set(0, 0, device->width(), device->height()); 1.661 + } else { 1.662 + bounds.setEmpty(); 1.663 + } 1.664 + // now jam our 1st clip to be bounds, and intersect the rest with that 1.665 + rec->fRasterClip->setRect(bounds); 1.666 + while ((rec = (MCRec*)iter.next()) != NULL) { 1.667 + (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op); 1.668 + } 1.669 + 1.670 + return device; 1.671 +} 1.672 + 1.673 +bool SkCanvas::readPixels(SkBitmap* bitmap, 1.674 + int x, int y, 1.675 + Config8888 config8888) { 1.676 + SkBaseDevice* device = this->getDevice(); 1.677 + if (!device) { 1.678 + return false; 1.679 + } 1.680 + return device->readPixels(bitmap, x, y, config8888); 1.681 +} 1.682 + 1.683 +bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { 1.684 + SkBaseDevice* device = this->getDevice(); 1.685 + if (!device) { 1.686 + return false; 1.687 + } 1.688 + 1.689 + SkIRect bounds; 1.690 + bounds.set(0, 0, device->width(), device->height()); 1.691 + if (!bounds.intersect(srcRect)) { 1.692 + return false; 1.693 + } 1.694 + 1.695 + SkBitmap tmp; 1.696 + tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), 1.697 + bounds.height()); 1.698 + if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) { 1.699 + bitmap->swap(tmp); 1.700 + return true; 1.701 + } else { 1.702 + return false; 1.703 + } 1.704 +} 1.705 + 1.706 +#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG 1.707 +void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y, 1.708 + Config8888 config8888) { 1.709 + SkBaseDevice* device = this->getDevice(); 1.710 + if (device) { 1.711 + if (SkIRect::Intersects(SkIRect::MakeSize(this->getDeviceSize()), 1.712 + SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))) { 1.713 + device->accessBitmap(true); 1.714 + device->writePixels(bitmap, x, y, config8888); 1.715 + } 1.716 + } 1.717 +} 1.718 +#endif 1.719 + 1.720 +bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { 1.721 + if (bitmap.getTexture()) { 1.722 + return false; 1.723 + } 1.724 + SkBitmap bm(bitmap); 1.725 + bm.lockPixels(); 1.726 + if (bm.getPixels()) { 1.727 + return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y); 1.728 + } 1.729 + return false; 1.730 +} 1.731 + 1.732 +bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes, 1.733 + int x, int y) { 1.734 + switch (origInfo.colorType()) { 1.735 + case kUnknown_SkColorType: 1.736 + case kIndex_8_SkColorType: 1.737 + return false; 1.738 + default: 1.739 + break; 1.740 + } 1.741 + if (NULL == pixels || rowBytes < origInfo.minRowBytes()) { 1.742 + return false; 1.743 + } 1.744 + 1.745 + const SkISize size = this->getBaseLayerSize(); 1.746 + SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); 1.747 + if (!target.intersect(0, 0, size.width(), size.height())) { 1.748 + return false; 1.749 + } 1.750 + 1.751 + SkBaseDevice* device = this->getDevice(); 1.752 + if (!device) { 1.753 + return false; 1.754 + } 1.755 + 1.756 + SkImageInfo info = origInfo; 1.757 + // the intersect may have shrunk info's logical size 1.758 + info.fWidth = target.width(); 1.759 + info.fHeight = target.height(); 1.760 + 1.761 + // if x or y are negative, then we have to adjust pixels 1.762 + if (x > 0) { 1.763 + x = 0; 1.764 + } 1.765 + if (y > 0) { 1.766 + y = 0; 1.767 + } 1.768 + // here x,y are either 0 or negative 1.769 + pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); 1.770 + 1.771 + // The device can assert that the requested area is always contained in its bounds 1.772 + return device->writePixelsDirect(info, pixels, rowBytes, target.x(), target.y()); 1.773 +} 1.774 + 1.775 +SkCanvas* SkCanvas::canvasForDrawIter() { 1.776 + return this; 1.777 +} 1.778 + 1.779 +////////////////////////////////////////////////////////////////////////////// 1.780 + 1.781 +void SkCanvas::updateDeviceCMCache() { 1.782 + if (fDeviceCMDirty) { 1.783 + const SkMatrix& totalMatrix = this->getTotalMatrix(); 1.784 + const SkRasterClip& totalClip = *fMCRec->fRasterClip; 1.785 + DeviceCM* layer = fMCRec->fTopLayer; 1.786 + 1.787 + if (NULL == layer->fNext) { // only one layer 1.788 + layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); 1.789 + } else { 1.790 + SkRasterClip clip(totalClip); 1.791 + do { 1.792 + layer->updateMC(totalMatrix, clip, fClipStack, &clip); 1.793 + } while ((layer = layer->fNext) != NULL); 1.794 + } 1.795 + fDeviceCMDirty = false; 1.796 + } 1.797 +} 1.798 + 1.799 +/////////////////////////////////////////////////////////////////////////////// 1.800 + 1.801 +int SkCanvas::internalSave(SaveFlags flags) { 1.802 + int saveCount = this->getSaveCount(); // record this before the actual save 1.803 + 1.804 + MCRec* newTop = (MCRec*)fMCStack.push_back(); 1.805 + new (newTop) MCRec(fMCRec, flags); // balanced in restore() 1.806 + 1.807 + fMCRec = newTop; 1.808 + 1.809 + if (SkCanvas::kClip_SaveFlag & flags) { 1.810 + fClipStack.save(); 1.811 + } 1.812 + 1.813 + return saveCount; 1.814 +} 1.815 + 1.816 +void SkCanvas::willSave(SaveFlags) { 1.817 + // Do nothing. Subclasses may do something. 1.818 +} 1.819 + 1.820 +int SkCanvas::save(SaveFlags flags) { 1.821 + this->willSave(flags); 1.822 + // call shared impl 1.823 + return this->internalSave(flags); 1.824 +} 1.825 + 1.826 +static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { 1.827 +#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 1.828 + return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; 1.829 +#else 1.830 + return true; 1.831 +#endif 1.832 +} 1.833 + 1.834 +bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, 1.835 + SkIRect* intersection, const SkImageFilter* imageFilter) { 1.836 + SkIRect clipBounds; 1.837 + SkRegion::Op op = SkRegion::kIntersect_Op; 1.838 + if (!this->getClipDeviceBounds(&clipBounds)) { 1.839 + return false; 1.840 + } 1.841 + 1.842 + if (imageFilter) { 1.843 + imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds); 1.844 + // Filters may grow the bounds beyond the device bounds. 1.845 + op = SkRegion::kReplace_Op; 1.846 + } 1.847 + SkIRect ir; 1.848 + if (NULL != bounds) { 1.849 + SkRect r; 1.850 + 1.851 + this->getTotalMatrix().mapRect(&r, *bounds); 1.852 + r.roundOut(&ir); 1.853 + // early exit if the layer's bounds are clipped out 1.854 + if (!ir.intersect(clipBounds)) { 1.855 + if (bounds_affects_clip(flags)) { 1.856 + fMCRec->fRasterClip->setEmpty(); 1.857 + } 1.858 + return false; 1.859 + } 1.860 + } else { // no user bounds, so just use the clip 1.861 + ir = clipBounds; 1.862 + } 1.863 + 1.864 + if (bounds_affects_clip(flags)) { 1.865 + fClipStack.clipDevRect(ir, op); 1.866 + // early exit if the clip is now empty 1.867 + if (!fMCRec->fRasterClip->op(ir, op)) { 1.868 + return false; 1.869 + } 1.870 + } 1.871 + 1.872 + if (intersection) { 1.873 + *intersection = ir; 1.874 + } 1.875 + return true; 1.876 +} 1.877 + 1.878 +SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) { 1.879 + 1.880 + // Do nothing. Subclasses may do something. 1.881 + return kFullLayer_SaveLayerStrategy; 1.882 +} 1.883 + 1.884 +int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 1.885 + SaveFlags flags) { 1.886 + // Overriding classes may return false to signal that we don't need to create a layer. 1.887 + SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); 1.888 + return this->internalSaveLayer(bounds, paint, flags, false, strategy); 1.889 +} 1.890 + 1.891 +static SkBaseDevice* createCompatibleDevice(SkCanvas* canvas, 1.892 + const SkImageInfo& info) { 1.893 + SkBaseDevice* device = canvas->getDevice(); 1.894 + return device ? device->createCompatibleDevice(info) : NULL; 1.895 +} 1.896 + 1.897 +int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, 1.898 + bool justForImageFilter, SaveLayerStrategy strategy) { 1.899 +#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG 1.900 + flags = (SaveFlags)(flags | kClipToLayer_SaveFlag); 1.901 +#endif 1.902 + 1.903 + // do this before we create the layer. We don't call the public save() since 1.904 + // that would invoke a possibly overridden virtual 1.905 + int count = this->internalSave(flags); 1.906 + 1.907 + fDeviceCMDirty = true; 1.908 + 1.909 + SkIRect ir; 1.910 + if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { 1.911 + return count; 1.912 + } 1.913 + 1.914 + // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about 1.915 + // the clipRectBounds() call above? 1.916 + if (kNoLayer_SaveLayerStrategy == strategy) { 1.917 + return count; 1.918 + } 1.919 + 1.920 + // Kill the imagefilter if our device doesn't allow it 1.921 + SkLazyPaint lazyP; 1.922 + if (paint && paint->getImageFilter()) { 1.923 + if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { 1.924 + if (justForImageFilter) { 1.925 + // early exit if the layer was just for the imageFilter 1.926 + return count; 1.927 + } 1.928 + SkPaint* p = lazyP.set(*paint); 1.929 + p->setImageFilter(NULL); 1.930 + paint = p; 1.931 + } 1.932 + } 1.933 + 1.934 + bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag); 1.935 + SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(), 1.936 + isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 1.937 + 1.938 + SkBaseDevice* device; 1.939 + if (paint && paint->getImageFilter()) { 1.940 + device = createCompatibleDevice(this, info); 1.941 + } else { 1.942 + device = this->createLayerDevice(info); 1.943 + } 1.944 + if (NULL == device) { 1.945 + SkDebugf("Unable to create device for layer."); 1.946 + return count; 1.947 + } 1.948 + 1.949 + device->setOrigin(ir.fLeft, ir.fTop); 1.950 + DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this)); 1.951 + device->unref(); 1.952 + 1.953 + layer->fNext = fMCRec->fTopLayer; 1.954 + fMCRec->fLayer = layer; 1.955 + fMCRec->fTopLayer = layer; // this field is NOT an owner of layer 1.956 + 1.957 + fSaveLayerCount += 1; 1.958 + return count; 1.959 +} 1.960 + 1.961 +int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, 1.962 + SaveFlags flags) { 1.963 + if (0xFF == alpha) { 1.964 + return this->saveLayer(bounds, NULL, flags); 1.965 + } else { 1.966 + SkPaint tmpPaint; 1.967 + tmpPaint.setAlpha(alpha); 1.968 + return this->saveLayer(bounds, &tmpPaint, flags); 1.969 + } 1.970 +} 1.971 + 1.972 +void SkCanvas::willRestore() { 1.973 + // Do nothing. Subclasses may do something. 1.974 +} 1.975 + 1.976 +void SkCanvas::restore() { 1.977 + // check for underflow 1.978 + if (fMCStack.count() > 1) { 1.979 + this->willRestore(); 1.980 + this->internalRestore(); 1.981 + } 1.982 +} 1.983 + 1.984 +void SkCanvas::internalRestore() { 1.985 + SkASSERT(fMCStack.count() != 0); 1.986 + 1.987 + fDeviceCMDirty = true; 1.988 + fCachedLocalClipBoundsDirty = true; 1.989 + 1.990 + if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) { 1.991 + fClipStack.restore(); 1.992 + } 1.993 + 1.994 + // reserve our layer (if any) 1.995 + DeviceCM* layer = fMCRec->fLayer; // may be null 1.996 + // now detach it from fMCRec so we can pop(). Gets freed after its drawn 1.997 + fMCRec->fLayer = NULL; 1.998 + 1.999 + // now do the normal restore() 1.1000 + fMCRec->~MCRec(); // balanced in save() 1.1001 + fMCStack.pop_back(); 1.1002 + fMCRec = (MCRec*)fMCStack.back(); 1.1003 + 1.1004 + /* Time to draw the layer's offscreen. We can't call the public drawSprite, 1.1005 + since if we're being recorded, we don't want to record this (the 1.1006 + recorder will have already recorded the restore). 1.1007 + */ 1.1008 + if (NULL != layer) { 1.1009 + if (layer->fNext) { 1.1010 + const SkIPoint& origin = layer->fDevice->getOrigin(); 1.1011 + this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), 1.1012 + layer->fPaint); 1.1013 + // reset this, since internalDrawDevice will have set it to true 1.1014 + fDeviceCMDirty = true; 1.1015 + 1.1016 + SkASSERT(fSaveLayerCount > 0); 1.1017 + fSaveLayerCount -= 1; 1.1018 + } 1.1019 + SkDELETE(layer); 1.1020 + } 1.1021 +} 1.1022 + 1.1023 +int SkCanvas::getSaveCount() const { 1.1024 + return fMCStack.count(); 1.1025 +} 1.1026 + 1.1027 +void SkCanvas::restoreToCount(int count) { 1.1028 + // sanity check 1.1029 + if (count < 1) { 1.1030 + count = 1; 1.1031 + } 1.1032 + 1.1033 + int n = this->getSaveCount() - count; 1.1034 + for (int i = 0; i < n; ++i) { 1.1035 + this->restore(); 1.1036 + } 1.1037 +} 1.1038 + 1.1039 +bool SkCanvas::isDrawingToLayer() const { 1.1040 + return fSaveLayerCount > 0; 1.1041 +} 1.1042 + 1.1043 +SkSurface* SkCanvas::newSurface(const SkImageInfo& info) { 1.1044 + return this->onNewSurface(info); 1.1045 +} 1.1046 + 1.1047 +SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) { 1.1048 + SkBaseDevice* dev = this->getDevice(); 1.1049 + return dev ? dev->newSurface(info) : NULL; 1.1050 +} 1.1051 + 1.1052 +SkImageInfo SkCanvas::imageInfo() const { 1.1053 + SkBaseDevice* dev = this->getDevice(); 1.1054 + if (dev) { 1.1055 + return dev->imageInfo(); 1.1056 + } else { 1.1057 + return SkImageInfo::MakeUnknown(0, 0); 1.1058 + } 1.1059 +} 1.1060 + 1.1061 +const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { 1.1062 + return this->onPeekPixels(info, rowBytes); 1.1063 +} 1.1064 + 1.1065 +const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) { 1.1066 + SkBaseDevice* dev = this->getDevice(); 1.1067 + return dev ? dev->peekPixels(info, rowBytes) : NULL; 1.1068 +} 1.1069 + 1.1070 +void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 1.1071 + return this->onAccessTopLayerPixels(info, rowBytes); 1.1072 +} 1.1073 + 1.1074 +void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { 1.1075 + SkBaseDevice* dev = this->getTopDevice(); 1.1076 + return dev ? dev->accessPixels(info, rowBytes) : NULL; 1.1077 +} 1.1078 + 1.1079 +SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { 1.1080 + fAddr = canvas->peekPixels(&fInfo, &fRowBytes); 1.1081 + if (NULL == fAddr) { 1.1082 + fInfo = canvas->imageInfo(); 1.1083 + if (kUnknown_SkColorType == fInfo.colorType() || 1.1084 + !fBitmap.allocPixels(fInfo)) 1.1085 + { 1.1086 + return; // failure, fAddr is NULL 1.1087 + } 1.1088 + fBitmap.lockPixels(); 1.1089 + if (!canvas->readPixels(&fBitmap, 0, 0)) { 1.1090 + return; // failure, fAddr is NULL 1.1091 + } 1.1092 + fAddr = fBitmap.getPixels(); 1.1093 + fRowBytes = fBitmap.rowBytes(); 1.1094 + } 1.1095 + SkASSERT(fAddr); // success 1.1096 +} 1.1097 + 1.1098 +bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { 1.1099 + if (fAddr) { 1.1100 + return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes, 1.1101 + NULL, NULL); 1.1102 + } else { 1.1103 + bitmap->reset(); 1.1104 + return false; 1.1105 + } 1.1106 +} 1.1107 + 1.1108 +void SkCanvas::onPushCull(const SkRect& cullRect) { 1.1109 + // do nothing. Subclasses may do something 1.1110 +} 1.1111 + 1.1112 +void SkCanvas::onPopCull() { 1.1113 + // do nothing. Subclasses may do something 1.1114 +} 1.1115 + 1.1116 +///////////////////////////////////////////////////////////////////////////// 1.1117 + 1.1118 +void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, 1.1119 + const SkMatrix& matrix, const SkPaint* paint) { 1.1120 + if (bitmap.drawsNothing()) { 1.1121 + return; 1.1122 + } 1.1123 + 1.1124 + SkLazyPaint lazy; 1.1125 + if (NULL == paint) { 1.1126 + paint = lazy.init(); 1.1127 + } 1.1128 + 1.1129 + SkDEBUGCODE(bitmap.validate();) 1.1130 + CHECK_LOCKCOUNT_BALANCE(bitmap); 1.1131 + 1.1132 + SkRect storage; 1.1133 + const SkRect* bounds = NULL; 1.1134 + if (paint && paint->canComputeFastBounds()) { 1.1135 + bitmap.getBounds(&storage); 1.1136 + matrix.mapRect(&storage); 1.1137 + bounds = &paint->computeFastBounds(storage, &storage); 1.1138 + } 1.1139 + 1.1140 + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1.1141 + 1.1142 + while (iter.next()) { 1.1143 + iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 1.1144 + } 1.1145 + 1.1146 + LOOPER_END 1.1147 +} 1.1148 + 1.1149 +void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, 1.1150 + const SkPaint* paint) { 1.1151 + SkPaint tmp; 1.1152 + if (NULL == paint) { 1.1153 + tmp.setDither(true); 1.1154 + paint = &tmp; 1.1155 + } 1.1156 + 1.1157 + LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1.1158 + while (iter.next()) { 1.1159 + SkBaseDevice* dstDev = iter.fDevice; 1.1160 + paint = &looper.paint(); 1.1161 + SkImageFilter* filter = paint->getImageFilter(); 1.1162 + SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1.1163 + if (filter && !dstDev->canHandleImageFilter(filter)) { 1.1164 + SkDeviceImageFilterProxy proxy(dstDev); 1.1165 + SkBitmap dst; 1.1166 + SkIPoint offset = SkIPoint::Make(0, 0); 1.1167 + const SkBitmap& src = srcDev->accessBitmap(false); 1.1168 + SkMatrix matrix = *iter.fMatrix; 1.1169 + matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1.1170 + SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height()); 1.1171 + SkImageFilter::Context ctx(matrix, clipBounds); 1.1172 + if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { 1.1173 + SkPaint tmpUnfiltered(*paint); 1.1174 + tmpUnfiltered.setImageFilter(NULL); 1.1175 + dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1.1176 + tmpUnfiltered); 1.1177 + } 1.1178 + } else { 1.1179 + dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); 1.1180 + } 1.1181 + } 1.1182 + LOOPER_END 1.1183 +} 1.1184 + 1.1185 +void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 1.1186 + const SkPaint* paint) { 1.1187 + if (bitmap.drawsNothing()) { 1.1188 + return; 1.1189 + } 1.1190 + SkDEBUGCODE(bitmap.validate();) 1.1191 + CHECK_LOCKCOUNT_BALANCE(bitmap); 1.1192 + 1.1193 + SkPaint tmp; 1.1194 + if (NULL == paint) { 1.1195 + paint = &tmp; 1.1196 + } 1.1197 + 1.1198 + LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) 1.1199 + 1.1200 + while (iter.next()) { 1.1201 + paint = &looper.paint(); 1.1202 + SkImageFilter* filter = paint->getImageFilter(); 1.1203 + SkIPoint pos = { x - iter.getX(), y - iter.getY() }; 1.1204 + if (filter && !iter.fDevice->canHandleImageFilter(filter)) { 1.1205 + SkDeviceImageFilterProxy proxy(iter.fDevice); 1.1206 + SkBitmap dst; 1.1207 + SkIPoint offset = SkIPoint::Make(0, 0); 1.1208 + SkMatrix matrix = *iter.fMatrix; 1.1209 + matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1.1210 + SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1.1211 + SkImageFilter::Context ctx(matrix, clipBounds); 1.1212 + if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { 1.1213 + SkPaint tmpUnfiltered(*paint); 1.1214 + tmpUnfiltered.setImageFilter(NULL); 1.1215 + iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), 1.1216 + tmpUnfiltered); 1.1217 + } 1.1218 + } else { 1.1219 + iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); 1.1220 + } 1.1221 + } 1.1222 + LOOPER_END 1.1223 +} 1.1224 + 1.1225 +///////////////////////////////////////////////////////////////////////////// 1.1226 +void SkCanvas::didTranslate(SkScalar, SkScalar) { 1.1227 + // Do nothing. Subclasses may do something. 1.1228 +} 1.1229 + 1.1230 +bool SkCanvas::translate(SkScalar dx, SkScalar dy) { 1.1231 + fDeviceCMDirty = true; 1.1232 + fCachedLocalClipBoundsDirty = true; 1.1233 + bool res = fMCRec->fMatrix->preTranslate(dx, dy); 1.1234 + 1.1235 + this->didTranslate(dx, dy); 1.1236 + return res; 1.1237 +} 1.1238 + 1.1239 +void SkCanvas::didScale(SkScalar, SkScalar) { 1.1240 + // Do nothing. Subclasses may do something. 1.1241 +} 1.1242 + 1.1243 +bool SkCanvas::scale(SkScalar sx, SkScalar sy) { 1.1244 + fDeviceCMDirty = true; 1.1245 + fCachedLocalClipBoundsDirty = true; 1.1246 + bool res = fMCRec->fMatrix->preScale(sx, sy); 1.1247 + 1.1248 + this->didScale(sx, sy); 1.1249 + return res; 1.1250 +} 1.1251 + 1.1252 +void SkCanvas::didRotate(SkScalar) { 1.1253 + // Do nothing. Subclasses may do something. 1.1254 +} 1.1255 + 1.1256 +bool SkCanvas::rotate(SkScalar degrees) { 1.1257 + fDeviceCMDirty = true; 1.1258 + fCachedLocalClipBoundsDirty = true; 1.1259 + bool res = fMCRec->fMatrix->preRotate(degrees); 1.1260 + 1.1261 + this->didRotate(degrees); 1.1262 + return res; 1.1263 +} 1.1264 + 1.1265 +void SkCanvas::didSkew(SkScalar, SkScalar) { 1.1266 + // Do nothing. Subclasses may do something. 1.1267 +} 1.1268 + 1.1269 +bool SkCanvas::skew(SkScalar sx, SkScalar sy) { 1.1270 + fDeviceCMDirty = true; 1.1271 + fCachedLocalClipBoundsDirty = true; 1.1272 + bool res = fMCRec->fMatrix->preSkew(sx, sy); 1.1273 + 1.1274 + this->didSkew(sx, sy); 1.1275 + return res; 1.1276 +} 1.1277 + 1.1278 +void SkCanvas::didConcat(const SkMatrix&) { 1.1279 + // Do nothing. Subclasses may do something. 1.1280 +} 1.1281 + 1.1282 +bool SkCanvas::concat(const SkMatrix& matrix) { 1.1283 + fDeviceCMDirty = true; 1.1284 + fCachedLocalClipBoundsDirty = true; 1.1285 + bool res = fMCRec->fMatrix->preConcat(matrix); 1.1286 + 1.1287 + this->didConcat(matrix); 1.1288 + return res; 1.1289 +} 1.1290 + 1.1291 +void SkCanvas::didSetMatrix(const SkMatrix&) { 1.1292 + // Do nothing. Subclasses may do something. 1.1293 +} 1.1294 + 1.1295 +void SkCanvas::setMatrix(const SkMatrix& matrix) { 1.1296 + fDeviceCMDirty = true; 1.1297 + fCachedLocalClipBoundsDirty = true; 1.1298 + *fMCRec->fMatrix = matrix; 1.1299 + this->didSetMatrix(matrix); 1.1300 +} 1.1301 + 1.1302 +void SkCanvas::resetMatrix() { 1.1303 + SkMatrix matrix; 1.1304 + 1.1305 + matrix.reset(); 1.1306 + this->setMatrix(matrix); 1.1307 +} 1.1308 + 1.1309 +////////////////////////////////////////////////////////////////////////////// 1.1310 + 1.1311 +void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1.1312 + ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1.1313 + this->onClipRect(rect, op, edgeStyle); 1.1314 +} 1.1315 + 1.1316 +void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1.1317 +#ifdef SK_ENABLE_CLIP_QUICKREJECT 1.1318 + if (SkRegion::kIntersect_Op == op) { 1.1319 + if (fMCRec->fRasterClip->isEmpty()) { 1.1320 + return false; 1.1321 + } 1.1322 + 1.1323 + if (this->quickReject(rect)) { 1.1324 + fDeviceCMDirty = true; 1.1325 + fCachedLocalClipBoundsDirty = true; 1.1326 + 1.1327 + fClipStack.clipEmpty(); 1.1328 + return fMCRec->fRasterClip->setEmpty(); 1.1329 + } 1.1330 + } 1.1331 +#endif 1.1332 + 1.1333 + AutoValidateClip avc(this); 1.1334 + 1.1335 + fDeviceCMDirty = true; 1.1336 + fCachedLocalClipBoundsDirty = true; 1.1337 + if (!fAllowSoftClip) { 1.1338 + edgeStyle = kHard_ClipEdgeStyle; 1.1339 + } 1.1340 + 1.1341 + if (fMCRec->fMatrix->rectStaysRect()) { 1.1342 + // for these simpler matrices, we can stay a rect even after applying 1.1343 + // the matrix. This means we don't have to a) make a path, and b) tell 1.1344 + // the region code to scan-convert the path, only to discover that it 1.1345 + // is really just a rect. 1.1346 + SkRect r; 1.1347 + 1.1348 + fMCRec->fMatrix->mapRect(&r, rect); 1.1349 + fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1.1350 + fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); 1.1351 + } else { 1.1352 + // since we're rotated or some such thing, we convert the rect to a path 1.1353 + // and clip against that, since it can handle any matrix. However, to 1.1354 + // avoid recursion in the case where we are subclassed (e.g. Pictures) 1.1355 + // we explicitly call "our" version of clipPath. 1.1356 + SkPath path; 1.1357 + 1.1358 + path.addRect(rect); 1.1359 + this->SkCanvas::onClipPath(path, op, edgeStyle); 1.1360 + } 1.1361 +} 1.1362 + 1.1363 +static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, 1.1364 + const SkPath& devPath, SkRegion::Op op, bool doAA) { 1.1365 + // base is used to limit the size (and therefore memory allocation) of the 1.1366 + // region that results from scan converting devPath. 1.1367 + SkRegion base; 1.1368 + 1.1369 + if (SkRegion::kIntersect_Op == op) { 1.1370 + // since we are intersect, we can do better (tighter) with currRgn's 1.1371 + // bounds, than just using the device. However, if currRgn is complex, 1.1372 + // our region blitter may hork, so we do that case in two steps. 1.1373 + if (currClip->isRect()) { 1.1374 + // FIXME: we should also be able to do this when currClip->isBW(), 1.1375 + // but relaxing the test above triggers GM asserts in 1.1376 + // SkRgnBuilder::blitH(). We need to investigate what's going on. 1.1377 + currClip->setPath(devPath, currClip->bwRgn(), doAA); 1.1378 + } else { 1.1379 + base.setRect(currClip->getBounds()); 1.1380 + SkRasterClip clip; 1.1381 + clip.setPath(devPath, base, doAA); 1.1382 + currClip->op(clip, op); 1.1383 + } 1.1384 + } else { 1.1385 + const SkBaseDevice* device = canvas->getDevice(); 1.1386 + if (!device) { 1.1387 + currClip->setEmpty(); 1.1388 + return; 1.1389 + } 1.1390 + 1.1391 + base.setRect(0, 0, device->width(), device->height()); 1.1392 + 1.1393 + if (SkRegion::kReplace_Op == op) { 1.1394 + currClip->setPath(devPath, base, doAA); 1.1395 + } else { 1.1396 + SkRasterClip clip; 1.1397 + clip.setPath(devPath, base, doAA); 1.1398 + currClip->op(clip, op); 1.1399 + } 1.1400 + } 1.1401 +} 1.1402 + 1.1403 +void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1.1404 + ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1.1405 + if (rrect.isRect()) { 1.1406 + this->onClipRect(rrect.getBounds(), op, edgeStyle); 1.1407 + } else { 1.1408 + this->onClipRRect(rrect, op, edgeStyle); 1.1409 + } 1.1410 +} 1.1411 + 1.1412 +void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1.1413 + SkRRect transformedRRect; 1.1414 + if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { 1.1415 + AutoValidateClip avc(this); 1.1416 + 1.1417 + fDeviceCMDirty = true; 1.1418 + fCachedLocalClipBoundsDirty = true; 1.1419 + if (!fAllowSoftClip) { 1.1420 + edgeStyle = kHard_ClipEdgeStyle; 1.1421 + } 1.1422 + 1.1423 + fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); 1.1424 + 1.1425 + SkPath devPath; 1.1426 + devPath.addRRect(transformedRRect); 1.1427 + 1.1428 + clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1.1429 + return; 1.1430 + } 1.1431 + 1.1432 + SkPath path; 1.1433 + path.addRRect(rrect); 1.1434 + // call the non-virtual version 1.1435 + this->SkCanvas::onClipPath(path, op, edgeStyle); 1.1436 +} 1.1437 + 1.1438 +void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1.1439 + ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1.1440 + SkRect r; 1.1441 + if (!path.isInverseFillType() && path.isRect(&r)) { 1.1442 + this->onClipRect(r, op, edgeStyle); 1.1443 + } else { 1.1444 + this->onClipPath(path, op, edgeStyle); 1.1445 + } 1.1446 +} 1.1447 + 1.1448 +void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1.1449 +#ifdef SK_ENABLE_CLIP_QUICKREJECT 1.1450 + if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { 1.1451 + if (fMCRec->fRasterClip->isEmpty()) { 1.1452 + return false; 1.1453 + } 1.1454 + 1.1455 + if (this->quickReject(path.getBounds())) { 1.1456 + fDeviceCMDirty = true; 1.1457 + fCachedLocalClipBoundsDirty = true; 1.1458 + 1.1459 + fClipStack.clipEmpty(); 1.1460 + return fMCRec->fRasterClip->setEmpty(); 1.1461 + } 1.1462 + } 1.1463 +#endif 1.1464 + 1.1465 + AutoValidateClip avc(this); 1.1466 + 1.1467 + fDeviceCMDirty = true; 1.1468 + fCachedLocalClipBoundsDirty = true; 1.1469 + if (!fAllowSoftClip) { 1.1470 + edgeStyle = kHard_ClipEdgeStyle; 1.1471 + } 1.1472 + 1.1473 + SkPath devPath; 1.1474 + path.transform(*fMCRec->fMatrix, &devPath); 1.1475 + 1.1476 + // Check if the transfomation, or the original path itself 1.1477 + // made us empty. Note this can also happen if we contained NaN 1.1478 + // values. computing the bounds detects this, and will set our 1.1479 + // bounds to empty if that is the case. (see SkRect::set(pts, count)) 1.1480 + if (devPath.getBounds().isEmpty()) { 1.1481 + // resetting the path will remove any NaN or other wanky values 1.1482 + // that might upset our scan converter. 1.1483 + devPath.reset(); 1.1484 + } 1.1485 + 1.1486 + // if we called path.swap() we could avoid a deep copy of this path 1.1487 + fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); 1.1488 + 1.1489 + if (fAllowSimplifyClip) { 1.1490 + devPath.reset(); 1.1491 + devPath.setFillType(SkPath::kInverseEvenOdd_FillType); 1.1492 + const SkClipStack* clipStack = getClipStack(); 1.1493 + SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart); 1.1494 + const SkClipStack::Element* element; 1.1495 + while ((element = iter.next())) { 1.1496 + SkClipStack::Element::Type type = element->getType(); 1.1497 + if (type == SkClipStack::Element::kEmpty_Type) { 1.1498 + continue; 1.1499 + } 1.1500 + SkPath operand; 1.1501 + element->asPath(&operand); 1.1502 + SkRegion::Op elementOp = element->getOp(); 1.1503 + if (elementOp == SkRegion::kReplace_Op) { 1.1504 + devPath = operand; 1.1505 + } else { 1.1506 + Op(devPath, operand, (SkPathOp) elementOp, &devPath); 1.1507 + } 1.1508 + // if the prev and curr clips disagree about aa -vs- not, favor the aa request. 1.1509 + // perhaps we need an API change to avoid this sort of mixed-signals about 1.1510 + // clipping. 1.1511 + if (element->isAA()) { 1.1512 + edgeStyle = kSoft_ClipEdgeStyle; 1.1513 + } 1.1514 + } 1.1515 + op = SkRegion::kReplace_Op; 1.1516 + } 1.1517 + 1.1518 + clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); 1.1519 +} 1.1520 + 1.1521 +void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, 1.1522 + bool inverseFilled) { 1.1523 + // This is for updating the clip conservatively using only bounds 1.1524 + // information. 1.1525 + // Contract: 1.1526 + // The current clip must contain the true clip. The true 1.1527 + // clip is the clip that would have normally been computed 1.1528 + // by calls to clipPath and clipRRect 1.1529 + // Objective: 1.1530 + // Keep the current clip as small as possible without 1.1531 + // breaking the contract, using only clip bounding rectangles 1.1532 + // (for performance). 1.1533 + 1.1534 + // N.B.: This *never* calls back through a virtual on canvas, so subclasses 1.1535 + // don't have to worry about getting caught in a loop. Thus anywhere 1.1536 + // we call a virtual method, we explicitly prefix it with 1.1537 + // SkCanvas:: to be sure to call the base-class. 1.1538 + 1.1539 + if (inverseFilled) { 1.1540 + switch (op) { 1.1541 + case SkRegion::kIntersect_Op: 1.1542 + case SkRegion::kDifference_Op: 1.1543 + // These ops can only shrink the current clip. So leaving 1.1544 + // the clip unchanged conservatively respects the contract. 1.1545 + break; 1.1546 + case SkRegion::kUnion_Op: 1.1547 + case SkRegion::kReplace_Op: 1.1548 + case SkRegion::kReverseDifference_Op: 1.1549 + case SkRegion::kXOR_Op: { 1.1550 + // These ops can grow the current clip up to the extents of 1.1551 + // the input clip, which is inverse filled, so we just set 1.1552 + // the current clip to the device bounds. 1.1553 + SkRect deviceBounds; 1.1554 + SkIRect deviceIBounds; 1.1555 + this->getDevice()->getGlobalBounds(&deviceIBounds); 1.1556 + deviceBounds = SkRect::Make(deviceIBounds); 1.1557 + this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); 1.1558 + // set the clip in device space 1.1559 + this->SkCanvas::setMatrix(SkMatrix::I()); 1.1560 + this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op, 1.1561 + kHard_ClipEdgeStyle); 1.1562 + this->SkCanvas::restore(); //pop the matrix, but keep the clip 1.1563 + break; 1.1564 + } 1.1565 + default: 1.1566 + SkASSERT(0); // unhandled op? 1.1567 + } 1.1568 + } else { 1.1569 + // Not inverse filled 1.1570 + switch (op) { 1.1571 + case SkRegion::kIntersect_Op: 1.1572 + case SkRegion::kUnion_Op: 1.1573 + case SkRegion::kReplace_Op: 1.1574 + this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); 1.1575 + break; 1.1576 + case SkRegion::kDifference_Op: 1.1577 + // Difference can only shrink the current clip. 1.1578 + // Leaving clip unchanged conservatively fullfills the contract. 1.1579 + break; 1.1580 + case SkRegion::kReverseDifference_Op: 1.1581 + // To reverse, we swap in the bounds with a replace op. 1.1582 + // As with difference, leave it unchanged. 1.1583 + this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle); 1.1584 + break; 1.1585 + case SkRegion::kXOR_Op: 1.1586 + // Be conservative, based on (A XOR B) always included in (A union B), 1.1587 + // which is always included in (bounds(A) union bounds(B)) 1.1588 + this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle); 1.1589 + break; 1.1590 + default: 1.1591 + SkASSERT(0); // unhandled op? 1.1592 + } 1.1593 + } 1.1594 +} 1.1595 + 1.1596 +void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1.1597 + this->onClipRegion(rgn, op); 1.1598 +} 1.1599 + 1.1600 +void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1.1601 + AutoValidateClip avc(this); 1.1602 + 1.1603 + fDeviceCMDirty = true; 1.1604 + fCachedLocalClipBoundsDirty = true; 1.1605 + 1.1606 + // todo: signal fClipStack that we have a region, and therefore (I guess) 1.1607 + // we have to ignore it, and use the region directly? 1.1608 + fClipStack.clipDevRect(rgn.getBounds(), op); 1.1609 + 1.1610 + fMCRec->fRasterClip->op(rgn, op); 1.1611 +} 1.1612 + 1.1613 +#ifdef SK_DEBUG 1.1614 +void SkCanvas::validateClip() const { 1.1615 + // construct clipRgn from the clipstack 1.1616 + const SkBaseDevice* device = this->getDevice(); 1.1617 + if (!device) { 1.1618 + SkASSERT(this->isClipEmpty()); 1.1619 + return; 1.1620 + } 1.1621 + 1.1622 + SkIRect ir; 1.1623 + ir.set(0, 0, device->width(), device->height()); 1.1624 + SkRasterClip tmpClip(ir); 1.1625 + 1.1626 + SkClipStack::B2TIter iter(fClipStack); 1.1627 + const SkClipStack::Element* element; 1.1628 + while ((element = iter.next()) != NULL) { 1.1629 + switch (element->getType()) { 1.1630 + case SkClipStack::Element::kRect_Type: 1.1631 + element->getRect().round(&ir); 1.1632 + tmpClip.op(ir, element->getOp()); 1.1633 + break; 1.1634 + case SkClipStack::Element::kEmpty_Type: 1.1635 + tmpClip.setEmpty(); 1.1636 + break; 1.1637 + default: { 1.1638 + SkPath path; 1.1639 + element->asPath(&path); 1.1640 + clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA()); 1.1641 + break; 1.1642 + } 1.1643 + } 1.1644 + } 1.1645 +} 1.1646 +#endif 1.1647 + 1.1648 +void SkCanvas::replayClips(ClipVisitor* visitor) const { 1.1649 + SkClipStack::B2TIter iter(fClipStack); 1.1650 + const SkClipStack::Element* element; 1.1651 + 1.1652 + static const SkRect kEmpty = { 0, 0, 0, 0 }; 1.1653 + while ((element = iter.next()) != NULL) { 1.1654 + switch (element->getType()) { 1.1655 + case SkClipStack::Element::kPath_Type: 1.1656 + visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); 1.1657 + break; 1.1658 + case SkClipStack::Element::kRRect_Type: 1.1659 + visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA()); 1.1660 + break; 1.1661 + case SkClipStack::Element::kRect_Type: 1.1662 + visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); 1.1663 + break; 1.1664 + case SkClipStack::Element::kEmpty_Type: 1.1665 + visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); 1.1666 + break; 1.1667 + } 1.1668 + } 1.1669 +} 1.1670 + 1.1671 +/////////////////////////////////////////////////////////////////////////////// 1.1672 + 1.1673 +bool SkCanvas::isClipEmpty() const { 1.1674 + return fMCRec->fRasterClip->isEmpty(); 1.1675 +} 1.1676 + 1.1677 +bool SkCanvas::isClipRect() const { 1.1678 + return fMCRec->fRasterClip->isRect(); 1.1679 +} 1.1680 + 1.1681 +bool SkCanvas::quickReject(const SkRect& rect) const { 1.1682 + 1.1683 + if (!rect.isFinite()) 1.1684 + return true; 1.1685 + 1.1686 + if (fMCRec->fRasterClip->isEmpty()) { 1.1687 + return true; 1.1688 + } 1.1689 + 1.1690 + if (fMCRec->fMatrix->hasPerspective()) { 1.1691 + SkRect dst; 1.1692 + fMCRec->fMatrix->mapRect(&dst, rect); 1.1693 + SkIRect idst; 1.1694 + dst.roundOut(&idst); 1.1695 + return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); 1.1696 + } else { 1.1697 + const SkRect& clipR = this->getLocalClipBounds(); 1.1698 + 1.1699 + // for speed, do the most likely reject compares first 1.1700 + // TODO: should we use | instead, or compare all 4 at once? 1.1701 + if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1.1702 + return true; 1.1703 + } 1.1704 + if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1.1705 + return true; 1.1706 + } 1.1707 + return false; 1.1708 + } 1.1709 +} 1.1710 + 1.1711 +bool SkCanvas::quickReject(const SkPath& path) const { 1.1712 + return path.isEmpty() || this->quickReject(path.getBounds()); 1.1713 +} 1.1714 + 1.1715 +bool SkCanvas::getClipBounds(SkRect* bounds) const { 1.1716 + SkIRect ibounds; 1.1717 + if (!this->getClipDeviceBounds(&ibounds)) { 1.1718 + return false; 1.1719 + } 1.1720 + 1.1721 + SkMatrix inverse; 1.1722 + // if we can't invert the CTM, we can't return local clip bounds 1.1723 + if (!fMCRec->fMatrix->invert(&inverse)) { 1.1724 + if (bounds) { 1.1725 + bounds->setEmpty(); 1.1726 + } 1.1727 + return false; 1.1728 + } 1.1729 + 1.1730 + if (NULL != bounds) { 1.1731 + SkRect r; 1.1732 + // adjust it outwards in case we are antialiasing 1.1733 + const int inset = 1; 1.1734 + 1.1735 + r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, 1.1736 + ibounds.fRight + inset, ibounds.fBottom + inset); 1.1737 + inverse.mapRect(bounds, r); 1.1738 + } 1.1739 + return true; 1.1740 +} 1.1741 + 1.1742 +bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { 1.1743 + const SkRasterClip& clip = *fMCRec->fRasterClip; 1.1744 + if (clip.isEmpty()) { 1.1745 + if (bounds) { 1.1746 + bounds->setEmpty(); 1.1747 + } 1.1748 + return false; 1.1749 + } 1.1750 + 1.1751 + if (NULL != bounds) { 1.1752 + *bounds = clip.getBounds(); 1.1753 + } 1.1754 + return true; 1.1755 +} 1.1756 + 1.1757 +const SkMatrix& SkCanvas::getTotalMatrix() const { 1.1758 + return *fMCRec->fMatrix; 1.1759 +} 1.1760 + 1.1761 +#ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE 1.1762 +SkCanvas::ClipType SkCanvas::getClipType() const { 1.1763 + if (fMCRec->fRasterClip->isEmpty()) { 1.1764 + return kEmpty_ClipType; 1.1765 + } 1.1766 + if (fMCRec->fRasterClip->isRect()) { 1.1767 + return kRect_ClipType; 1.1768 + } 1.1769 + return kComplex_ClipType; 1.1770 +} 1.1771 +#endif 1.1772 + 1.1773 +#ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP 1.1774 +const SkRegion& SkCanvas::getTotalClip() const { 1.1775 + return fMCRec->fRasterClip->forceGetBW(); 1.1776 +} 1.1777 +#endif 1.1778 + 1.1779 +const SkRegion& SkCanvas::internal_private_getTotalClip() const { 1.1780 + return fMCRec->fRasterClip->forceGetBW(); 1.1781 +} 1.1782 + 1.1783 +void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const { 1.1784 + path->reset(); 1.1785 + 1.1786 + const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW(); 1.1787 + if (rgn.isEmpty()) { 1.1788 + return; 1.1789 + } 1.1790 + (void)rgn.getBoundaryPath(path); 1.1791 +} 1.1792 + 1.1793 +GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() { 1.1794 + SkBaseDevice* dev = this->getTopDevice(); 1.1795 + return dev ? dev->accessRenderTarget() : NULL; 1.1796 +} 1.1797 + 1.1798 +SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { 1.1799 + SkBaseDevice* device = this->getTopDevice(); 1.1800 + return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; 1.1801 +} 1.1802 + 1.1803 +GrContext* SkCanvas::getGrContext() { 1.1804 +#if SK_SUPPORT_GPU 1.1805 + SkBaseDevice* device = this->getTopDevice(); 1.1806 + if (NULL != device) { 1.1807 + GrRenderTarget* renderTarget = device->accessRenderTarget(); 1.1808 + if (NULL != renderTarget) { 1.1809 + return renderTarget->getContext(); 1.1810 + } 1.1811 + } 1.1812 +#endif 1.1813 + 1.1814 + return NULL; 1.1815 + 1.1816 +} 1.1817 + 1.1818 +void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, 1.1819 + const SkPaint& paint) { 1.1820 + if (outer.isEmpty()) { 1.1821 + return; 1.1822 + } 1.1823 + if (inner.isEmpty()) { 1.1824 + this->drawRRect(outer, paint); 1.1825 + return; 1.1826 + } 1.1827 + 1.1828 + // We don't have this method (yet), but technically this is what we should 1.1829 + // be able to assert... 1.1830 + // SkASSERT(outer.contains(inner)); 1.1831 + // 1.1832 + // For now at least check for containment of bounds 1.1833 + SkASSERT(outer.getBounds().contains(inner.getBounds())); 1.1834 + 1.1835 + this->onDrawDRRect(outer, inner, paint); 1.1836 +} 1.1837 + 1.1838 +////////////////////////////////////////////////////////////////////////////// 1.1839 +// These are the virtual drawing methods 1.1840 +////////////////////////////////////////////////////////////////////////////// 1.1841 + 1.1842 +void SkCanvas::clear(SkColor color) { 1.1843 + SkDrawIter iter(this); 1.1844 + this->predrawNotify(); 1.1845 + while (iter.next()) { 1.1846 + iter.fDevice->clear(color); 1.1847 + } 1.1848 +} 1.1849 + 1.1850 +void SkCanvas::drawPaint(const SkPaint& paint) { 1.1851 + this->internalDrawPaint(paint); 1.1852 +} 1.1853 + 1.1854 +void SkCanvas::internalDrawPaint(const SkPaint& paint) { 1.1855 + CHECK_SHADER_NOSETCONTEXT(paint); 1.1856 + 1.1857 + LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) 1.1858 + 1.1859 + while (iter.next()) { 1.1860 + iter.fDevice->drawPaint(iter, looper.paint()); 1.1861 + } 1.1862 + 1.1863 + LOOPER_END 1.1864 +} 1.1865 + 1.1866 +void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1.1867 + const SkPaint& paint) { 1.1868 + if ((long)count <= 0) { 1.1869 + return; 1.1870 + } 1.1871 + 1.1872 + CHECK_SHADER_NOSETCONTEXT(paint); 1.1873 + 1.1874 + SkRect r, storage; 1.1875 + const SkRect* bounds = NULL; 1.1876 + if (paint.canComputeFastBounds()) { 1.1877 + // special-case 2 points (common for drawing a single line) 1.1878 + if (2 == count) { 1.1879 + r.set(pts[0], pts[1]); 1.1880 + } else { 1.1881 + r.set(pts, SkToInt(count)); 1.1882 + } 1.1883 + bounds = &paint.computeFastStrokeBounds(r, &storage); 1.1884 + if (this->quickReject(*bounds)) { 1.1885 + return; 1.1886 + } 1.1887 + } 1.1888 + 1.1889 + SkASSERT(pts != NULL); 1.1890 + 1.1891 + LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) 1.1892 + 1.1893 + while (iter.next()) { 1.1894 + iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); 1.1895 + } 1.1896 + 1.1897 + LOOPER_END 1.1898 +} 1.1899 + 1.1900 +void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { 1.1901 + CHECK_SHADER_NOSETCONTEXT(paint); 1.1902 + 1.1903 + SkRect storage; 1.1904 + const SkRect* bounds = NULL; 1.1905 + if (paint.canComputeFastBounds()) { 1.1906 + bounds = &paint.computeFastBounds(r, &storage); 1.1907 + if (this->quickReject(*bounds)) { 1.1908 + return; 1.1909 + } 1.1910 + } 1.1911 + 1.1912 + LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) 1.1913 + 1.1914 + while (iter.next()) { 1.1915 + iter.fDevice->drawRect(iter, r, looper.paint()); 1.1916 + } 1.1917 + 1.1918 + LOOPER_END 1.1919 +} 1.1920 + 1.1921 +void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 1.1922 + CHECK_SHADER_NOSETCONTEXT(paint); 1.1923 + 1.1924 + SkRect storage; 1.1925 + const SkRect* bounds = NULL; 1.1926 + if (paint.canComputeFastBounds()) { 1.1927 + bounds = &paint.computeFastBounds(oval, &storage); 1.1928 + if (this->quickReject(*bounds)) { 1.1929 + return; 1.1930 + } 1.1931 + } 1.1932 + 1.1933 + LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) 1.1934 + 1.1935 + while (iter.next()) { 1.1936 + iter.fDevice->drawOval(iter, oval, looper.paint()); 1.1937 + } 1.1938 + 1.1939 + LOOPER_END 1.1940 +} 1.1941 + 1.1942 +void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1.1943 + CHECK_SHADER_NOSETCONTEXT(paint); 1.1944 + 1.1945 + SkRect storage; 1.1946 + const SkRect* bounds = NULL; 1.1947 + if (paint.canComputeFastBounds()) { 1.1948 + bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); 1.1949 + if (this->quickReject(*bounds)) { 1.1950 + return; 1.1951 + } 1.1952 + } 1.1953 + 1.1954 + if (rrect.isRect()) { 1.1955 + // call the non-virtual version 1.1956 + this->SkCanvas::drawRect(rrect.getBounds(), paint); 1.1957 + return; 1.1958 + } else if (rrect.isOval()) { 1.1959 + // call the non-virtual version 1.1960 + this->SkCanvas::drawOval(rrect.getBounds(), paint); 1.1961 + return; 1.1962 + } 1.1963 + 1.1964 + LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 1.1965 + 1.1966 + while (iter.next()) { 1.1967 + iter.fDevice->drawRRect(iter, rrect, looper.paint()); 1.1968 + } 1.1969 + 1.1970 + LOOPER_END 1.1971 +} 1.1972 + 1.1973 +void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 1.1974 + const SkPaint& paint) { 1.1975 + CHECK_SHADER_NOSETCONTEXT(paint); 1.1976 + 1.1977 + SkRect storage; 1.1978 + const SkRect* bounds = NULL; 1.1979 + if (paint.canComputeFastBounds()) { 1.1980 + bounds = &paint.computeFastBounds(outer.getBounds(), &storage); 1.1981 + if (this->quickReject(*bounds)) { 1.1982 + return; 1.1983 + } 1.1984 + } 1.1985 + 1.1986 + LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) 1.1987 + 1.1988 + while (iter.next()) { 1.1989 + iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); 1.1990 + } 1.1991 + 1.1992 + LOOPER_END 1.1993 +} 1.1994 + 1.1995 +void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 1.1996 + CHECK_SHADER_NOSETCONTEXT(paint); 1.1997 + 1.1998 + if (!path.isFinite()) { 1.1999 + return; 1.2000 + } 1.2001 + 1.2002 + SkRect storage; 1.2003 + const SkRect* bounds = NULL; 1.2004 + if (!path.isInverseFillType() && paint.canComputeFastBounds()) { 1.2005 + const SkRect& pathBounds = path.getBounds(); 1.2006 + bounds = &paint.computeFastBounds(pathBounds, &storage); 1.2007 + if (this->quickReject(*bounds)) { 1.2008 + return; 1.2009 + } 1.2010 + } 1.2011 + 1.2012 + const SkRect& r = path.getBounds(); 1.2013 + if (r.width() <= 0 && r.height() <= 0) { 1.2014 + if (path.isInverseFillType()) { 1.2015 + this->internalDrawPaint(paint); 1.2016 + } 1.2017 + return; 1.2018 + } 1.2019 + 1.2020 + LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) 1.2021 + 1.2022 + while (iter.next()) { 1.2023 + iter.fDevice->drawPath(iter, path, looper.paint()); 1.2024 + } 1.2025 + 1.2026 + LOOPER_END 1.2027 +} 1.2028 + 1.2029 +void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, 1.2030 + const SkPaint* paint) { 1.2031 + SkDEBUGCODE(bitmap.validate();) 1.2032 + 1.2033 + if (NULL == paint || paint->canComputeFastBounds()) { 1.2034 + SkRect bounds = { 1.2035 + x, y, 1.2036 + x + SkIntToScalar(bitmap.width()), 1.2037 + y + SkIntToScalar(bitmap.height()) 1.2038 + }; 1.2039 + if (paint) { 1.2040 + (void)paint->computeFastBounds(bounds, &bounds); 1.2041 + } 1.2042 + if (this->quickReject(bounds)) { 1.2043 + return; 1.2044 + } 1.2045 + } 1.2046 + 1.2047 + SkMatrix matrix; 1.2048 + matrix.setTranslate(x, y); 1.2049 + this->internalDrawBitmap(bitmap, matrix, paint); 1.2050 +} 1.2051 + 1.2052 +// this one is non-virtual, so it can be called safely by other canvas apis 1.2053 +void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 1.2054 + const SkRect& dst, const SkPaint* paint, 1.2055 + DrawBitmapRectFlags flags) { 1.2056 + if (bitmap.drawsNothing() || dst.isEmpty()) { 1.2057 + return; 1.2058 + } 1.2059 + 1.2060 + CHECK_LOCKCOUNT_BALANCE(bitmap); 1.2061 + 1.2062 + SkRect storage; 1.2063 + const SkRect* bounds = &dst; 1.2064 + if (NULL == paint || paint->canComputeFastBounds()) { 1.2065 + if (paint) { 1.2066 + bounds = &paint->computeFastBounds(dst, &storage); 1.2067 + } 1.2068 + if (this->quickReject(*bounds)) { 1.2069 + return; 1.2070 + } 1.2071 + } 1.2072 + 1.2073 + SkLazyPaint lazy; 1.2074 + if (NULL == paint) { 1.2075 + paint = lazy.init(); 1.2076 + } 1.2077 + 1.2078 + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) 1.2079 + 1.2080 + while (iter.next()) { 1.2081 + iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags); 1.2082 + } 1.2083 + 1.2084 + LOOPER_END 1.2085 +} 1.2086 + 1.2087 +void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 1.2088 + const SkRect& dst, const SkPaint* paint, 1.2089 + DrawBitmapRectFlags flags) { 1.2090 + SkDEBUGCODE(bitmap.validate();) 1.2091 + this->internalDrawBitmapRect(bitmap, src, dst, paint, flags); 1.2092 +} 1.2093 + 1.2094 +void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1.2095 + const SkPaint* paint) { 1.2096 + SkDEBUGCODE(bitmap.validate();) 1.2097 + this->internalDrawBitmap(bitmap, matrix, paint); 1.2098 +} 1.2099 + 1.2100 +void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, 1.2101 + const SkIRect& center, const SkRect& dst, 1.2102 + const SkPaint* paint) { 1.2103 + if (bitmap.drawsNothing()) { 1.2104 + return; 1.2105 + } 1.2106 + if (NULL == paint || paint->canComputeFastBounds()) { 1.2107 + SkRect storage; 1.2108 + const SkRect* bounds = &dst; 1.2109 + if (paint) { 1.2110 + bounds = &paint->computeFastBounds(dst, &storage); 1.2111 + } 1.2112 + if (this->quickReject(*bounds)) { 1.2113 + return; 1.2114 + } 1.2115 + } 1.2116 + 1.2117 + const int32_t w = bitmap.width(); 1.2118 + const int32_t h = bitmap.height(); 1.2119 + 1.2120 + SkIRect c = center; 1.2121 + // pin center to the bounds of the bitmap 1.2122 + c.fLeft = SkMax32(0, center.fLeft); 1.2123 + c.fTop = SkMax32(0, center.fTop); 1.2124 + c.fRight = SkPin32(center.fRight, c.fLeft, w); 1.2125 + c.fBottom = SkPin32(center.fBottom, c.fTop, h); 1.2126 + 1.2127 + const SkScalar srcX[4] = { 1.2128 + 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) 1.2129 + }; 1.2130 + const SkScalar srcY[4] = { 1.2131 + 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) 1.2132 + }; 1.2133 + SkScalar dstX[4] = { 1.2134 + dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), 1.2135 + dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight 1.2136 + }; 1.2137 + SkScalar dstY[4] = { 1.2138 + dst.fTop, dst.fTop + SkIntToScalar(c.fTop), 1.2139 + dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom 1.2140 + }; 1.2141 + 1.2142 + if (dstX[1] > dstX[2]) { 1.2143 + dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); 1.2144 + dstX[2] = dstX[1]; 1.2145 + } 1.2146 + 1.2147 + if (dstY[1] > dstY[2]) { 1.2148 + dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); 1.2149 + dstY[2] = dstY[1]; 1.2150 + } 1.2151 + 1.2152 + for (int y = 0; y < 3; y++) { 1.2153 + SkRect s, d; 1.2154 + 1.2155 + s.fTop = srcY[y]; 1.2156 + s.fBottom = srcY[y+1]; 1.2157 + d.fTop = dstY[y]; 1.2158 + d.fBottom = dstY[y+1]; 1.2159 + for (int x = 0; x < 3; x++) { 1.2160 + s.fLeft = srcX[x]; 1.2161 + s.fRight = srcX[x+1]; 1.2162 + d.fLeft = dstX[x]; 1.2163 + d.fRight = dstX[x+1]; 1.2164 + this->internalDrawBitmapRect(bitmap, &s, d, paint, 1.2165 + kNone_DrawBitmapRectFlag); 1.2166 + } 1.2167 + } 1.2168 +} 1.2169 + 1.2170 +void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1.2171 + const SkRect& dst, const SkPaint* paint) { 1.2172 + SkDEBUGCODE(bitmap.validate();) 1.2173 + 1.2174 + // Need a device entry-point, so gpu can use a mesh 1.2175 + this->internalDrawBitmapNine(bitmap, center, dst, paint); 1.2176 +} 1.2177 + 1.2178 +class SkDeviceFilteredPaint { 1.2179 +public: 1.2180 + SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { 1.2181 + SkBaseDevice::TextFlags flags; 1.2182 + if (device->filterTextFlags(paint, &flags)) { 1.2183 + SkPaint* newPaint = fLazy.set(paint); 1.2184 + newPaint->setFlags(flags.fFlags); 1.2185 + newPaint->setHinting(flags.fHinting); 1.2186 + fPaint = newPaint; 1.2187 + } else { 1.2188 + fPaint = &paint; 1.2189 + } 1.2190 + } 1.2191 + 1.2192 + const SkPaint& paint() const { return *fPaint; } 1.2193 + 1.2194 +private: 1.2195 + const SkPaint* fPaint; 1.2196 + SkLazyPaint fLazy; 1.2197 +}; 1.2198 + 1.2199 +void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, 1.2200 + const SkRect& r, SkScalar textSize) { 1.2201 + if (paint.getStyle() == SkPaint::kFill_Style) { 1.2202 + draw.fDevice->drawRect(draw, r, paint); 1.2203 + } else { 1.2204 + SkPaint p(paint); 1.2205 + p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); 1.2206 + draw.fDevice->drawRect(draw, r, p); 1.2207 + } 1.2208 +} 1.2209 + 1.2210 +void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, 1.2211 + const char text[], size_t byteLength, 1.2212 + SkScalar x, SkScalar y) { 1.2213 + SkASSERT(byteLength == 0 || text != NULL); 1.2214 + 1.2215 + // nothing to draw 1.2216 + if (text == NULL || byteLength == 0 || 1.2217 + draw.fClip->isEmpty() || 1.2218 + (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { 1.2219 + return; 1.2220 + } 1.2221 + 1.2222 + SkScalar width = 0; 1.2223 + SkPoint start; 1.2224 + 1.2225 + start.set(0, 0); // to avoid warning 1.2226 + if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | 1.2227 + SkPaint::kStrikeThruText_Flag)) { 1.2228 + width = paint.measureText(text, byteLength); 1.2229 + 1.2230 + SkScalar offsetX = 0; 1.2231 + if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1.2232 + offsetX = SkScalarHalf(width); 1.2233 + } else if (paint.getTextAlign() == SkPaint::kRight_Align) { 1.2234 + offsetX = width; 1.2235 + } 1.2236 + start.set(x - offsetX, y); 1.2237 + } 1.2238 + 1.2239 + if (0 == width) { 1.2240 + return; 1.2241 + } 1.2242 + 1.2243 + uint32_t flags = paint.getFlags(); 1.2244 + 1.2245 + if (flags & (SkPaint::kUnderlineText_Flag | 1.2246 + SkPaint::kStrikeThruText_Flag)) { 1.2247 + SkScalar textSize = paint.getTextSize(); 1.2248 + SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); 1.2249 + SkRect r; 1.2250 + 1.2251 + r.fLeft = start.fX; 1.2252 + r.fRight = start.fX + width; 1.2253 + 1.2254 + if (flags & SkPaint::kUnderlineText_Flag) { 1.2255 + SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, 1.2256 + start.fY); 1.2257 + r.fTop = offset; 1.2258 + r.fBottom = offset + height; 1.2259 + DrawRect(draw, paint, r, textSize); 1.2260 + } 1.2261 + if (flags & SkPaint::kStrikeThruText_Flag) { 1.2262 + SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, 1.2263 + start.fY); 1.2264 + r.fTop = offset; 1.2265 + r.fBottom = offset + height; 1.2266 + DrawRect(draw, paint, r, textSize); 1.2267 + } 1.2268 + } 1.2269 +} 1.2270 + 1.2271 +void SkCanvas::drawText(const void* text, size_t byteLength, 1.2272 + SkScalar x, SkScalar y, const SkPaint& paint) { 1.2273 + CHECK_SHADER_NOSETCONTEXT(paint); 1.2274 + 1.2275 + LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 1.2276 + 1.2277 + while (iter.next()) { 1.2278 + SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1.2279 + iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); 1.2280 + DrawTextDecorations(iter, dfp.paint(), 1.2281 + static_cast<const char*>(text), byteLength, x, y); 1.2282 + } 1.2283 + 1.2284 + LOOPER_END 1.2285 +} 1.2286 + 1.2287 +void SkCanvas::drawPosText(const void* text, size_t byteLength, 1.2288 + const SkPoint pos[], const SkPaint& paint) { 1.2289 + CHECK_SHADER_NOSETCONTEXT(paint); 1.2290 + 1.2291 + LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 1.2292 + 1.2293 + while (iter.next()) { 1.2294 + SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1.2295 + iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, 1.2296 + dfp.paint()); 1.2297 + } 1.2298 + 1.2299 + LOOPER_END 1.2300 +} 1.2301 + 1.2302 +void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 1.2303 + const SkScalar xpos[], SkScalar constY, 1.2304 + const SkPaint& paint) { 1.2305 + CHECK_SHADER_NOSETCONTEXT(paint); 1.2306 + 1.2307 + LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 1.2308 + 1.2309 + while (iter.next()) { 1.2310 + SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); 1.2311 + iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, 1.2312 + dfp.paint()); 1.2313 + } 1.2314 + 1.2315 + LOOPER_END 1.2316 +} 1.2317 + 1.2318 +void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, 1.2319 + const SkPath& path, const SkMatrix* matrix, 1.2320 + const SkPaint& paint) { 1.2321 + CHECK_SHADER_NOSETCONTEXT(paint); 1.2322 + 1.2323 + LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) 1.2324 + 1.2325 + while (iter.next()) { 1.2326 + iter.fDevice->drawTextOnPath(iter, text, byteLength, path, 1.2327 + matrix, looper.paint()); 1.2328 + } 1.2329 + 1.2330 + LOOPER_END 1.2331 +} 1.2332 + 1.2333 +void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, 1.2334 + const SkPoint verts[], const SkPoint texs[], 1.2335 + const SkColor colors[], SkXfermode* xmode, 1.2336 + const uint16_t indices[], int indexCount, 1.2337 + const SkPaint& paint) { 1.2338 + CHECK_SHADER_NOSETCONTEXT(paint); 1.2339 + 1.2340 + LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) 1.2341 + 1.2342 + while (iter.next()) { 1.2343 + iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, 1.2344 + colors, xmode, indices, indexCount, 1.2345 + looper.paint()); 1.2346 + } 1.2347 + 1.2348 + LOOPER_END 1.2349 +} 1.2350 + 1.2351 +////////////////////////////////////////////////////////////////////////////// 1.2352 +// These methods are NOT virtual, and therefore must call back into virtual 1.2353 +// methods, rather than actually drawing themselves. 1.2354 +////////////////////////////////////////////////////////////////////////////// 1.2355 + 1.2356 +void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, 1.2357 + SkXfermode::Mode mode) { 1.2358 + SkPaint paint; 1.2359 + 1.2360 + paint.setARGB(a, r, g, b); 1.2361 + if (SkXfermode::kSrcOver_Mode != mode) { 1.2362 + paint.setXfermodeMode(mode); 1.2363 + } 1.2364 + this->drawPaint(paint); 1.2365 +} 1.2366 + 1.2367 +void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { 1.2368 + SkPaint paint; 1.2369 + 1.2370 + paint.setColor(c); 1.2371 + if (SkXfermode::kSrcOver_Mode != mode) { 1.2372 + paint.setXfermodeMode(mode); 1.2373 + } 1.2374 + this->drawPaint(paint); 1.2375 +} 1.2376 + 1.2377 +void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { 1.2378 + SkPoint pt; 1.2379 + 1.2380 + pt.set(x, y); 1.2381 + this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1.2382 +} 1.2383 + 1.2384 +void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { 1.2385 + SkPoint pt; 1.2386 + SkPaint paint; 1.2387 + 1.2388 + pt.set(x, y); 1.2389 + paint.setColor(color); 1.2390 + this->drawPoints(kPoints_PointMode, 1, &pt, paint); 1.2391 +} 1.2392 + 1.2393 +void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, 1.2394 + const SkPaint& paint) { 1.2395 + SkPoint pts[2]; 1.2396 + 1.2397 + pts[0].set(x0, y0); 1.2398 + pts[1].set(x1, y1); 1.2399 + this->drawPoints(kLines_PointMode, 2, pts, paint); 1.2400 +} 1.2401 + 1.2402 +void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, 1.2403 + SkScalar right, SkScalar bottom, 1.2404 + const SkPaint& paint) { 1.2405 + SkRect r; 1.2406 + 1.2407 + r.set(left, top, right, bottom); 1.2408 + this->drawRect(r, paint); 1.2409 +} 1.2410 + 1.2411 +void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, 1.2412 + const SkPaint& paint) { 1.2413 + if (radius < 0) { 1.2414 + radius = 0; 1.2415 + } 1.2416 + 1.2417 + SkRect r; 1.2418 + r.set(cx - radius, cy - radius, cx + radius, cy + radius); 1.2419 + this->drawOval(r, paint); 1.2420 +} 1.2421 + 1.2422 +void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, 1.2423 + const SkPaint& paint) { 1.2424 + if (rx > 0 && ry > 0) { 1.2425 + if (paint.canComputeFastBounds()) { 1.2426 + SkRect storage; 1.2427 + if (this->quickReject(paint.computeFastBounds(r, &storage))) { 1.2428 + return; 1.2429 + } 1.2430 + } 1.2431 + SkRRect rrect; 1.2432 + rrect.setRectXY(r, rx, ry); 1.2433 + this->drawRRect(rrect, paint); 1.2434 + } else { 1.2435 + this->drawRect(r, paint); 1.2436 + } 1.2437 +} 1.2438 + 1.2439 +void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, 1.2440 + SkScalar sweepAngle, bool useCenter, 1.2441 + const SkPaint& paint) { 1.2442 + if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { 1.2443 + this->drawOval(oval, paint); 1.2444 + } else { 1.2445 + SkPath path; 1.2446 + if (useCenter) { 1.2447 + path.moveTo(oval.centerX(), oval.centerY()); 1.2448 + } 1.2449 + path.arcTo(oval, startAngle, sweepAngle, !useCenter); 1.2450 + if (useCenter) { 1.2451 + path.close(); 1.2452 + } 1.2453 + this->drawPath(path, paint); 1.2454 + } 1.2455 +} 1.2456 + 1.2457 +void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, 1.2458 + const SkPath& path, SkScalar hOffset, 1.2459 + SkScalar vOffset, const SkPaint& paint) { 1.2460 + SkMatrix matrix; 1.2461 + 1.2462 + matrix.setTranslate(hOffset, vOffset); 1.2463 + this->drawTextOnPath(text, byteLength, path, &matrix, paint); 1.2464 +} 1.2465 + 1.2466 +/////////////////////////////////////////////////////////////////////////////// 1.2467 +void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) { 1.2468 + SkBaseDevice* device = this->getDevice(); 1.2469 + if (NULL != device) { 1.2470 + device->EXPERIMENTAL_optimize(picture); 1.2471 + } 1.2472 +} 1.2473 + 1.2474 +void SkCanvas::drawPicture(SkPicture& picture) { 1.2475 + SkBaseDevice* device = this->getTopDevice(); 1.2476 + if (NULL != device) { 1.2477 + // Canvas has to first give the device the opportunity to render 1.2478 + // the picture itself. 1.2479 + if (device->EXPERIMENTAL_drawPicture(picture)) { 1.2480 + return; // the device has rendered the entire picture 1.2481 + } 1.2482 + } 1.2483 + 1.2484 + picture.draw(this); 1.2485 +} 1.2486 + 1.2487 +/////////////////////////////////////////////////////////////////////////////// 1.2488 +/////////////////////////////////////////////////////////////////////////////// 1.2489 + 1.2490 +SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { 1.2491 + SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); 1.2492 + 1.2493 + SkASSERT(canvas); 1.2494 + 1.2495 + fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); 1.2496 + fDone = !fImpl->next(); 1.2497 +} 1.2498 + 1.2499 +SkCanvas::LayerIter::~LayerIter() { 1.2500 + fImpl->~SkDrawIter(); 1.2501 +} 1.2502 + 1.2503 +void SkCanvas::LayerIter::next() { 1.2504 + fDone = !fImpl->next(); 1.2505 +} 1.2506 + 1.2507 +SkBaseDevice* SkCanvas::LayerIter::device() const { 1.2508 + return fImpl->getDevice(); 1.2509 +} 1.2510 + 1.2511 +const SkMatrix& SkCanvas::LayerIter::matrix() const { 1.2512 + return fImpl->getMatrix(); 1.2513 +} 1.2514 + 1.2515 +const SkPaint& SkCanvas::LayerIter::paint() const { 1.2516 + const SkPaint* paint = fImpl->getPaint(); 1.2517 + if (NULL == paint) { 1.2518 + paint = &fDefaultPaint; 1.2519 + } 1.2520 + return *paint; 1.2521 +} 1.2522 + 1.2523 +const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } 1.2524 +int SkCanvas::LayerIter::x() const { return fImpl->getX(); } 1.2525 +int SkCanvas::LayerIter::y() const { return fImpl->getY(); } 1.2526 + 1.2527 +/////////////////////////////////////////////////////////////////////////////// 1.2528 + 1.2529 +SkCanvas::ClipVisitor::~ClipVisitor() { } 1.2530 + 1.2531 +/////////////////////////////////////////////////////////////////////////////// 1.2532 + 1.2533 +static bool supported_for_raster_canvas(const SkImageInfo& info) { 1.2534 + switch (info.alphaType()) { 1.2535 + case kPremul_SkAlphaType: 1.2536 + case kOpaque_SkAlphaType: 1.2537 + break; 1.2538 + default: 1.2539 + return false; 1.2540 + } 1.2541 + 1.2542 + switch (info.colorType()) { 1.2543 + case kAlpha_8_SkColorType: 1.2544 + case kRGB_565_SkColorType: 1.2545 + case kPMColor_SkColorType: 1.2546 + break; 1.2547 + default: 1.2548 + return false; 1.2549 + } 1.2550 + 1.2551 + return true; 1.2552 +} 1.2553 + 1.2554 +SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) { 1.2555 + if (!supported_for_raster_canvas(info)) { 1.2556 + return NULL; 1.2557 + } 1.2558 + 1.2559 + SkBitmap bitmap; 1.2560 + if (!bitmap.allocPixels(info)) { 1.2561 + return NULL; 1.2562 + } 1.2563 + 1.2564 + // should this functionality be moved into allocPixels()? 1.2565 + if (!bitmap.info().isOpaque()) { 1.2566 + bitmap.eraseColor(0); 1.2567 + } 1.2568 + return SkNEW_ARGS(SkCanvas, (bitmap)); 1.2569 +} 1.2570 + 1.2571 +SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { 1.2572 + if (!supported_for_raster_canvas(info)) { 1.2573 + return NULL; 1.2574 + } 1.2575 + 1.2576 + SkBitmap bitmap; 1.2577 + if (!bitmap.installPixels(info, pixels, rowBytes)) { 1.2578 + return NULL; 1.2579 + } 1.2580 + 1.2581 + // should this functionality be moved into allocPixels()? 1.2582 + if (!bitmap.info().isOpaque()) { 1.2583 + bitmap.eraseColor(0); 1.2584 + } 1.2585 + return SkNEW_ARGS(SkCanvas, (bitmap)); 1.2586 +}