|
1 |
|
2 /* |
|
3 * Copyright 2008 The Android Open Source Project |
|
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 |
|
10 #include "SkCanvas.h" |
|
11 #include "SkBitmapDevice.h" |
|
12 #include "SkBounder.h" |
|
13 #include "SkDeviceImageFilterProxy.h" |
|
14 #include "SkDraw.h" |
|
15 #include "SkDrawFilter.h" |
|
16 #include "SkDrawLooper.h" |
|
17 #include "SkMetaData.h" |
|
18 #include "SkPathOps.h" |
|
19 #include "SkPicture.h" |
|
20 #include "SkRasterClip.h" |
|
21 #include "SkRRect.h" |
|
22 #include "SkSmallAllocator.h" |
|
23 #include "SkSurface_Base.h" |
|
24 #include "SkTemplates.h" |
|
25 #include "SkTextFormatParams.h" |
|
26 #include "SkTLazy.h" |
|
27 #include "SkUtils.h" |
|
28 |
|
29 #if SK_SUPPORT_GPU |
|
30 #include "GrRenderTarget.h" |
|
31 #endif |
|
32 |
|
33 // experimental for faster tiled drawing... |
|
34 //#define SK_ENABLE_CLIP_QUICKREJECT |
|
35 |
|
36 //#define SK_TRACE_SAVERESTORE |
|
37 |
|
38 #ifdef SK_TRACE_SAVERESTORE |
|
39 static int gLayerCounter; |
|
40 static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); } |
|
41 static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); } |
|
42 |
|
43 static int gRecCounter; |
|
44 static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); } |
|
45 static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); } |
|
46 |
|
47 static int gCanvasCounter; |
|
48 static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); } |
|
49 static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); } |
|
50 #else |
|
51 #define inc_layer() |
|
52 #define dec_layer() |
|
53 #define inc_rec() |
|
54 #define dec_rec() |
|
55 #define inc_canvas() |
|
56 #define dec_canvas() |
|
57 #endif |
|
58 |
|
59 #ifdef SK_DEBUG |
|
60 #include "SkPixelRef.h" |
|
61 |
|
62 /* |
|
63 * Some pixelref subclasses can support being "locked" from another thread |
|
64 * during the lock-scope of skia calling them. In these instances, this balance |
|
65 * check will fail, but may not be indicative of a problem, so we allow a build |
|
66 * flag to disable this check. |
|
67 * |
|
68 * Potentially another fix would be to have a (debug-only) virtual or flag on |
|
69 * pixelref, which could tell us at runtime if this check is valid. That would |
|
70 * eliminate the need for this heavy-handed build check. |
|
71 */ |
|
72 #ifdef SK_DISABLE_PIXELREF_LOCKCOUNT_BALANCE_CHECK |
|
73 class AutoCheckLockCountBalance { |
|
74 public: |
|
75 AutoCheckLockCountBalance(const SkBitmap&) { /* do nothing */ } |
|
76 }; |
|
77 #else |
|
78 class AutoCheckLockCountBalance { |
|
79 public: |
|
80 AutoCheckLockCountBalance(const SkBitmap& bm) : fPixelRef(bm.pixelRef()) { |
|
81 fLockCount = fPixelRef ? fPixelRef->getLockCount() : 0; |
|
82 } |
|
83 ~AutoCheckLockCountBalance() { |
|
84 const int count = fPixelRef ? fPixelRef->getLockCount() : 0; |
|
85 SkASSERT(count == fLockCount); |
|
86 } |
|
87 |
|
88 private: |
|
89 const SkPixelRef* fPixelRef; |
|
90 int fLockCount; |
|
91 }; |
|
92 #endif |
|
93 |
|
94 class AutoCheckNoSetContext { |
|
95 public: |
|
96 AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) { |
|
97 this->assertNoSetContext(fPaint); |
|
98 } |
|
99 ~AutoCheckNoSetContext() { |
|
100 this->assertNoSetContext(fPaint); |
|
101 } |
|
102 |
|
103 private: |
|
104 const SkPaint& fPaint; |
|
105 |
|
106 void assertNoSetContext(const SkPaint& paint) { |
|
107 SkShader* s = paint.getShader(); |
|
108 if (s) { |
|
109 SkASSERT(!s->setContextHasBeenCalled()); |
|
110 } |
|
111 } |
|
112 }; |
|
113 |
|
114 #define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap) |
|
115 #define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext cshsc(paint) |
|
116 |
|
117 #else |
|
118 #define CHECK_LOCKCOUNT_BALANCE(bitmap) |
|
119 #define CHECK_SHADER_NOSETCONTEXT(paint) |
|
120 #endif |
|
121 |
|
122 typedef SkTLazy<SkPaint> SkLazyPaint; |
|
123 |
|
124 void SkCanvas::predrawNotify() { |
|
125 if (fSurfaceBase) { |
|
126 fSurfaceBase->aboutToDraw(SkSurface::kRetain_ContentChangeMode); |
|
127 } |
|
128 } |
|
129 |
|
130 /////////////////////////////////////////////////////////////////////////////// |
|
131 |
|
132 /* This is the record we keep for each SkBaseDevice that the user installs. |
|
133 The clip/matrix/proc are fields that reflect the top of the save/restore |
|
134 stack. Whenever the canvas changes, it marks a dirty flag, and then before |
|
135 these are used (assuming we're not on a layer) we rebuild these cache |
|
136 values: they reflect the top of the save stack, but translated and clipped |
|
137 by the device's XY offset and bitmap-bounds. |
|
138 */ |
|
139 struct DeviceCM { |
|
140 DeviceCM* fNext; |
|
141 SkBaseDevice* fDevice; |
|
142 SkRasterClip fClip; |
|
143 const SkMatrix* fMatrix; |
|
144 SkPaint* fPaint; // may be null (in the future) |
|
145 |
|
146 DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas) |
|
147 : fNext(NULL) { |
|
148 if (NULL != device) { |
|
149 device->ref(); |
|
150 device->onAttachToCanvas(canvas); |
|
151 } |
|
152 fDevice = device; |
|
153 fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; |
|
154 } |
|
155 |
|
156 ~DeviceCM() { |
|
157 if (NULL != fDevice) { |
|
158 fDevice->onDetachFromCanvas(); |
|
159 fDevice->unref(); |
|
160 } |
|
161 SkDELETE(fPaint); |
|
162 } |
|
163 |
|
164 void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, |
|
165 const SkClipStack& clipStack, SkRasterClip* updateClip) { |
|
166 int x = fDevice->getOrigin().x(); |
|
167 int y = fDevice->getOrigin().y(); |
|
168 int width = fDevice->width(); |
|
169 int height = fDevice->height(); |
|
170 |
|
171 if ((x | y) == 0) { |
|
172 fMatrix = &totalMatrix; |
|
173 fClip = totalClip; |
|
174 } else { |
|
175 fMatrixStorage = totalMatrix; |
|
176 fMatrixStorage.postTranslate(SkIntToScalar(-x), |
|
177 SkIntToScalar(-y)); |
|
178 fMatrix = &fMatrixStorage; |
|
179 |
|
180 totalClip.translate(-x, -y, &fClip); |
|
181 } |
|
182 |
|
183 fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op); |
|
184 |
|
185 // intersect clip, but don't translate it (yet) |
|
186 |
|
187 if (updateClip) { |
|
188 updateClip->op(SkIRect::MakeXYWH(x, y, width, height), |
|
189 SkRegion::kDifference_Op); |
|
190 } |
|
191 |
|
192 fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); |
|
193 |
|
194 #ifdef SK_DEBUG |
|
195 if (!fClip.isEmpty()) { |
|
196 SkIRect deviceR; |
|
197 deviceR.set(0, 0, width, height); |
|
198 SkASSERT(deviceR.contains(fClip.getBounds())); |
|
199 } |
|
200 #endif |
|
201 } |
|
202 |
|
203 private: |
|
204 SkMatrix fMatrixStorage; |
|
205 }; |
|
206 |
|
207 /* This is the record we keep for each save/restore level in the stack. |
|
208 Since a level optionally copies the matrix and/or stack, we have pointers |
|
209 for these fields. If the value is copied for this level, the copy is |
|
210 stored in the ...Storage field, and the pointer points to that. If the |
|
211 value is not copied for this level, we ignore ...Storage, and just point |
|
212 at the corresponding value in the previous level in the stack. |
|
213 */ |
|
214 class SkCanvas::MCRec { |
|
215 public: |
|
216 int fFlags; |
|
217 SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec |
|
218 SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec |
|
219 SkDrawFilter* fFilter; // the current filter (or null) |
|
220 |
|
221 DeviceCM* fLayer; |
|
222 /* If there are any layers in the stack, this points to the top-most |
|
223 one that is at or below this level in the stack (so we know what |
|
224 bitmap/device to draw into from this level. This value is NOT |
|
225 reference counted, since the real owner is either our fLayer field, |
|
226 or a previous one in a lower level.) |
|
227 */ |
|
228 DeviceCM* fTopLayer; |
|
229 |
|
230 MCRec(const MCRec* prev, int flags) : fFlags(flags) { |
|
231 if (NULL != prev) { |
|
232 if (flags & SkCanvas::kMatrix_SaveFlag) { |
|
233 fMatrixStorage = *prev->fMatrix; |
|
234 fMatrix = &fMatrixStorage; |
|
235 } else { |
|
236 fMatrix = prev->fMatrix; |
|
237 } |
|
238 |
|
239 if (flags & SkCanvas::kClip_SaveFlag) { |
|
240 fRasterClipStorage = *prev->fRasterClip; |
|
241 fRasterClip = &fRasterClipStorage; |
|
242 } else { |
|
243 fRasterClip = prev->fRasterClip; |
|
244 } |
|
245 |
|
246 fFilter = prev->fFilter; |
|
247 SkSafeRef(fFilter); |
|
248 |
|
249 fTopLayer = prev->fTopLayer; |
|
250 } else { // no prev |
|
251 fMatrixStorage.reset(); |
|
252 |
|
253 fMatrix = &fMatrixStorage; |
|
254 fRasterClip = &fRasterClipStorage; |
|
255 fFilter = NULL; |
|
256 fTopLayer = NULL; |
|
257 } |
|
258 fLayer = NULL; |
|
259 |
|
260 // don't bother initializing fNext |
|
261 inc_rec(); |
|
262 } |
|
263 ~MCRec() { |
|
264 SkSafeUnref(fFilter); |
|
265 SkDELETE(fLayer); |
|
266 dec_rec(); |
|
267 } |
|
268 |
|
269 private: |
|
270 SkMatrix fMatrixStorage; |
|
271 SkRasterClip fRasterClipStorage; |
|
272 }; |
|
273 |
|
274 class SkDrawIter : public SkDraw { |
|
275 public: |
|
276 SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { |
|
277 canvas = canvas->canvasForDrawIter(); |
|
278 fCanvas = canvas; |
|
279 canvas->updateDeviceCMCache(); |
|
280 |
|
281 fClipStack = &canvas->fClipStack; |
|
282 fBounder = canvas->getBounder(); |
|
283 fCurrLayer = canvas->fMCRec->fTopLayer; |
|
284 fSkipEmptyClips = skipEmptyClips; |
|
285 } |
|
286 |
|
287 bool next() { |
|
288 // skip over recs with empty clips |
|
289 if (fSkipEmptyClips) { |
|
290 while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { |
|
291 fCurrLayer = fCurrLayer->fNext; |
|
292 } |
|
293 } |
|
294 |
|
295 const DeviceCM* rec = fCurrLayer; |
|
296 if (rec && rec->fDevice) { |
|
297 |
|
298 fMatrix = rec->fMatrix; |
|
299 fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW(); |
|
300 fRC = &rec->fClip; |
|
301 fDevice = rec->fDevice; |
|
302 fBitmap = &fDevice->accessBitmap(true); |
|
303 fPaint = rec->fPaint; |
|
304 SkDEBUGCODE(this->validate();) |
|
305 |
|
306 fCurrLayer = rec->fNext; |
|
307 if (fBounder) { |
|
308 fBounder->setClip(fClip); |
|
309 } |
|
310 // fCurrLayer may be NULL now |
|
311 |
|
312 return true; |
|
313 } |
|
314 return false; |
|
315 } |
|
316 |
|
317 SkBaseDevice* getDevice() const { return fDevice; } |
|
318 int getX() const { return fDevice->getOrigin().x(); } |
|
319 int getY() const { return fDevice->getOrigin().y(); } |
|
320 const SkMatrix& getMatrix() const { return *fMatrix; } |
|
321 const SkRegion& getClip() const { return *fClip; } |
|
322 const SkPaint* getPaint() const { return fPaint; } |
|
323 |
|
324 private: |
|
325 SkCanvas* fCanvas; |
|
326 const DeviceCM* fCurrLayer; |
|
327 const SkPaint* fPaint; // May be null. |
|
328 SkBool8 fSkipEmptyClips; |
|
329 |
|
330 typedef SkDraw INHERITED; |
|
331 }; |
|
332 |
|
333 ///////////////////////////////////////////////////////////////////////////// |
|
334 |
|
335 class AutoDrawLooper { |
|
336 public: |
|
337 AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, |
|
338 bool skipLayerForImageFilter = false, |
|
339 const SkRect* bounds = NULL) : fOrigPaint(paint) { |
|
340 fCanvas = canvas; |
|
341 fFilter = canvas->getDrawFilter(); |
|
342 fPaint = NULL; |
|
343 fSaveCount = canvas->getSaveCount(); |
|
344 fDoClearImageFilter = false; |
|
345 fDone = false; |
|
346 |
|
347 if (!skipLayerForImageFilter && fOrigPaint.getImageFilter()) { |
|
348 SkPaint tmp; |
|
349 tmp.setImageFilter(fOrigPaint.getImageFilter()); |
|
350 (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag, |
|
351 true, SkCanvas::kFullLayer_SaveLayerStrategy); |
|
352 // we'll clear the imageFilter for the actual draws in next(), so |
|
353 // it will only be applied during the restore(). |
|
354 fDoClearImageFilter = true; |
|
355 } |
|
356 |
|
357 if (SkDrawLooper* looper = paint.getLooper()) { |
|
358 void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>( |
|
359 looper->contextSize()); |
|
360 fLooperContext = looper->createContext(canvas, buffer); |
|
361 fIsSimple = false; |
|
362 } else { |
|
363 fLooperContext = NULL; |
|
364 // can we be marked as simple? |
|
365 fIsSimple = !fFilter && !fDoClearImageFilter; |
|
366 } |
|
367 } |
|
368 |
|
369 ~AutoDrawLooper() { |
|
370 if (fDoClearImageFilter) { |
|
371 fCanvas->internalRestore(); |
|
372 } |
|
373 SkASSERT(fCanvas->getSaveCount() == fSaveCount); |
|
374 } |
|
375 |
|
376 const SkPaint& paint() const { |
|
377 SkASSERT(fPaint); |
|
378 return *fPaint; |
|
379 } |
|
380 |
|
381 bool next(SkDrawFilter::Type drawType) { |
|
382 if (fDone) { |
|
383 return false; |
|
384 } else if (fIsSimple) { |
|
385 fDone = true; |
|
386 fPaint = &fOrigPaint; |
|
387 return !fPaint->nothingToDraw(); |
|
388 } else { |
|
389 return this->doNext(drawType); |
|
390 } |
|
391 } |
|
392 |
|
393 private: |
|
394 SkLazyPaint fLazyPaint; |
|
395 SkCanvas* fCanvas; |
|
396 const SkPaint& fOrigPaint; |
|
397 SkDrawFilter* fFilter; |
|
398 const SkPaint* fPaint; |
|
399 int fSaveCount; |
|
400 bool fDoClearImageFilter; |
|
401 bool fDone; |
|
402 bool fIsSimple; |
|
403 SkDrawLooper::Context* fLooperContext; |
|
404 SkSmallAllocator<1, 32> fLooperContextAllocator; |
|
405 |
|
406 bool doNext(SkDrawFilter::Type drawType); |
|
407 }; |
|
408 |
|
409 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { |
|
410 fPaint = NULL; |
|
411 SkASSERT(!fIsSimple); |
|
412 SkASSERT(fLooperContext || fFilter || fDoClearImageFilter); |
|
413 |
|
414 SkPaint* paint = fLazyPaint.set(fOrigPaint); |
|
415 |
|
416 if (fDoClearImageFilter) { |
|
417 paint->setImageFilter(NULL); |
|
418 } |
|
419 |
|
420 if (fLooperContext && !fLooperContext->next(fCanvas, paint)) { |
|
421 fDone = true; |
|
422 return false; |
|
423 } |
|
424 if (fFilter) { |
|
425 if (!fFilter->filter(paint, drawType)) { |
|
426 fDone = true; |
|
427 return false; |
|
428 } |
|
429 if (NULL == fLooperContext) { |
|
430 // no looper means we only draw once |
|
431 fDone = true; |
|
432 } |
|
433 } |
|
434 fPaint = paint; |
|
435 |
|
436 // if we only came in here for the imagefilter, mark us as done |
|
437 if (!fLooperContext && !fFilter) { |
|
438 fDone = true; |
|
439 } |
|
440 |
|
441 // call this after any possible paint modifiers |
|
442 if (fPaint->nothingToDraw()) { |
|
443 fPaint = NULL; |
|
444 return false; |
|
445 } |
|
446 return true; |
|
447 } |
|
448 |
|
449 /* Stack helper for managing a SkBounder. In the destructor, if we were |
|
450 given a bounder, we call its commit() method, signifying that we are |
|
451 done accumulating bounds for that draw. |
|
452 */ |
|
453 class SkAutoBounderCommit { |
|
454 public: |
|
455 SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {} |
|
456 ~SkAutoBounderCommit() { |
|
457 if (NULL != fBounder) { |
|
458 fBounder->commit(); |
|
459 } |
|
460 } |
|
461 private: |
|
462 SkBounder* fBounder; |
|
463 }; |
|
464 #define SkAutoBounderCommit(...) SK_REQUIRE_LOCAL_VAR(SkAutoBounderCommit) |
|
465 |
|
466 #include "SkColorPriv.h" |
|
467 |
|
468 ////////// macros to place around the internal draw calls ////////////////// |
|
469 |
|
470 #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ |
|
471 this->predrawNotify(); \ |
|
472 AutoDrawLooper looper(this, paint, true); \ |
|
473 while (looper.next(type)) { \ |
|
474 SkAutoBounderCommit ac(fBounder); \ |
|
475 SkDrawIter iter(this); |
|
476 |
|
477 #define LOOPER_BEGIN(paint, type, bounds) \ |
|
478 this->predrawNotify(); \ |
|
479 AutoDrawLooper looper(this, paint, false, bounds); \ |
|
480 while (looper.next(type)) { \ |
|
481 SkAutoBounderCommit ac(fBounder); \ |
|
482 SkDrawIter iter(this); |
|
483 |
|
484 #define LOOPER_END } |
|
485 |
|
486 //////////////////////////////////////////////////////////////////////////// |
|
487 |
|
488 SkBaseDevice* SkCanvas::init(SkBaseDevice* device) { |
|
489 fBounder = NULL; |
|
490 fCachedLocalClipBounds.setEmpty(); |
|
491 fCachedLocalClipBoundsDirty = true; |
|
492 fAllowSoftClip = true; |
|
493 fAllowSimplifyClip = false; |
|
494 fDeviceCMDirty = false; |
|
495 fSaveLayerCount = 0; |
|
496 fCullCount = 0; |
|
497 fMetaData = NULL; |
|
498 |
|
499 fMCRec = (MCRec*)fMCStack.push_back(); |
|
500 new (fMCRec) MCRec(NULL, 0); |
|
501 |
|
502 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL)); |
|
503 fMCRec->fTopLayer = fMCRec->fLayer; |
|
504 |
|
505 fSurfaceBase = NULL; |
|
506 |
|
507 return this->setRootDevice(device); |
|
508 } |
|
509 |
|
510 SkCanvas::SkCanvas() |
|
511 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) |
|
512 { |
|
513 inc_canvas(); |
|
514 |
|
515 this->init(NULL); |
|
516 } |
|
517 |
|
518 SkCanvas::SkCanvas(int width, int height) |
|
519 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) |
|
520 { |
|
521 inc_canvas(); |
|
522 |
|
523 SkBitmap bitmap; |
|
524 bitmap.setConfig(SkImageInfo::MakeUnknown(width, height)); |
|
525 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); |
|
526 } |
|
527 |
|
528 SkCanvas::SkCanvas(SkBaseDevice* device) |
|
529 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) |
|
530 { |
|
531 inc_canvas(); |
|
532 |
|
533 this->init(device); |
|
534 } |
|
535 |
|
536 SkCanvas::SkCanvas(const SkBitmap& bitmap) |
|
537 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) |
|
538 { |
|
539 inc_canvas(); |
|
540 |
|
541 this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref(); |
|
542 } |
|
543 |
|
544 SkCanvas::~SkCanvas() { |
|
545 // free up the contents of our deque |
|
546 this->restoreToCount(1); // restore everything but the last |
|
547 SkASSERT(0 == fSaveLayerCount); |
|
548 |
|
549 this->internalRestore(); // restore the last, since we're going away |
|
550 |
|
551 SkSafeUnref(fBounder); |
|
552 SkDELETE(fMetaData); |
|
553 |
|
554 dec_canvas(); |
|
555 } |
|
556 |
|
557 SkBounder* SkCanvas::setBounder(SkBounder* bounder) { |
|
558 SkRefCnt_SafeAssign(fBounder, bounder); |
|
559 return bounder; |
|
560 } |
|
561 |
|
562 SkDrawFilter* SkCanvas::getDrawFilter() const { |
|
563 return fMCRec->fFilter; |
|
564 } |
|
565 |
|
566 SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) { |
|
567 SkRefCnt_SafeAssign(fMCRec->fFilter, filter); |
|
568 return filter; |
|
569 } |
|
570 |
|
571 SkMetaData& SkCanvas::getMetaData() { |
|
572 // metadata users are rare, so we lazily allocate it. If that changes we |
|
573 // can decide to just make it a field in the device (rather than a ptr) |
|
574 if (NULL == fMetaData) { |
|
575 fMetaData = new SkMetaData; |
|
576 } |
|
577 return *fMetaData; |
|
578 } |
|
579 |
|
580 /////////////////////////////////////////////////////////////////////////////// |
|
581 |
|
582 void SkCanvas::flush() { |
|
583 SkBaseDevice* device = this->getDevice(); |
|
584 if (device) { |
|
585 device->flush(); |
|
586 } |
|
587 } |
|
588 |
|
589 SkISize SkCanvas::getTopLayerSize() const { |
|
590 SkBaseDevice* d = this->getTopDevice(); |
|
591 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); |
|
592 } |
|
593 |
|
594 SkIPoint SkCanvas::getTopLayerOrigin() const { |
|
595 SkBaseDevice* d = this->getTopDevice(); |
|
596 return d ? d->getOrigin() : SkIPoint::Make(0, 0); |
|
597 } |
|
598 |
|
599 SkISize SkCanvas::getBaseLayerSize() const { |
|
600 SkBaseDevice* d = this->getDevice(); |
|
601 return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0); |
|
602 } |
|
603 |
|
604 SkBaseDevice* SkCanvas::getDevice() const { |
|
605 // return root device |
|
606 MCRec* rec = (MCRec*) fMCStack.front(); |
|
607 SkASSERT(rec && rec->fLayer); |
|
608 return rec->fLayer->fDevice; |
|
609 } |
|
610 |
|
611 SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { |
|
612 if (updateMatrixClip) { |
|
613 const_cast<SkCanvas*>(this)->updateDeviceCMCache(); |
|
614 } |
|
615 return fMCRec->fTopLayer->fDevice; |
|
616 } |
|
617 |
|
618 SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) { |
|
619 // return root device |
|
620 SkDeque::F2BIter iter(fMCStack); |
|
621 MCRec* rec = (MCRec*)iter.next(); |
|
622 SkASSERT(rec && rec->fLayer); |
|
623 SkBaseDevice* rootDevice = rec->fLayer->fDevice; |
|
624 |
|
625 if (rootDevice == device) { |
|
626 return device; |
|
627 } |
|
628 |
|
629 if (device) { |
|
630 device->onAttachToCanvas(this); |
|
631 } |
|
632 if (rootDevice) { |
|
633 rootDevice->onDetachFromCanvas(); |
|
634 } |
|
635 |
|
636 SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); |
|
637 rootDevice = device; |
|
638 |
|
639 fDeviceCMDirty = true; |
|
640 |
|
641 /* Now we update our initial region to have the bounds of the new device, |
|
642 and then intersect all of the clips in our stack with these bounds, |
|
643 to ensure that we can't draw outside of the device's bounds (and trash |
|
644 memory). |
|
645 |
|
646 NOTE: this is only a partial-fix, since if the new device is larger than |
|
647 the previous one, we don't know how to "enlarge" the clips in our stack, |
|
648 so drawing may be artificially restricted. Without keeping a history of |
|
649 all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly |
|
650 reconstruct the correct clips, so this approximation will have to do. |
|
651 The caller really needs to restore() back to the base if they want to |
|
652 accurately take advantage of the new device bounds. |
|
653 */ |
|
654 |
|
655 SkIRect bounds; |
|
656 if (device) { |
|
657 bounds.set(0, 0, device->width(), device->height()); |
|
658 } else { |
|
659 bounds.setEmpty(); |
|
660 } |
|
661 // now jam our 1st clip to be bounds, and intersect the rest with that |
|
662 rec->fRasterClip->setRect(bounds); |
|
663 while ((rec = (MCRec*)iter.next()) != NULL) { |
|
664 (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op); |
|
665 } |
|
666 |
|
667 return device; |
|
668 } |
|
669 |
|
670 bool SkCanvas::readPixels(SkBitmap* bitmap, |
|
671 int x, int y, |
|
672 Config8888 config8888) { |
|
673 SkBaseDevice* device = this->getDevice(); |
|
674 if (!device) { |
|
675 return false; |
|
676 } |
|
677 return device->readPixels(bitmap, x, y, config8888); |
|
678 } |
|
679 |
|
680 bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) { |
|
681 SkBaseDevice* device = this->getDevice(); |
|
682 if (!device) { |
|
683 return false; |
|
684 } |
|
685 |
|
686 SkIRect bounds; |
|
687 bounds.set(0, 0, device->width(), device->height()); |
|
688 if (!bounds.intersect(srcRect)) { |
|
689 return false; |
|
690 } |
|
691 |
|
692 SkBitmap tmp; |
|
693 tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), |
|
694 bounds.height()); |
|
695 if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) { |
|
696 bitmap->swap(tmp); |
|
697 return true; |
|
698 } else { |
|
699 return false; |
|
700 } |
|
701 } |
|
702 |
|
703 #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG |
|
704 void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y, |
|
705 Config8888 config8888) { |
|
706 SkBaseDevice* device = this->getDevice(); |
|
707 if (device) { |
|
708 if (SkIRect::Intersects(SkIRect::MakeSize(this->getDeviceSize()), |
|
709 SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))) { |
|
710 device->accessBitmap(true); |
|
711 device->writePixels(bitmap, x, y, config8888); |
|
712 } |
|
713 } |
|
714 } |
|
715 #endif |
|
716 |
|
717 bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { |
|
718 if (bitmap.getTexture()) { |
|
719 return false; |
|
720 } |
|
721 SkBitmap bm(bitmap); |
|
722 bm.lockPixels(); |
|
723 if (bm.getPixels()) { |
|
724 return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y); |
|
725 } |
|
726 return false; |
|
727 } |
|
728 |
|
729 bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes, |
|
730 int x, int y) { |
|
731 switch (origInfo.colorType()) { |
|
732 case kUnknown_SkColorType: |
|
733 case kIndex_8_SkColorType: |
|
734 return false; |
|
735 default: |
|
736 break; |
|
737 } |
|
738 if (NULL == pixels || rowBytes < origInfo.minRowBytes()) { |
|
739 return false; |
|
740 } |
|
741 |
|
742 const SkISize size = this->getBaseLayerSize(); |
|
743 SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height()); |
|
744 if (!target.intersect(0, 0, size.width(), size.height())) { |
|
745 return false; |
|
746 } |
|
747 |
|
748 SkBaseDevice* device = this->getDevice(); |
|
749 if (!device) { |
|
750 return false; |
|
751 } |
|
752 |
|
753 SkImageInfo info = origInfo; |
|
754 // the intersect may have shrunk info's logical size |
|
755 info.fWidth = target.width(); |
|
756 info.fHeight = target.height(); |
|
757 |
|
758 // if x or y are negative, then we have to adjust pixels |
|
759 if (x > 0) { |
|
760 x = 0; |
|
761 } |
|
762 if (y > 0) { |
|
763 y = 0; |
|
764 } |
|
765 // here x,y are either 0 or negative |
|
766 pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel()); |
|
767 |
|
768 // The device can assert that the requested area is always contained in its bounds |
|
769 return device->writePixelsDirect(info, pixels, rowBytes, target.x(), target.y()); |
|
770 } |
|
771 |
|
772 SkCanvas* SkCanvas::canvasForDrawIter() { |
|
773 return this; |
|
774 } |
|
775 |
|
776 ////////////////////////////////////////////////////////////////////////////// |
|
777 |
|
778 void SkCanvas::updateDeviceCMCache() { |
|
779 if (fDeviceCMDirty) { |
|
780 const SkMatrix& totalMatrix = this->getTotalMatrix(); |
|
781 const SkRasterClip& totalClip = *fMCRec->fRasterClip; |
|
782 DeviceCM* layer = fMCRec->fTopLayer; |
|
783 |
|
784 if (NULL == layer->fNext) { // only one layer |
|
785 layer->updateMC(totalMatrix, totalClip, fClipStack, NULL); |
|
786 } else { |
|
787 SkRasterClip clip(totalClip); |
|
788 do { |
|
789 layer->updateMC(totalMatrix, clip, fClipStack, &clip); |
|
790 } while ((layer = layer->fNext) != NULL); |
|
791 } |
|
792 fDeviceCMDirty = false; |
|
793 } |
|
794 } |
|
795 |
|
796 /////////////////////////////////////////////////////////////////////////////// |
|
797 |
|
798 int SkCanvas::internalSave(SaveFlags flags) { |
|
799 int saveCount = this->getSaveCount(); // record this before the actual save |
|
800 |
|
801 MCRec* newTop = (MCRec*)fMCStack.push_back(); |
|
802 new (newTop) MCRec(fMCRec, flags); // balanced in restore() |
|
803 |
|
804 fMCRec = newTop; |
|
805 |
|
806 if (SkCanvas::kClip_SaveFlag & flags) { |
|
807 fClipStack.save(); |
|
808 } |
|
809 |
|
810 return saveCount; |
|
811 } |
|
812 |
|
813 void SkCanvas::willSave(SaveFlags) { |
|
814 // Do nothing. Subclasses may do something. |
|
815 } |
|
816 |
|
817 int SkCanvas::save(SaveFlags flags) { |
|
818 this->willSave(flags); |
|
819 // call shared impl |
|
820 return this->internalSave(flags); |
|
821 } |
|
822 |
|
823 static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { |
|
824 #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG |
|
825 return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0; |
|
826 #else |
|
827 return true; |
|
828 #endif |
|
829 } |
|
830 |
|
831 bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, |
|
832 SkIRect* intersection, const SkImageFilter* imageFilter) { |
|
833 SkIRect clipBounds; |
|
834 SkRegion::Op op = SkRegion::kIntersect_Op; |
|
835 if (!this->getClipDeviceBounds(&clipBounds)) { |
|
836 return false; |
|
837 } |
|
838 |
|
839 if (imageFilter) { |
|
840 imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds); |
|
841 // Filters may grow the bounds beyond the device bounds. |
|
842 op = SkRegion::kReplace_Op; |
|
843 } |
|
844 SkIRect ir; |
|
845 if (NULL != bounds) { |
|
846 SkRect r; |
|
847 |
|
848 this->getTotalMatrix().mapRect(&r, *bounds); |
|
849 r.roundOut(&ir); |
|
850 // early exit if the layer's bounds are clipped out |
|
851 if (!ir.intersect(clipBounds)) { |
|
852 if (bounds_affects_clip(flags)) { |
|
853 fMCRec->fRasterClip->setEmpty(); |
|
854 } |
|
855 return false; |
|
856 } |
|
857 } else { // no user bounds, so just use the clip |
|
858 ir = clipBounds; |
|
859 } |
|
860 |
|
861 if (bounds_affects_clip(flags)) { |
|
862 fClipStack.clipDevRect(ir, op); |
|
863 // early exit if the clip is now empty |
|
864 if (!fMCRec->fRasterClip->op(ir, op)) { |
|
865 return false; |
|
866 } |
|
867 } |
|
868 |
|
869 if (intersection) { |
|
870 *intersection = ir; |
|
871 } |
|
872 return true; |
|
873 } |
|
874 |
|
875 SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) { |
|
876 |
|
877 // Do nothing. Subclasses may do something. |
|
878 return kFullLayer_SaveLayerStrategy; |
|
879 } |
|
880 |
|
881 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, |
|
882 SaveFlags flags) { |
|
883 // Overriding classes may return false to signal that we don't need to create a layer. |
|
884 SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); |
|
885 return this->internalSaveLayer(bounds, paint, flags, false, strategy); |
|
886 } |
|
887 |
|
888 static SkBaseDevice* createCompatibleDevice(SkCanvas* canvas, |
|
889 const SkImageInfo& info) { |
|
890 SkBaseDevice* device = canvas->getDevice(); |
|
891 return device ? device->createCompatibleDevice(info) : NULL; |
|
892 } |
|
893 |
|
894 int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags, |
|
895 bool justForImageFilter, SaveLayerStrategy strategy) { |
|
896 #ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG |
|
897 flags = (SaveFlags)(flags | kClipToLayer_SaveFlag); |
|
898 #endif |
|
899 |
|
900 // do this before we create the layer. We don't call the public save() since |
|
901 // that would invoke a possibly overridden virtual |
|
902 int count = this->internalSave(flags); |
|
903 |
|
904 fDeviceCMDirty = true; |
|
905 |
|
906 SkIRect ir; |
|
907 if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { |
|
908 return count; |
|
909 } |
|
910 |
|
911 // FIXME: do willSaveLayer() overriders returning kNoLayer_SaveLayerStrategy really care about |
|
912 // the clipRectBounds() call above? |
|
913 if (kNoLayer_SaveLayerStrategy == strategy) { |
|
914 return count; |
|
915 } |
|
916 |
|
917 // Kill the imagefilter if our device doesn't allow it |
|
918 SkLazyPaint lazyP; |
|
919 if (paint && paint->getImageFilter()) { |
|
920 if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) { |
|
921 if (justForImageFilter) { |
|
922 // early exit if the layer was just for the imageFilter |
|
923 return count; |
|
924 } |
|
925 SkPaint* p = lazyP.set(*paint); |
|
926 p->setImageFilter(NULL); |
|
927 paint = p; |
|
928 } |
|
929 } |
|
930 |
|
931 bool isOpaque = !SkToBool(flags & kHasAlphaLayer_SaveFlag); |
|
932 SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(), |
|
933 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); |
|
934 |
|
935 SkBaseDevice* device; |
|
936 if (paint && paint->getImageFilter()) { |
|
937 device = createCompatibleDevice(this, info); |
|
938 } else { |
|
939 device = this->createLayerDevice(info); |
|
940 } |
|
941 if (NULL == device) { |
|
942 SkDebugf("Unable to create device for layer."); |
|
943 return count; |
|
944 } |
|
945 |
|
946 device->setOrigin(ir.fLeft, ir.fTop); |
|
947 DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this)); |
|
948 device->unref(); |
|
949 |
|
950 layer->fNext = fMCRec->fTopLayer; |
|
951 fMCRec->fLayer = layer; |
|
952 fMCRec->fTopLayer = layer; // this field is NOT an owner of layer |
|
953 |
|
954 fSaveLayerCount += 1; |
|
955 return count; |
|
956 } |
|
957 |
|
958 int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, |
|
959 SaveFlags flags) { |
|
960 if (0xFF == alpha) { |
|
961 return this->saveLayer(bounds, NULL, flags); |
|
962 } else { |
|
963 SkPaint tmpPaint; |
|
964 tmpPaint.setAlpha(alpha); |
|
965 return this->saveLayer(bounds, &tmpPaint, flags); |
|
966 } |
|
967 } |
|
968 |
|
969 void SkCanvas::willRestore() { |
|
970 // Do nothing. Subclasses may do something. |
|
971 } |
|
972 |
|
973 void SkCanvas::restore() { |
|
974 // check for underflow |
|
975 if (fMCStack.count() > 1) { |
|
976 this->willRestore(); |
|
977 this->internalRestore(); |
|
978 } |
|
979 } |
|
980 |
|
981 void SkCanvas::internalRestore() { |
|
982 SkASSERT(fMCStack.count() != 0); |
|
983 |
|
984 fDeviceCMDirty = true; |
|
985 fCachedLocalClipBoundsDirty = true; |
|
986 |
|
987 if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) { |
|
988 fClipStack.restore(); |
|
989 } |
|
990 |
|
991 // reserve our layer (if any) |
|
992 DeviceCM* layer = fMCRec->fLayer; // may be null |
|
993 // now detach it from fMCRec so we can pop(). Gets freed after its drawn |
|
994 fMCRec->fLayer = NULL; |
|
995 |
|
996 // now do the normal restore() |
|
997 fMCRec->~MCRec(); // balanced in save() |
|
998 fMCStack.pop_back(); |
|
999 fMCRec = (MCRec*)fMCStack.back(); |
|
1000 |
|
1001 /* Time to draw the layer's offscreen. We can't call the public drawSprite, |
|
1002 since if we're being recorded, we don't want to record this (the |
|
1003 recorder will have already recorded the restore). |
|
1004 */ |
|
1005 if (NULL != layer) { |
|
1006 if (layer->fNext) { |
|
1007 const SkIPoint& origin = layer->fDevice->getOrigin(); |
|
1008 this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), |
|
1009 layer->fPaint); |
|
1010 // reset this, since internalDrawDevice will have set it to true |
|
1011 fDeviceCMDirty = true; |
|
1012 |
|
1013 SkASSERT(fSaveLayerCount > 0); |
|
1014 fSaveLayerCount -= 1; |
|
1015 } |
|
1016 SkDELETE(layer); |
|
1017 } |
|
1018 } |
|
1019 |
|
1020 int SkCanvas::getSaveCount() const { |
|
1021 return fMCStack.count(); |
|
1022 } |
|
1023 |
|
1024 void SkCanvas::restoreToCount(int count) { |
|
1025 // sanity check |
|
1026 if (count < 1) { |
|
1027 count = 1; |
|
1028 } |
|
1029 |
|
1030 int n = this->getSaveCount() - count; |
|
1031 for (int i = 0; i < n; ++i) { |
|
1032 this->restore(); |
|
1033 } |
|
1034 } |
|
1035 |
|
1036 bool SkCanvas::isDrawingToLayer() const { |
|
1037 return fSaveLayerCount > 0; |
|
1038 } |
|
1039 |
|
1040 SkSurface* SkCanvas::newSurface(const SkImageInfo& info) { |
|
1041 return this->onNewSurface(info); |
|
1042 } |
|
1043 |
|
1044 SkSurface* SkCanvas::onNewSurface(const SkImageInfo& info) { |
|
1045 SkBaseDevice* dev = this->getDevice(); |
|
1046 return dev ? dev->newSurface(info) : NULL; |
|
1047 } |
|
1048 |
|
1049 SkImageInfo SkCanvas::imageInfo() const { |
|
1050 SkBaseDevice* dev = this->getDevice(); |
|
1051 if (dev) { |
|
1052 return dev->imageInfo(); |
|
1053 } else { |
|
1054 return SkImageInfo::MakeUnknown(0, 0); |
|
1055 } |
|
1056 } |
|
1057 |
|
1058 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) { |
|
1059 return this->onPeekPixels(info, rowBytes); |
|
1060 } |
|
1061 |
|
1062 const void* SkCanvas::onPeekPixels(SkImageInfo* info, size_t* rowBytes) { |
|
1063 SkBaseDevice* dev = this->getDevice(); |
|
1064 return dev ? dev->peekPixels(info, rowBytes) : NULL; |
|
1065 } |
|
1066 |
|
1067 void* SkCanvas::accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { |
|
1068 return this->onAccessTopLayerPixels(info, rowBytes); |
|
1069 } |
|
1070 |
|
1071 void* SkCanvas::onAccessTopLayerPixels(SkImageInfo* info, size_t* rowBytes) { |
|
1072 SkBaseDevice* dev = this->getTopDevice(); |
|
1073 return dev ? dev->accessPixels(info, rowBytes) : NULL; |
|
1074 } |
|
1075 |
|
1076 SkAutoROCanvasPixels::SkAutoROCanvasPixels(SkCanvas* canvas) { |
|
1077 fAddr = canvas->peekPixels(&fInfo, &fRowBytes); |
|
1078 if (NULL == fAddr) { |
|
1079 fInfo = canvas->imageInfo(); |
|
1080 if (kUnknown_SkColorType == fInfo.colorType() || |
|
1081 !fBitmap.allocPixels(fInfo)) |
|
1082 { |
|
1083 return; // failure, fAddr is NULL |
|
1084 } |
|
1085 fBitmap.lockPixels(); |
|
1086 if (!canvas->readPixels(&fBitmap, 0, 0)) { |
|
1087 return; // failure, fAddr is NULL |
|
1088 } |
|
1089 fAddr = fBitmap.getPixels(); |
|
1090 fRowBytes = fBitmap.rowBytes(); |
|
1091 } |
|
1092 SkASSERT(fAddr); // success |
|
1093 } |
|
1094 |
|
1095 bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { |
|
1096 if (fAddr) { |
|
1097 return bitmap->installPixels(fInfo, const_cast<void*>(fAddr), fRowBytes, |
|
1098 NULL, NULL); |
|
1099 } else { |
|
1100 bitmap->reset(); |
|
1101 return false; |
|
1102 } |
|
1103 } |
|
1104 |
|
1105 void SkCanvas::onPushCull(const SkRect& cullRect) { |
|
1106 // do nothing. Subclasses may do something |
|
1107 } |
|
1108 |
|
1109 void SkCanvas::onPopCull() { |
|
1110 // do nothing. Subclasses may do something |
|
1111 } |
|
1112 |
|
1113 ///////////////////////////////////////////////////////////////////////////// |
|
1114 |
|
1115 void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, |
|
1116 const SkMatrix& matrix, const SkPaint* paint) { |
|
1117 if (bitmap.drawsNothing()) { |
|
1118 return; |
|
1119 } |
|
1120 |
|
1121 SkLazyPaint lazy; |
|
1122 if (NULL == paint) { |
|
1123 paint = lazy.init(); |
|
1124 } |
|
1125 |
|
1126 SkDEBUGCODE(bitmap.validate();) |
|
1127 CHECK_LOCKCOUNT_BALANCE(bitmap); |
|
1128 |
|
1129 SkRect storage; |
|
1130 const SkRect* bounds = NULL; |
|
1131 if (paint && paint->canComputeFastBounds()) { |
|
1132 bitmap.getBounds(&storage); |
|
1133 matrix.mapRect(&storage); |
|
1134 bounds = &paint->computeFastBounds(storage, &storage); |
|
1135 } |
|
1136 |
|
1137 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) |
|
1138 |
|
1139 while (iter.next()) { |
|
1140 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); |
|
1141 } |
|
1142 |
|
1143 LOOPER_END |
|
1144 } |
|
1145 |
|
1146 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, |
|
1147 const SkPaint* paint) { |
|
1148 SkPaint tmp; |
|
1149 if (NULL == paint) { |
|
1150 tmp.setDither(true); |
|
1151 paint = &tmp; |
|
1152 } |
|
1153 |
|
1154 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) |
|
1155 while (iter.next()) { |
|
1156 SkBaseDevice* dstDev = iter.fDevice; |
|
1157 paint = &looper.paint(); |
|
1158 SkImageFilter* filter = paint->getImageFilter(); |
|
1159 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; |
|
1160 if (filter && !dstDev->canHandleImageFilter(filter)) { |
|
1161 SkDeviceImageFilterProxy proxy(dstDev); |
|
1162 SkBitmap dst; |
|
1163 SkIPoint offset = SkIPoint::Make(0, 0); |
|
1164 const SkBitmap& src = srcDev->accessBitmap(false); |
|
1165 SkMatrix matrix = *iter.fMatrix; |
|
1166 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); |
|
1167 SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height()); |
|
1168 SkImageFilter::Context ctx(matrix, clipBounds); |
|
1169 if (filter->filterImage(&proxy, src, ctx, &dst, &offset)) { |
|
1170 SkPaint tmpUnfiltered(*paint); |
|
1171 tmpUnfiltered.setImageFilter(NULL); |
|
1172 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), |
|
1173 tmpUnfiltered); |
|
1174 } |
|
1175 } else { |
|
1176 dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); |
|
1177 } |
|
1178 } |
|
1179 LOOPER_END |
|
1180 } |
|
1181 |
|
1182 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, |
|
1183 const SkPaint* paint) { |
|
1184 if (bitmap.drawsNothing()) { |
|
1185 return; |
|
1186 } |
|
1187 SkDEBUGCODE(bitmap.validate();) |
|
1188 CHECK_LOCKCOUNT_BALANCE(bitmap); |
|
1189 |
|
1190 SkPaint tmp; |
|
1191 if (NULL == paint) { |
|
1192 paint = &tmp; |
|
1193 } |
|
1194 |
|
1195 LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) |
|
1196 |
|
1197 while (iter.next()) { |
|
1198 paint = &looper.paint(); |
|
1199 SkImageFilter* filter = paint->getImageFilter(); |
|
1200 SkIPoint pos = { x - iter.getX(), y - iter.getY() }; |
|
1201 if (filter && !iter.fDevice->canHandleImageFilter(filter)) { |
|
1202 SkDeviceImageFilterProxy proxy(iter.fDevice); |
|
1203 SkBitmap dst; |
|
1204 SkIPoint offset = SkIPoint::Make(0, 0); |
|
1205 SkMatrix matrix = *iter.fMatrix; |
|
1206 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); |
|
1207 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); |
|
1208 SkImageFilter::Context ctx(matrix, clipBounds); |
|
1209 if (filter->filterImage(&proxy, bitmap, ctx, &dst, &offset)) { |
|
1210 SkPaint tmpUnfiltered(*paint); |
|
1211 tmpUnfiltered.setImageFilter(NULL); |
|
1212 iter.fDevice->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(), |
|
1213 tmpUnfiltered); |
|
1214 } |
|
1215 } else { |
|
1216 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); |
|
1217 } |
|
1218 } |
|
1219 LOOPER_END |
|
1220 } |
|
1221 |
|
1222 ///////////////////////////////////////////////////////////////////////////// |
|
1223 void SkCanvas::didTranslate(SkScalar, SkScalar) { |
|
1224 // Do nothing. Subclasses may do something. |
|
1225 } |
|
1226 |
|
1227 bool SkCanvas::translate(SkScalar dx, SkScalar dy) { |
|
1228 fDeviceCMDirty = true; |
|
1229 fCachedLocalClipBoundsDirty = true; |
|
1230 bool res = fMCRec->fMatrix->preTranslate(dx, dy); |
|
1231 |
|
1232 this->didTranslate(dx, dy); |
|
1233 return res; |
|
1234 } |
|
1235 |
|
1236 void SkCanvas::didScale(SkScalar, SkScalar) { |
|
1237 // Do nothing. Subclasses may do something. |
|
1238 } |
|
1239 |
|
1240 bool SkCanvas::scale(SkScalar sx, SkScalar sy) { |
|
1241 fDeviceCMDirty = true; |
|
1242 fCachedLocalClipBoundsDirty = true; |
|
1243 bool res = fMCRec->fMatrix->preScale(sx, sy); |
|
1244 |
|
1245 this->didScale(sx, sy); |
|
1246 return res; |
|
1247 } |
|
1248 |
|
1249 void SkCanvas::didRotate(SkScalar) { |
|
1250 // Do nothing. Subclasses may do something. |
|
1251 } |
|
1252 |
|
1253 bool SkCanvas::rotate(SkScalar degrees) { |
|
1254 fDeviceCMDirty = true; |
|
1255 fCachedLocalClipBoundsDirty = true; |
|
1256 bool res = fMCRec->fMatrix->preRotate(degrees); |
|
1257 |
|
1258 this->didRotate(degrees); |
|
1259 return res; |
|
1260 } |
|
1261 |
|
1262 void SkCanvas::didSkew(SkScalar, SkScalar) { |
|
1263 // Do nothing. Subclasses may do something. |
|
1264 } |
|
1265 |
|
1266 bool SkCanvas::skew(SkScalar sx, SkScalar sy) { |
|
1267 fDeviceCMDirty = true; |
|
1268 fCachedLocalClipBoundsDirty = true; |
|
1269 bool res = fMCRec->fMatrix->preSkew(sx, sy); |
|
1270 |
|
1271 this->didSkew(sx, sy); |
|
1272 return res; |
|
1273 } |
|
1274 |
|
1275 void SkCanvas::didConcat(const SkMatrix&) { |
|
1276 // Do nothing. Subclasses may do something. |
|
1277 } |
|
1278 |
|
1279 bool SkCanvas::concat(const SkMatrix& matrix) { |
|
1280 fDeviceCMDirty = true; |
|
1281 fCachedLocalClipBoundsDirty = true; |
|
1282 bool res = fMCRec->fMatrix->preConcat(matrix); |
|
1283 |
|
1284 this->didConcat(matrix); |
|
1285 return res; |
|
1286 } |
|
1287 |
|
1288 void SkCanvas::didSetMatrix(const SkMatrix&) { |
|
1289 // Do nothing. Subclasses may do something. |
|
1290 } |
|
1291 |
|
1292 void SkCanvas::setMatrix(const SkMatrix& matrix) { |
|
1293 fDeviceCMDirty = true; |
|
1294 fCachedLocalClipBoundsDirty = true; |
|
1295 *fMCRec->fMatrix = matrix; |
|
1296 this->didSetMatrix(matrix); |
|
1297 } |
|
1298 |
|
1299 void SkCanvas::resetMatrix() { |
|
1300 SkMatrix matrix; |
|
1301 |
|
1302 matrix.reset(); |
|
1303 this->setMatrix(matrix); |
|
1304 } |
|
1305 |
|
1306 ////////////////////////////////////////////////////////////////////////////// |
|
1307 |
|
1308 void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
|
1309 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
|
1310 this->onClipRect(rect, op, edgeStyle); |
|
1311 } |
|
1312 |
|
1313 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { |
|
1314 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
|
1315 if (SkRegion::kIntersect_Op == op) { |
|
1316 if (fMCRec->fRasterClip->isEmpty()) { |
|
1317 return false; |
|
1318 } |
|
1319 |
|
1320 if (this->quickReject(rect)) { |
|
1321 fDeviceCMDirty = true; |
|
1322 fCachedLocalClipBoundsDirty = true; |
|
1323 |
|
1324 fClipStack.clipEmpty(); |
|
1325 return fMCRec->fRasterClip->setEmpty(); |
|
1326 } |
|
1327 } |
|
1328 #endif |
|
1329 |
|
1330 AutoValidateClip avc(this); |
|
1331 |
|
1332 fDeviceCMDirty = true; |
|
1333 fCachedLocalClipBoundsDirty = true; |
|
1334 if (!fAllowSoftClip) { |
|
1335 edgeStyle = kHard_ClipEdgeStyle; |
|
1336 } |
|
1337 |
|
1338 if (fMCRec->fMatrix->rectStaysRect()) { |
|
1339 // for these simpler matrices, we can stay a rect even after applying |
|
1340 // the matrix. This means we don't have to a) make a path, and b) tell |
|
1341 // the region code to scan-convert the path, only to discover that it |
|
1342 // is really just a rect. |
|
1343 SkRect r; |
|
1344 |
|
1345 fMCRec->fMatrix->mapRect(&r, rect); |
|
1346 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
1347 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
1348 } else { |
|
1349 // since we're rotated or some such thing, we convert the rect to a path |
|
1350 // and clip against that, since it can handle any matrix. However, to |
|
1351 // avoid recursion in the case where we are subclassed (e.g. Pictures) |
|
1352 // we explicitly call "our" version of clipPath. |
|
1353 SkPath path; |
|
1354 |
|
1355 path.addRect(rect); |
|
1356 this->SkCanvas::onClipPath(path, op, edgeStyle); |
|
1357 } |
|
1358 } |
|
1359 |
|
1360 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, |
|
1361 const SkPath& devPath, SkRegion::Op op, bool doAA) { |
|
1362 // base is used to limit the size (and therefore memory allocation) of the |
|
1363 // region that results from scan converting devPath. |
|
1364 SkRegion base; |
|
1365 |
|
1366 if (SkRegion::kIntersect_Op == op) { |
|
1367 // since we are intersect, we can do better (tighter) with currRgn's |
|
1368 // bounds, than just using the device. However, if currRgn is complex, |
|
1369 // our region blitter may hork, so we do that case in two steps. |
|
1370 if (currClip->isRect()) { |
|
1371 // FIXME: we should also be able to do this when currClip->isBW(), |
|
1372 // but relaxing the test above triggers GM asserts in |
|
1373 // SkRgnBuilder::blitH(). We need to investigate what's going on. |
|
1374 currClip->setPath(devPath, currClip->bwRgn(), doAA); |
|
1375 } else { |
|
1376 base.setRect(currClip->getBounds()); |
|
1377 SkRasterClip clip; |
|
1378 clip.setPath(devPath, base, doAA); |
|
1379 currClip->op(clip, op); |
|
1380 } |
|
1381 } else { |
|
1382 const SkBaseDevice* device = canvas->getDevice(); |
|
1383 if (!device) { |
|
1384 currClip->setEmpty(); |
|
1385 return; |
|
1386 } |
|
1387 |
|
1388 base.setRect(0, 0, device->width(), device->height()); |
|
1389 |
|
1390 if (SkRegion::kReplace_Op == op) { |
|
1391 currClip->setPath(devPath, base, doAA); |
|
1392 } else { |
|
1393 SkRasterClip clip; |
|
1394 clip.setPath(devPath, base, doAA); |
|
1395 currClip->op(clip, op); |
|
1396 } |
|
1397 } |
|
1398 } |
|
1399 |
|
1400 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
|
1401 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
|
1402 if (rrect.isRect()) { |
|
1403 this->onClipRect(rrect.getBounds(), op, edgeStyle); |
|
1404 } else { |
|
1405 this->onClipRRect(rrect, op, edgeStyle); |
|
1406 } |
|
1407 } |
|
1408 |
|
1409 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { |
|
1410 SkRRect transformedRRect; |
|
1411 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { |
|
1412 AutoValidateClip avc(this); |
|
1413 |
|
1414 fDeviceCMDirty = true; |
|
1415 fCachedLocalClipBoundsDirty = true; |
|
1416 if (!fAllowSoftClip) { |
|
1417 edgeStyle = kHard_ClipEdgeStyle; |
|
1418 } |
|
1419 |
|
1420 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
1421 |
|
1422 SkPath devPath; |
|
1423 devPath.addRRect(transformedRRect); |
|
1424 |
|
1425 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
1426 return; |
|
1427 } |
|
1428 |
|
1429 SkPath path; |
|
1430 path.addRRect(rrect); |
|
1431 // call the non-virtual version |
|
1432 this->SkCanvas::onClipPath(path, op, edgeStyle); |
|
1433 } |
|
1434 |
|
1435 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
|
1436 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
|
1437 SkRect r; |
|
1438 if (!path.isInverseFillType() && path.isRect(&r)) { |
|
1439 this->onClipRect(r, op, edgeStyle); |
|
1440 } else { |
|
1441 this->onClipPath(path, op, edgeStyle); |
|
1442 } |
|
1443 } |
|
1444 |
|
1445 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { |
|
1446 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
|
1447 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { |
|
1448 if (fMCRec->fRasterClip->isEmpty()) { |
|
1449 return false; |
|
1450 } |
|
1451 |
|
1452 if (this->quickReject(path.getBounds())) { |
|
1453 fDeviceCMDirty = true; |
|
1454 fCachedLocalClipBoundsDirty = true; |
|
1455 |
|
1456 fClipStack.clipEmpty(); |
|
1457 return fMCRec->fRasterClip->setEmpty(); |
|
1458 } |
|
1459 } |
|
1460 #endif |
|
1461 |
|
1462 AutoValidateClip avc(this); |
|
1463 |
|
1464 fDeviceCMDirty = true; |
|
1465 fCachedLocalClipBoundsDirty = true; |
|
1466 if (!fAllowSoftClip) { |
|
1467 edgeStyle = kHard_ClipEdgeStyle; |
|
1468 } |
|
1469 |
|
1470 SkPath devPath; |
|
1471 path.transform(*fMCRec->fMatrix, &devPath); |
|
1472 |
|
1473 // Check if the transfomation, or the original path itself |
|
1474 // made us empty. Note this can also happen if we contained NaN |
|
1475 // values. computing the bounds detects this, and will set our |
|
1476 // bounds to empty if that is the case. (see SkRect::set(pts, count)) |
|
1477 if (devPath.getBounds().isEmpty()) { |
|
1478 // resetting the path will remove any NaN or other wanky values |
|
1479 // that might upset our scan converter. |
|
1480 devPath.reset(); |
|
1481 } |
|
1482 |
|
1483 // if we called path.swap() we could avoid a deep copy of this path |
|
1484 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); |
|
1485 |
|
1486 if (fAllowSimplifyClip) { |
|
1487 devPath.reset(); |
|
1488 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); |
|
1489 const SkClipStack* clipStack = getClipStack(); |
|
1490 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart); |
|
1491 const SkClipStack::Element* element; |
|
1492 while ((element = iter.next())) { |
|
1493 SkClipStack::Element::Type type = element->getType(); |
|
1494 if (type == SkClipStack::Element::kEmpty_Type) { |
|
1495 continue; |
|
1496 } |
|
1497 SkPath operand; |
|
1498 element->asPath(&operand); |
|
1499 SkRegion::Op elementOp = element->getOp(); |
|
1500 if (elementOp == SkRegion::kReplace_Op) { |
|
1501 devPath = operand; |
|
1502 } else { |
|
1503 Op(devPath, operand, (SkPathOp) elementOp, &devPath); |
|
1504 } |
|
1505 // if the prev and curr clips disagree about aa -vs- not, favor the aa request. |
|
1506 // perhaps we need an API change to avoid this sort of mixed-signals about |
|
1507 // clipping. |
|
1508 if (element->isAA()) { |
|
1509 edgeStyle = kSoft_ClipEdgeStyle; |
|
1510 } |
|
1511 } |
|
1512 op = SkRegion::kReplace_Op; |
|
1513 } |
|
1514 |
|
1515 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); |
|
1516 } |
|
1517 |
|
1518 void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op, |
|
1519 bool inverseFilled) { |
|
1520 // This is for updating the clip conservatively using only bounds |
|
1521 // information. |
|
1522 // Contract: |
|
1523 // The current clip must contain the true clip. The true |
|
1524 // clip is the clip that would have normally been computed |
|
1525 // by calls to clipPath and clipRRect |
|
1526 // Objective: |
|
1527 // Keep the current clip as small as possible without |
|
1528 // breaking the contract, using only clip bounding rectangles |
|
1529 // (for performance). |
|
1530 |
|
1531 // N.B.: This *never* calls back through a virtual on canvas, so subclasses |
|
1532 // don't have to worry about getting caught in a loop. Thus anywhere |
|
1533 // we call a virtual method, we explicitly prefix it with |
|
1534 // SkCanvas:: to be sure to call the base-class. |
|
1535 |
|
1536 if (inverseFilled) { |
|
1537 switch (op) { |
|
1538 case SkRegion::kIntersect_Op: |
|
1539 case SkRegion::kDifference_Op: |
|
1540 // These ops can only shrink the current clip. So leaving |
|
1541 // the clip unchanged conservatively respects the contract. |
|
1542 break; |
|
1543 case SkRegion::kUnion_Op: |
|
1544 case SkRegion::kReplace_Op: |
|
1545 case SkRegion::kReverseDifference_Op: |
|
1546 case SkRegion::kXOR_Op: { |
|
1547 // These ops can grow the current clip up to the extents of |
|
1548 // the input clip, which is inverse filled, so we just set |
|
1549 // the current clip to the device bounds. |
|
1550 SkRect deviceBounds; |
|
1551 SkIRect deviceIBounds; |
|
1552 this->getDevice()->getGlobalBounds(&deviceIBounds); |
|
1553 deviceBounds = SkRect::Make(deviceIBounds); |
|
1554 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); |
|
1555 // set the clip in device space |
|
1556 this->SkCanvas::setMatrix(SkMatrix::I()); |
|
1557 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op, |
|
1558 kHard_ClipEdgeStyle); |
|
1559 this->SkCanvas::restore(); //pop the matrix, but keep the clip |
|
1560 break; |
|
1561 } |
|
1562 default: |
|
1563 SkASSERT(0); // unhandled op? |
|
1564 } |
|
1565 } else { |
|
1566 // Not inverse filled |
|
1567 switch (op) { |
|
1568 case SkRegion::kIntersect_Op: |
|
1569 case SkRegion::kUnion_Op: |
|
1570 case SkRegion::kReplace_Op: |
|
1571 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); |
|
1572 break; |
|
1573 case SkRegion::kDifference_Op: |
|
1574 // Difference can only shrink the current clip. |
|
1575 // Leaving clip unchanged conservatively fullfills the contract. |
|
1576 break; |
|
1577 case SkRegion::kReverseDifference_Op: |
|
1578 // To reverse, we swap in the bounds with a replace op. |
|
1579 // As with difference, leave it unchanged. |
|
1580 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle); |
|
1581 break; |
|
1582 case SkRegion::kXOR_Op: |
|
1583 // Be conservative, based on (A XOR B) always included in (A union B), |
|
1584 // which is always included in (bounds(A) union bounds(B)) |
|
1585 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle); |
|
1586 break; |
|
1587 default: |
|
1588 SkASSERT(0); // unhandled op? |
|
1589 } |
|
1590 } |
|
1591 } |
|
1592 |
|
1593 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
|
1594 this->onClipRegion(rgn, op); |
|
1595 } |
|
1596 |
|
1597 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { |
|
1598 AutoValidateClip avc(this); |
|
1599 |
|
1600 fDeviceCMDirty = true; |
|
1601 fCachedLocalClipBoundsDirty = true; |
|
1602 |
|
1603 // todo: signal fClipStack that we have a region, and therefore (I guess) |
|
1604 // we have to ignore it, and use the region directly? |
|
1605 fClipStack.clipDevRect(rgn.getBounds(), op); |
|
1606 |
|
1607 fMCRec->fRasterClip->op(rgn, op); |
|
1608 } |
|
1609 |
|
1610 #ifdef SK_DEBUG |
|
1611 void SkCanvas::validateClip() const { |
|
1612 // construct clipRgn from the clipstack |
|
1613 const SkBaseDevice* device = this->getDevice(); |
|
1614 if (!device) { |
|
1615 SkASSERT(this->isClipEmpty()); |
|
1616 return; |
|
1617 } |
|
1618 |
|
1619 SkIRect ir; |
|
1620 ir.set(0, 0, device->width(), device->height()); |
|
1621 SkRasterClip tmpClip(ir); |
|
1622 |
|
1623 SkClipStack::B2TIter iter(fClipStack); |
|
1624 const SkClipStack::Element* element; |
|
1625 while ((element = iter.next()) != NULL) { |
|
1626 switch (element->getType()) { |
|
1627 case SkClipStack::Element::kRect_Type: |
|
1628 element->getRect().round(&ir); |
|
1629 tmpClip.op(ir, element->getOp()); |
|
1630 break; |
|
1631 case SkClipStack::Element::kEmpty_Type: |
|
1632 tmpClip.setEmpty(); |
|
1633 break; |
|
1634 default: { |
|
1635 SkPath path; |
|
1636 element->asPath(&path); |
|
1637 clip_path_helper(this, &tmpClip, path, element->getOp(), element->isAA()); |
|
1638 break; |
|
1639 } |
|
1640 } |
|
1641 } |
|
1642 } |
|
1643 #endif |
|
1644 |
|
1645 void SkCanvas::replayClips(ClipVisitor* visitor) const { |
|
1646 SkClipStack::B2TIter iter(fClipStack); |
|
1647 const SkClipStack::Element* element; |
|
1648 |
|
1649 static const SkRect kEmpty = { 0, 0, 0, 0 }; |
|
1650 while ((element = iter.next()) != NULL) { |
|
1651 switch (element->getType()) { |
|
1652 case SkClipStack::Element::kPath_Type: |
|
1653 visitor->clipPath(element->getPath(), element->getOp(), element->isAA()); |
|
1654 break; |
|
1655 case SkClipStack::Element::kRRect_Type: |
|
1656 visitor->clipRRect(element->getRRect(), element->getOp(), element->isAA()); |
|
1657 break; |
|
1658 case SkClipStack::Element::kRect_Type: |
|
1659 visitor->clipRect(element->getRect(), element->getOp(), element->isAA()); |
|
1660 break; |
|
1661 case SkClipStack::Element::kEmpty_Type: |
|
1662 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); |
|
1663 break; |
|
1664 } |
|
1665 } |
|
1666 } |
|
1667 |
|
1668 /////////////////////////////////////////////////////////////////////////////// |
|
1669 |
|
1670 bool SkCanvas::isClipEmpty() const { |
|
1671 return fMCRec->fRasterClip->isEmpty(); |
|
1672 } |
|
1673 |
|
1674 bool SkCanvas::isClipRect() const { |
|
1675 return fMCRec->fRasterClip->isRect(); |
|
1676 } |
|
1677 |
|
1678 bool SkCanvas::quickReject(const SkRect& rect) const { |
|
1679 |
|
1680 if (!rect.isFinite()) |
|
1681 return true; |
|
1682 |
|
1683 if (fMCRec->fRasterClip->isEmpty()) { |
|
1684 return true; |
|
1685 } |
|
1686 |
|
1687 if (fMCRec->fMatrix->hasPerspective()) { |
|
1688 SkRect dst; |
|
1689 fMCRec->fMatrix->mapRect(&dst, rect); |
|
1690 SkIRect idst; |
|
1691 dst.roundOut(&idst); |
|
1692 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); |
|
1693 } else { |
|
1694 const SkRect& clipR = this->getLocalClipBounds(); |
|
1695 |
|
1696 // for speed, do the most likely reject compares first |
|
1697 // TODO: should we use | instead, or compare all 4 at once? |
|
1698 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { |
|
1699 return true; |
|
1700 } |
|
1701 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { |
|
1702 return true; |
|
1703 } |
|
1704 return false; |
|
1705 } |
|
1706 } |
|
1707 |
|
1708 bool SkCanvas::quickReject(const SkPath& path) const { |
|
1709 return path.isEmpty() || this->quickReject(path.getBounds()); |
|
1710 } |
|
1711 |
|
1712 bool SkCanvas::getClipBounds(SkRect* bounds) const { |
|
1713 SkIRect ibounds; |
|
1714 if (!this->getClipDeviceBounds(&ibounds)) { |
|
1715 return false; |
|
1716 } |
|
1717 |
|
1718 SkMatrix inverse; |
|
1719 // if we can't invert the CTM, we can't return local clip bounds |
|
1720 if (!fMCRec->fMatrix->invert(&inverse)) { |
|
1721 if (bounds) { |
|
1722 bounds->setEmpty(); |
|
1723 } |
|
1724 return false; |
|
1725 } |
|
1726 |
|
1727 if (NULL != bounds) { |
|
1728 SkRect r; |
|
1729 // adjust it outwards in case we are antialiasing |
|
1730 const int inset = 1; |
|
1731 |
|
1732 r.iset(ibounds.fLeft - inset, ibounds.fTop - inset, |
|
1733 ibounds.fRight + inset, ibounds.fBottom + inset); |
|
1734 inverse.mapRect(bounds, r); |
|
1735 } |
|
1736 return true; |
|
1737 } |
|
1738 |
|
1739 bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const { |
|
1740 const SkRasterClip& clip = *fMCRec->fRasterClip; |
|
1741 if (clip.isEmpty()) { |
|
1742 if (bounds) { |
|
1743 bounds->setEmpty(); |
|
1744 } |
|
1745 return false; |
|
1746 } |
|
1747 |
|
1748 if (NULL != bounds) { |
|
1749 *bounds = clip.getBounds(); |
|
1750 } |
|
1751 return true; |
|
1752 } |
|
1753 |
|
1754 const SkMatrix& SkCanvas::getTotalMatrix() const { |
|
1755 return *fMCRec->fMatrix; |
|
1756 } |
|
1757 |
|
1758 #ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE |
|
1759 SkCanvas::ClipType SkCanvas::getClipType() const { |
|
1760 if (fMCRec->fRasterClip->isEmpty()) { |
|
1761 return kEmpty_ClipType; |
|
1762 } |
|
1763 if (fMCRec->fRasterClip->isRect()) { |
|
1764 return kRect_ClipType; |
|
1765 } |
|
1766 return kComplex_ClipType; |
|
1767 } |
|
1768 #endif |
|
1769 |
|
1770 #ifdef SK_SUPPORT_LEGACY_GETTOTALCLIP |
|
1771 const SkRegion& SkCanvas::getTotalClip() const { |
|
1772 return fMCRec->fRasterClip->forceGetBW(); |
|
1773 } |
|
1774 #endif |
|
1775 |
|
1776 const SkRegion& SkCanvas::internal_private_getTotalClip() const { |
|
1777 return fMCRec->fRasterClip->forceGetBW(); |
|
1778 } |
|
1779 |
|
1780 void SkCanvas::internal_private_getTotalClipAsPath(SkPath* path) const { |
|
1781 path->reset(); |
|
1782 |
|
1783 const SkRegion& rgn = fMCRec->fRasterClip->forceGetBW(); |
|
1784 if (rgn.isEmpty()) { |
|
1785 return; |
|
1786 } |
|
1787 (void)rgn.getBoundaryPath(path); |
|
1788 } |
|
1789 |
|
1790 GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() { |
|
1791 SkBaseDevice* dev = this->getTopDevice(); |
|
1792 return dev ? dev->accessRenderTarget() : NULL; |
|
1793 } |
|
1794 |
|
1795 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { |
|
1796 SkBaseDevice* device = this->getTopDevice(); |
|
1797 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; |
|
1798 } |
|
1799 |
|
1800 GrContext* SkCanvas::getGrContext() { |
|
1801 #if SK_SUPPORT_GPU |
|
1802 SkBaseDevice* device = this->getTopDevice(); |
|
1803 if (NULL != device) { |
|
1804 GrRenderTarget* renderTarget = device->accessRenderTarget(); |
|
1805 if (NULL != renderTarget) { |
|
1806 return renderTarget->getContext(); |
|
1807 } |
|
1808 } |
|
1809 #endif |
|
1810 |
|
1811 return NULL; |
|
1812 |
|
1813 } |
|
1814 |
|
1815 void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, |
|
1816 const SkPaint& paint) { |
|
1817 if (outer.isEmpty()) { |
|
1818 return; |
|
1819 } |
|
1820 if (inner.isEmpty()) { |
|
1821 this->drawRRect(outer, paint); |
|
1822 return; |
|
1823 } |
|
1824 |
|
1825 // We don't have this method (yet), but technically this is what we should |
|
1826 // be able to assert... |
|
1827 // SkASSERT(outer.contains(inner)); |
|
1828 // |
|
1829 // For now at least check for containment of bounds |
|
1830 SkASSERT(outer.getBounds().contains(inner.getBounds())); |
|
1831 |
|
1832 this->onDrawDRRect(outer, inner, paint); |
|
1833 } |
|
1834 |
|
1835 ////////////////////////////////////////////////////////////////////////////// |
|
1836 // These are the virtual drawing methods |
|
1837 ////////////////////////////////////////////////////////////////////////////// |
|
1838 |
|
1839 void SkCanvas::clear(SkColor color) { |
|
1840 SkDrawIter iter(this); |
|
1841 this->predrawNotify(); |
|
1842 while (iter.next()) { |
|
1843 iter.fDevice->clear(color); |
|
1844 } |
|
1845 } |
|
1846 |
|
1847 void SkCanvas::drawPaint(const SkPaint& paint) { |
|
1848 this->internalDrawPaint(paint); |
|
1849 } |
|
1850 |
|
1851 void SkCanvas::internalDrawPaint(const SkPaint& paint) { |
|
1852 CHECK_SHADER_NOSETCONTEXT(paint); |
|
1853 |
|
1854 LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL) |
|
1855 |
|
1856 while (iter.next()) { |
|
1857 iter.fDevice->drawPaint(iter, looper.paint()); |
|
1858 } |
|
1859 |
|
1860 LOOPER_END |
|
1861 } |
|
1862 |
|
1863 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], |
|
1864 const SkPaint& paint) { |
|
1865 if ((long)count <= 0) { |
|
1866 return; |
|
1867 } |
|
1868 |
|
1869 CHECK_SHADER_NOSETCONTEXT(paint); |
|
1870 |
|
1871 SkRect r, storage; |
|
1872 const SkRect* bounds = NULL; |
|
1873 if (paint.canComputeFastBounds()) { |
|
1874 // special-case 2 points (common for drawing a single line) |
|
1875 if (2 == count) { |
|
1876 r.set(pts[0], pts[1]); |
|
1877 } else { |
|
1878 r.set(pts, SkToInt(count)); |
|
1879 } |
|
1880 bounds = &paint.computeFastStrokeBounds(r, &storage); |
|
1881 if (this->quickReject(*bounds)) { |
|
1882 return; |
|
1883 } |
|
1884 } |
|
1885 |
|
1886 SkASSERT(pts != NULL); |
|
1887 |
|
1888 LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type, bounds) |
|
1889 |
|
1890 while (iter.next()) { |
|
1891 iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint()); |
|
1892 } |
|
1893 |
|
1894 LOOPER_END |
|
1895 } |
|
1896 |
|
1897 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { |
|
1898 CHECK_SHADER_NOSETCONTEXT(paint); |
|
1899 |
|
1900 SkRect storage; |
|
1901 const SkRect* bounds = NULL; |
|
1902 if (paint.canComputeFastBounds()) { |
|
1903 bounds = &paint.computeFastBounds(r, &storage); |
|
1904 if (this->quickReject(*bounds)) { |
|
1905 return; |
|
1906 } |
|
1907 } |
|
1908 |
|
1909 LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) |
|
1910 |
|
1911 while (iter.next()) { |
|
1912 iter.fDevice->drawRect(iter, r, looper.paint()); |
|
1913 } |
|
1914 |
|
1915 LOOPER_END |
|
1916 } |
|
1917 |
|
1918 void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { |
|
1919 CHECK_SHADER_NOSETCONTEXT(paint); |
|
1920 |
|
1921 SkRect storage; |
|
1922 const SkRect* bounds = NULL; |
|
1923 if (paint.canComputeFastBounds()) { |
|
1924 bounds = &paint.computeFastBounds(oval, &storage); |
|
1925 if (this->quickReject(*bounds)) { |
|
1926 return; |
|
1927 } |
|
1928 } |
|
1929 |
|
1930 LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) |
|
1931 |
|
1932 while (iter.next()) { |
|
1933 iter.fDevice->drawOval(iter, oval, looper.paint()); |
|
1934 } |
|
1935 |
|
1936 LOOPER_END |
|
1937 } |
|
1938 |
|
1939 void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { |
|
1940 CHECK_SHADER_NOSETCONTEXT(paint); |
|
1941 |
|
1942 SkRect storage; |
|
1943 const SkRect* bounds = NULL; |
|
1944 if (paint.canComputeFastBounds()) { |
|
1945 bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); |
|
1946 if (this->quickReject(*bounds)) { |
|
1947 return; |
|
1948 } |
|
1949 } |
|
1950 |
|
1951 if (rrect.isRect()) { |
|
1952 // call the non-virtual version |
|
1953 this->SkCanvas::drawRect(rrect.getBounds(), paint); |
|
1954 return; |
|
1955 } else if (rrect.isOval()) { |
|
1956 // call the non-virtual version |
|
1957 this->SkCanvas::drawOval(rrect.getBounds(), paint); |
|
1958 return; |
|
1959 } |
|
1960 |
|
1961 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) |
|
1962 |
|
1963 while (iter.next()) { |
|
1964 iter.fDevice->drawRRect(iter, rrect, looper.paint()); |
|
1965 } |
|
1966 |
|
1967 LOOPER_END |
|
1968 } |
|
1969 |
|
1970 void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, |
|
1971 const SkPaint& paint) { |
|
1972 CHECK_SHADER_NOSETCONTEXT(paint); |
|
1973 |
|
1974 SkRect storage; |
|
1975 const SkRect* bounds = NULL; |
|
1976 if (paint.canComputeFastBounds()) { |
|
1977 bounds = &paint.computeFastBounds(outer.getBounds(), &storage); |
|
1978 if (this->quickReject(*bounds)) { |
|
1979 return; |
|
1980 } |
|
1981 } |
|
1982 |
|
1983 LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) |
|
1984 |
|
1985 while (iter.next()) { |
|
1986 iter.fDevice->drawDRRect(iter, outer, inner, looper.paint()); |
|
1987 } |
|
1988 |
|
1989 LOOPER_END |
|
1990 } |
|
1991 |
|
1992 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) { |
|
1993 CHECK_SHADER_NOSETCONTEXT(paint); |
|
1994 |
|
1995 if (!path.isFinite()) { |
|
1996 return; |
|
1997 } |
|
1998 |
|
1999 SkRect storage; |
|
2000 const SkRect* bounds = NULL; |
|
2001 if (!path.isInverseFillType() && paint.canComputeFastBounds()) { |
|
2002 const SkRect& pathBounds = path.getBounds(); |
|
2003 bounds = &paint.computeFastBounds(pathBounds, &storage); |
|
2004 if (this->quickReject(*bounds)) { |
|
2005 return; |
|
2006 } |
|
2007 } |
|
2008 |
|
2009 const SkRect& r = path.getBounds(); |
|
2010 if (r.width() <= 0 && r.height() <= 0) { |
|
2011 if (path.isInverseFillType()) { |
|
2012 this->internalDrawPaint(paint); |
|
2013 } |
|
2014 return; |
|
2015 } |
|
2016 |
|
2017 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, bounds) |
|
2018 |
|
2019 while (iter.next()) { |
|
2020 iter.fDevice->drawPath(iter, path, looper.paint()); |
|
2021 } |
|
2022 |
|
2023 LOOPER_END |
|
2024 } |
|
2025 |
|
2026 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, |
|
2027 const SkPaint* paint) { |
|
2028 SkDEBUGCODE(bitmap.validate();) |
|
2029 |
|
2030 if (NULL == paint || paint->canComputeFastBounds()) { |
|
2031 SkRect bounds = { |
|
2032 x, y, |
|
2033 x + SkIntToScalar(bitmap.width()), |
|
2034 y + SkIntToScalar(bitmap.height()) |
|
2035 }; |
|
2036 if (paint) { |
|
2037 (void)paint->computeFastBounds(bounds, &bounds); |
|
2038 } |
|
2039 if (this->quickReject(bounds)) { |
|
2040 return; |
|
2041 } |
|
2042 } |
|
2043 |
|
2044 SkMatrix matrix; |
|
2045 matrix.setTranslate(x, y); |
|
2046 this->internalDrawBitmap(bitmap, matrix, paint); |
|
2047 } |
|
2048 |
|
2049 // this one is non-virtual, so it can be called safely by other canvas apis |
|
2050 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, |
|
2051 const SkRect& dst, const SkPaint* paint, |
|
2052 DrawBitmapRectFlags flags) { |
|
2053 if (bitmap.drawsNothing() || dst.isEmpty()) { |
|
2054 return; |
|
2055 } |
|
2056 |
|
2057 CHECK_LOCKCOUNT_BALANCE(bitmap); |
|
2058 |
|
2059 SkRect storage; |
|
2060 const SkRect* bounds = &dst; |
|
2061 if (NULL == paint || paint->canComputeFastBounds()) { |
|
2062 if (paint) { |
|
2063 bounds = &paint->computeFastBounds(dst, &storage); |
|
2064 } |
|
2065 if (this->quickReject(*bounds)) { |
|
2066 return; |
|
2067 } |
|
2068 } |
|
2069 |
|
2070 SkLazyPaint lazy; |
|
2071 if (NULL == paint) { |
|
2072 paint = lazy.init(); |
|
2073 } |
|
2074 |
|
2075 LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) |
|
2076 |
|
2077 while (iter.next()) { |
|
2078 iter.fDevice->drawBitmapRect(iter, bitmap, src, dst, looper.paint(), flags); |
|
2079 } |
|
2080 |
|
2081 LOOPER_END |
|
2082 } |
|
2083 |
|
2084 void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, |
|
2085 const SkRect& dst, const SkPaint* paint, |
|
2086 DrawBitmapRectFlags flags) { |
|
2087 SkDEBUGCODE(bitmap.validate();) |
|
2088 this->internalDrawBitmapRect(bitmap, src, dst, paint, flags); |
|
2089 } |
|
2090 |
|
2091 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, |
|
2092 const SkPaint* paint) { |
|
2093 SkDEBUGCODE(bitmap.validate();) |
|
2094 this->internalDrawBitmap(bitmap, matrix, paint); |
|
2095 } |
|
2096 |
|
2097 void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap, |
|
2098 const SkIRect& center, const SkRect& dst, |
|
2099 const SkPaint* paint) { |
|
2100 if (bitmap.drawsNothing()) { |
|
2101 return; |
|
2102 } |
|
2103 if (NULL == paint || paint->canComputeFastBounds()) { |
|
2104 SkRect storage; |
|
2105 const SkRect* bounds = &dst; |
|
2106 if (paint) { |
|
2107 bounds = &paint->computeFastBounds(dst, &storage); |
|
2108 } |
|
2109 if (this->quickReject(*bounds)) { |
|
2110 return; |
|
2111 } |
|
2112 } |
|
2113 |
|
2114 const int32_t w = bitmap.width(); |
|
2115 const int32_t h = bitmap.height(); |
|
2116 |
|
2117 SkIRect c = center; |
|
2118 // pin center to the bounds of the bitmap |
|
2119 c.fLeft = SkMax32(0, center.fLeft); |
|
2120 c.fTop = SkMax32(0, center.fTop); |
|
2121 c.fRight = SkPin32(center.fRight, c.fLeft, w); |
|
2122 c.fBottom = SkPin32(center.fBottom, c.fTop, h); |
|
2123 |
|
2124 const SkScalar srcX[4] = { |
|
2125 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w) |
|
2126 }; |
|
2127 const SkScalar srcY[4] = { |
|
2128 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h) |
|
2129 }; |
|
2130 SkScalar dstX[4] = { |
|
2131 dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft), |
|
2132 dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight |
|
2133 }; |
|
2134 SkScalar dstY[4] = { |
|
2135 dst.fTop, dst.fTop + SkIntToScalar(c.fTop), |
|
2136 dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom |
|
2137 }; |
|
2138 |
|
2139 if (dstX[1] > dstX[2]) { |
|
2140 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width()); |
|
2141 dstX[2] = dstX[1]; |
|
2142 } |
|
2143 |
|
2144 if (dstY[1] > dstY[2]) { |
|
2145 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height()); |
|
2146 dstY[2] = dstY[1]; |
|
2147 } |
|
2148 |
|
2149 for (int y = 0; y < 3; y++) { |
|
2150 SkRect s, d; |
|
2151 |
|
2152 s.fTop = srcY[y]; |
|
2153 s.fBottom = srcY[y+1]; |
|
2154 d.fTop = dstY[y]; |
|
2155 d.fBottom = dstY[y+1]; |
|
2156 for (int x = 0; x < 3; x++) { |
|
2157 s.fLeft = srcX[x]; |
|
2158 s.fRight = srcX[x+1]; |
|
2159 d.fLeft = dstX[x]; |
|
2160 d.fRight = dstX[x+1]; |
|
2161 this->internalDrawBitmapRect(bitmap, &s, d, paint, |
|
2162 kNone_DrawBitmapRectFlag); |
|
2163 } |
|
2164 } |
|
2165 } |
|
2166 |
|
2167 void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, |
|
2168 const SkRect& dst, const SkPaint* paint) { |
|
2169 SkDEBUGCODE(bitmap.validate();) |
|
2170 |
|
2171 // Need a device entry-point, so gpu can use a mesh |
|
2172 this->internalDrawBitmapNine(bitmap, center, dst, paint); |
|
2173 } |
|
2174 |
|
2175 class SkDeviceFilteredPaint { |
|
2176 public: |
|
2177 SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { |
|
2178 SkBaseDevice::TextFlags flags; |
|
2179 if (device->filterTextFlags(paint, &flags)) { |
|
2180 SkPaint* newPaint = fLazy.set(paint); |
|
2181 newPaint->setFlags(flags.fFlags); |
|
2182 newPaint->setHinting(flags.fHinting); |
|
2183 fPaint = newPaint; |
|
2184 } else { |
|
2185 fPaint = &paint; |
|
2186 } |
|
2187 } |
|
2188 |
|
2189 const SkPaint& paint() const { return *fPaint; } |
|
2190 |
|
2191 private: |
|
2192 const SkPaint* fPaint; |
|
2193 SkLazyPaint fLazy; |
|
2194 }; |
|
2195 |
|
2196 void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint, |
|
2197 const SkRect& r, SkScalar textSize) { |
|
2198 if (paint.getStyle() == SkPaint::kFill_Style) { |
|
2199 draw.fDevice->drawRect(draw, r, paint); |
|
2200 } else { |
|
2201 SkPaint p(paint); |
|
2202 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth())); |
|
2203 draw.fDevice->drawRect(draw, r, p); |
|
2204 } |
|
2205 } |
|
2206 |
|
2207 void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, |
|
2208 const char text[], size_t byteLength, |
|
2209 SkScalar x, SkScalar y) { |
|
2210 SkASSERT(byteLength == 0 || text != NULL); |
|
2211 |
|
2212 // nothing to draw |
|
2213 if (text == NULL || byteLength == 0 || |
|
2214 draw.fClip->isEmpty() || |
|
2215 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) { |
|
2216 return; |
|
2217 } |
|
2218 |
|
2219 SkScalar width = 0; |
|
2220 SkPoint start; |
|
2221 |
|
2222 start.set(0, 0); // to avoid warning |
|
2223 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag | |
|
2224 SkPaint::kStrikeThruText_Flag)) { |
|
2225 width = paint.measureText(text, byteLength); |
|
2226 |
|
2227 SkScalar offsetX = 0; |
|
2228 if (paint.getTextAlign() == SkPaint::kCenter_Align) { |
|
2229 offsetX = SkScalarHalf(width); |
|
2230 } else if (paint.getTextAlign() == SkPaint::kRight_Align) { |
|
2231 offsetX = width; |
|
2232 } |
|
2233 start.set(x - offsetX, y); |
|
2234 } |
|
2235 |
|
2236 if (0 == width) { |
|
2237 return; |
|
2238 } |
|
2239 |
|
2240 uint32_t flags = paint.getFlags(); |
|
2241 |
|
2242 if (flags & (SkPaint::kUnderlineText_Flag | |
|
2243 SkPaint::kStrikeThruText_Flag)) { |
|
2244 SkScalar textSize = paint.getTextSize(); |
|
2245 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness); |
|
2246 SkRect r; |
|
2247 |
|
2248 r.fLeft = start.fX; |
|
2249 r.fRight = start.fX + width; |
|
2250 |
|
2251 if (flags & SkPaint::kUnderlineText_Flag) { |
|
2252 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset, |
|
2253 start.fY); |
|
2254 r.fTop = offset; |
|
2255 r.fBottom = offset + height; |
|
2256 DrawRect(draw, paint, r, textSize); |
|
2257 } |
|
2258 if (flags & SkPaint::kStrikeThruText_Flag) { |
|
2259 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, |
|
2260 start.fY); |
|
2261 r.fTop = offset; |
|
2262 r.fBottom = offset + height; |
|
2263 DrawRect(draw, paint, r, textSize); |
|
2264 } |
|
2265 } |
|
2266 } |
|
2267 |
|
2268 void SkCanvas::drawText(const void* text, size_t byteLength, |
|
2269 SkScalar x, SkScalar y, const SkPaint& paint) { |
|
2270 CHECK_SHADER_NOSETCONTEXT(paint); |
|
2271 |
|
2272 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) |
|
2273 |
|
2274 while (iter.next()) { |
|
2275 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); |
|
2276 iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint()); |
|
2277 DrawTextDecorations(iter, dfp.paint(), |
|
2278 static_cast<const char*>(text), byteLength, x, y); |
|
2279 } |
|
2280 |
|
2281 LOOPER_END |
|
2282 } |
|
2283 |
|
2284 void SkCanvas::drawPosText(const void* text, size_t byteLength, |
|
2285 const SkPoint pos[], const SkPaint& paint) { |
|
2286 CHECK_SHADER_NOSETCONTEXT(paint); |
|
2287 |
|
2288 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) |
|
2289 |
|
2290 while (iter.next()) { |
|
2291 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); |
|
2292 iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, |
|
2293 dfp.paint()); |
|
2294 } |
|
2295 |
|
2296 LOOPER_END |
|
2297 } |
|
2298 |
|
2299 void SkCanvas::drawPosTextH(const void* text, size_t byteLength, |
|
2300 const SkScalar xpos[], SkScalar constY, |
|
2301 const SkPaint& paint) { |
|
2302 CHECK_SHADER_NOSETCONTEXT(paint); |
|
2303 |
|
2304 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) |
|
2305 |
|
2306 while (iter.next()) { |
|
2307 SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint()); |
|
2308 iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, |
|
2309 dfp.paint()); |
|
2310 } |
|
2311 |
|
2312 LOOPER_END |
|
2313 } |
|
2314 |
|
2315 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, |
|
2316 const SkPath& path, const SkMatrix* matrix, |
|
2317 const SkPaint& paint) { |
|
2318 CHECK_SHADER_NOSETCONTEXT(paint); |
|
2319 |
|
2320 LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL) |
|
2321 |
|
2322 while (iter.next()) { |
|
2323 iter.fDevice->drawTextOnPath(iter, text, byteLength, path, |
|
2324 matrix, looper.paint()); |
|
2325 } |
|
2326 |
|
2327 LOOPER_END |
|
2328 } |
|
2329 |
|
2330 void SkCanvas::drawVertices(VertexMode vmode, int vertexCount, |
|
2331 const SkPoint verts[], const SkPoint texs[], |
|
2332 const SkColor colors[], SkXfermode* xmode, |
|
2333 const uint16_t indices[], int indexCount, |
|
2334 const SkPaint& paint) { |
|
2335 CHECK_SHADER_NOSETCONTEXT(paint); |
|
2336 |
|
2337 LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL) |
|
2338 |
|
2339 while (iter.next()) { |
|
2340 iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs, |
|
2341 colors, xmode, indices, indexCount, |
|
2342 looper.paint()); |
|
2343 } |
|
2344 |
|
2345 LOOPER_END |
|
2346 } |
|
2347 |
|
2348 ////////////////////////////////////////////////////////////////////////////// |
|
2349 // These methods are NOT virtual, and therefore must call back into virtual |
|
2350 // methods, rather than actually drawing themselves. |
|
2351 ////////////////////////////////////////////////////////////////////////////// |
|
2352 |
|
2353 void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, |
|
2354 SkXfermode::Mode mode) { |
|
2355 SkPaint paint; |
|
2356 |
|
2357 paint.setARGB(a, r, g, b); |
|
2358 if (SkXfermode::kSrcOver_Mode != mode) { |
|
2359 paint.setXfermodeMode(mode); |
|
2360 } |
|
2361 this->drawPaint(paint); |
|
2362 } |
|
2363 |
|
2364 void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { |
|
2365 SkPaint paint; |
|
2366 |
|
2367 paint.setColor(c); |
|
2368 if (SkXfermode::kSrcOver_Mode != mode) { |
|
2369 paint.setXfermodeMode(mode); |
|
2370 } |
|
2371 this->drawPaint(paint); |
|
2372 } |
|
2373 |
|
2374 void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) { |
|
2375 SkPoint pt; |
|
2376 |
|
2377 pt.set(x, y); |
|
2378 this->drawPoints(kPoints_PointMode, 1, &pt, paint); |
|
2379 } |
|
2380 |
|
2381 void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) { |
|
2382 SkPoint pt; |
|
2383 SkPaint paint; |
|
2384 |
|
2385 pt.set(x, y); |
|
2386 paint.setColor(color); |
|
2387 this->drawPoints(kPoints_PointMode, 1, &pt, paint); |
|
2388 } |
|
2389 |
|
2390 void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, |
|
2391 const SkPaint& paint) { |
|
2392 SkPoint pts[2]; |
|
2393 |
|
2394 pts[0].set(x0, y0); |
|
2395 pts[1].set(x1, y1); |
|
2396 this->drawPoints(kLines_PointMode, 2, pts, paint); |
|
2397 } |
|
2398 |
|
2399 void SkCanvas::drawRectCoords(SkScalar left, SkScalar top, |
|
2400 SkScalar right, SkScalar bottom, |
|
2401 const SkPaint& paint) { |
|
2402 SkRect r; |
|
2403 |
|
2404 r.set(left, top, right, bottom); |
|
2405 this->drawRect(r, paint); |
|
2406 } |
|
2407 |
|
2408 void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, |
|
2409 const SkPaint& paint) { |
|
2410 if (radius < 0) { |
|
2411 radius = 0; |
|
2412 } |
|
2413 |
|
2414 SkRect r; |
|
2415 r.set(cx - radius, cy - radius, cx + radius, cy + radius); |
|
2416 this->drawOval(r, paint); |
|
2417 } |
|
2418 |
|
2419 void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, |
|
2420 const SkPaint& paint) { |
|
2421 if (rx > 0 && ry > 0) { |
|
2422 if (paint.canComputeFastBounds()) { |
|
2423 SkRect storage; |
|
2424 if (this->quickReject(paint.computeFastBounds(r, &storage))) { |
|
2425 return; |
|
2426 } |
|
2427 } |
|
2428 SkRRect rrect; |
|
2429 rrect.setRectXY(r, rx, ry); |
|
2430 this->drawRRect(rrect, paint); |
|
2431 } else { |
|
2432 this->drawRect(r, paint); |
|
2433 } |
|
2434 } |
|
2435 |
|
2436 void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, |
|
2437 SkScalar sweepAngle, bool useCenter, |
|
2438 const SkPaint& paint) { |
|
2439 if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { |
|
2440 this->drawOval(oval, paint); |
|
2441 } else { |
|
2442 SkPath path; |
|
2443 if (useCenter) { |
|
2444 path.moveTo(oval.centerX(), oval.centerY()); |
|
2445 } |
|
2446 path.arcTo(oval, startAngle, sweepAngle, !useCenter); |
|
2447 if (useCenter) { |
|
2448 path.close(); |
|
2449 } |
|
2450 this->drawPath(path, paint); |
|
2451 } |
|
2452 } |
|
2453 |
|
2454 void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, |
|
2455 const SkPath& path, SkScalar hOffset, |
|
2456 SkScalar vOffset, const SkPaint& paint) { |
|
2457 SkMatrix matrix; |
|
2458 |
|
2459 matrix.setTranslate(hOffset, vOffset); |
|
2460 this->drawTextOnPath(text, byteLength, path, &matrix, paint); |
|
2461 } |
|
2462 |
|
2463 /////////////////////////////////////////////////////////////////////////////// |
|
2464 void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) { |
|
2465 SkBaseDevice* device = this->getDevice(); |
|
2466 if (NULL != device) { |
|
2467 device->EXPERIMENTAL_optimize(picture); |
|
2468 } |
|
2469 } |
|
2470 |
|
2471 void SkCanvas::drawPicture(SkPicture& picture) { |
|
2472 SkBaseDevice* device = this->getTopDevice(); |
|
2473 if (NULL != device) { |
|
2474 // Canvas has to first give the device the opportunity to render |
|
2475 // the picture itself. |
|
2476 if (device->EXPERIMENTAL_drawPicture(picture)) { |
|
2477 return; // the device has rendered the entire picture |
|
2478 } |
|
2479 } |
|
2480 |
|
2481 picture.draw(this); |
|
2482 } |
|
2483 |
|
2484 /////////////////////////////////////////////////////////////////////////////// |
|
2485 /////////////////////////////////////////////////////////////////////////////// |
|
2486 |
|
2487 SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { |
|
2488 SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small); |
|
2489 |
|
2490 SkASSERT(canvas); |
|
2491 |
|
2492 fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); |
|
2493 fDone = !fImpl->next(); |
|
2494 } |
|
2495 |
|
2496 SkCanvas::LayerIter::~LayerIter() { |
|
2497 fImpl->~SkDrawIter(); |
|
2498 } |
|
2499 |
|
2500 void SkCanvas::LayerIter::next() { |
|
2501 fDone = !fImpl->next(); |
|
2502 } |
|
2503 |
|
2504 SkBaseDevice* SkCanvas::LayerIter::device() const { |
|
2505 return fImpl->getDevice(); |
|
2506 } |
|
2507 |
|
2508 const SkMatrix& SkCanvas::LayerIter::matrix() const { |
|
2509 return fImpl->getMatrix(); |
|
2510 } |
|
2511 |
|
2512 const SkPaint& SkCanvas::LayerIter::paint() const { |
|
2513 const SkPaint* paint = fImpl->getPaint(); |
|
2514 if (NULL == paint) { |
|
2515 paint = &fDefaultPaint; |
|
2516 } |
|
2517 return *paint; |
|
2518 } |
|
2519 |
|
2520 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } |
|
2521 int SkCanvas::LayerIter::x() const { return fImpl->getX(); } |
|
2522 int SkCanvas::LayerIter::y() const { return fImpl->getY(); } |
|
2523 |
|
2524 /////////////////////////////////////////////////////////////////////////////// |
|
2525 |
|
2526 SkCanvas::ClipVisitor::~ClipVisitor() { } |
|
2527 |
|
2528 /////////////////////////////////////////////////////////////////////////////// |
|
2529 |
|
2530 static bool supported_for_raster_canvas(const SkImageInfo& info) { |
|
2531 switch (info.alphaType()) { |
|
2532 case kPremul_SkAlphaType: |
|
2533 case kOpaque_SkAlphaType: |
|
2534 break; |
|
2535 default: |
|
2536 return false; |
|
2537 } |
|
2538 |
|
2539 switch (info.colorType()) { |
|
2540 case kAlpha_8_SkColorType: |
|
2541 case kRGB_565_SkColorType: |
|
2542 case kPMColor_SkColorType: |
|
2543 break; |
|
2544 default: |
|
2545 return false; |
|
2546 } |
|
2547 |
|
2548 return true; |
|
2549 } |
|
2550 |
|
2551 SkCanvas* SkCanvas::NewRaster(const SkImageInfo& info) { |
|
2552 if (!supported_for_raster_canvas(info)) { |
|
2553 return NULL; |
|
2554 } |
|
2555 |
|
2556 SkBitmap bitmap; |
|
2557 if (!bitmap.allocPixels(info)) { |
|
2558 return NULL; |
|
2559 } |
|
2560 |
|
2561 // should this functionality be moved into allocPixels()? |
|
2562 if (!bitmap.info().isOpaque()) { |
|
2563 bitmap.eraseColor(0); |
|
2564 } |
|
2565 return SkNEW_ARGS(SkCanvas, (bitmap)); |
|
2566 } |
|
2567 |
|
2568 SkCanvas* SkCanvas::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes) { |
|
2569 if (!supported_for_raster_canvas(info)) { |
|
2570 return NULL; |
|
2571 } |
|
2572 |
|
2573 SkBitmap bitmap; |
|
2574 if (!bitmap.installPixels(info, pixels, rowBytes)) { |
|
2575 return NULL; |
|
2576 } |
|
2577 |
|
2578 // should this functionality be moved into allocPixels()? |
|
2579 if (!bitmap.info().isOpaque()) { |
|
2580 bitmap.eraseColor(0); |
|
2581 } |
|
2582 return SkNEW_ARGS(SkCanvas, (bitmap)); |
|
2583 } |