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 "SkBounder.h"
12 : #include "SkDevice.h"
13 : #include "SkDraw.h"
14 : #include "SkDrawFilter.h"
15 : #include "SkDrawLooper.h"
16 : #include "SkPicture.h"
17 : #include "SkRasterClip.h"
18 : #include "SkScalarCompare.h"
19 : #include "SkTemplates.h"
20 : #include "SkTextFormatParams.h"
21 : #include "SkTLazy.h"
22 : #include "SkUtils.h"
23 :
24 : //#define SK_TRACE_SAVERESTORE
25 :
26 : #ifdef SK_TRACE_SAVERESTORE
27 : static int gLayerCounter;
28 : static void inc_layer() { ++gLayerCounter; printf("----- inc layer %d\n", gLayerCounter); }
29 : static void dec_layer() { --gLayerCounter; printf("----- dec layer %d\n", gLayerCounter); }
30 :
31 : static int gRecCounter;
32 : static void inc_rec() { ++gRecCounter; printf("----- inc rec %d\n", gRecCounter); }
33 : static void dec_rec() { --gRecCounter; printf("----- dec rec %d\n", gRecCounter); }
34 :
35 : static int gCanvasCounter;
36 : static void inc_canvas() { ++gCanvasCounter; printf("----- inc canvas %d\n", gCanvasCounter); }
37 : static void dec_canvas() { --gCanvasCounter; printf("----- dec canvas %d\n", gCanvasCounter); }
38 : #else
39 : #define inc_layer()
40 : #define dec_layer()
41 : #define inc_rec()
42 : #define dec_rec()
43 : #define inc_canvas()
44 : #define dec_canvas()
45 : #endif
46 :
47 : typedef SkTLazy<SkPaint> SkLazyPaint;
48 :
49 : ///////////////////////////////////////////////////////////////////////////////
50 : // Helpers for computing fast bounds for quickReject tests
51 :
52 0 : static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
53 0 : return paint != NULL && paint->isAntiAlias() ?
54 0 : SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType;
55 : }
56 :
57 : ///////////////////////////////////////////////////////////////////////////////
58 :
59 : /* This is the record we keep for each SkDevice that the user installs.
60 : The clip/matrix/proc are fields that reflect the top of the save/restore
61 : stack. Whenever the canvas changes, it marks a dirty flag, and then before
62 : these are used (assuming we're not on a layer) we rebuild these cache
63 : values: they reflect the top of the save stack, but translated and clipped
64 : by the device's XY offset and bitmap-bounds.
65 : */
66 : struct DeviceCM {
67 : DeviceCM* fNext;
68 : SkDevice* fDevice;
69 : SkRasterClip fClip;
70 : const SkMatrix* fMatrix;
71 : SkPaint* fPaint; // may be null (in the future)
72 : // optional, related to canvas' external matrix
73 : const SkMatrix* fMVMatrix;
74 : const SkMatrix* fExtMatrix;
75 :
76 0 : DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
77 0 : : fNext(NULL) {
78 0 : if (NULL != device) {
79 0 : device->ref();
80 0 : device->lockPixels();
81 : }
82 0 : fDevice = device;
83 0 : fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
84 0 : }
85 :
86 0 : ~DeviceCM() {
87 0 : if (NULL != fDevice) {
88 0 : fDevice->unlockPixels();
89 0 : fDevice->unref();
90 : }
91 0 : SkDELETE(fPaint);
92 0 : }
93 :
94 0 : void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
95 : const SkClipStack& clipStack, SkRasterClip* updateClip) {
96 0 : int x = fDevice->getOrigin().x();
97 0 : int y = fDevice->getOrigin().y();
98 0 : int width = fDevice->width();
99 0 : int height = fDevice->height();
100 :
101 0 : if ((x | y) == 0) {
102 0 : fMatrix = &totalMatrix;
103 0 : fClip = totalClip;
104 : } else {
105 0 : fMatrixStorage = totalMatrix;
106 : fMatrixStorage.postTranslate(SkIntToScalar(-x),
107 0 : SkIntToScalar(-y));
108 0 : fMatrix = &fMatrixStorage;
109 :
110 0 : totalClip.translate(-x, -y, &fClip);
111 : }
112 :
113 0 : fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
114 :
115 : // intersect clip, but don't translate it (yet)
116 :
117 0 : if (updateClip) {
118 : updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
119 0 : SkRegion::kDifference_Op);
120 : }
121 :
122 0 : fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
123 :
124 : #ifdef SK_DEBUG
125 0 : if (!fClip.isEmpty()) {
126 : SkIRect deviceR;
127 0 : deviceR.set(0, 0, width, height);
128 0 : SkASSERT(deviceR.contains(fClip.getBounds()));
129 : }
130 : #endif
131 : // default is to assume no external matrix
132 0 : fMVMatrix = NULL;
133 0 : fExtMatrix = NULL;
134 0 : }
135 :
136 : // can only be called after calling updateMC()
137 0 : void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) {
138 0 : fMVMatrixStorage.setConcat(extI, *fMatrix);
139 0 : fMVMatrix = &fMVMatrixStorage;
140 0 : fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas)
141 0 : }
142 :
143 : private:
144 : SkMatrix fMatrixStorage, fMVMatrixStorage;
145 : };
146 :
147 : /* This is the record we keep for each save/restore level in the stack.
148 : Since a level optionally copies the matrix and/or stack, we have pointers
149 : for these fields. If the value is copied for this level, the copy is
150 : stored in the ...Storage field, and the pointer points to that. If the
151 : value is not copied for this level, we ignore ...Storage, and just point
152 : at the corresponding value in the previous level in the stack.
153 : */
154 : class SkCanvas::MCRec {
155 : public:
156 : MCRec* fNext;
157 : SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec
158 : SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec
159 : SkDrawFilter* fFilter; // the current filter (or null)
160 :
161 : DeviceCM* fLayer;
162 : /* If there are any layers in the stack, this points to the top-most
163 : one that is at or below this level in the stack (so we know what
164 : bitmap/device to draw into from this level. This value is NOT
165 : reference counted, since the real owner is either our fLayer field,
166 : or a previous one in a lower level.)
167 : */
168 : DeviceCM* fTopLayer;
169 :
170 0 : MCRec(const MCRec* prev, int flags) {
171 0 : if (NULL != prev) {
172 0 : if (flags & SkCanvas::kMatrix_SaveFlag) {
173 0 : fMatrixStorage = *prev->fMatrix;
174 0 : fMatrix = &fMatrixStorage;
175 : } else {
176 0 : fMatrix = prev->fMatrix;
177 : }
178 :
179 0 : if (flags & SkCanvas::kClip_SaveFlag) {
180 0 : fRasterClipStorage = *prev->fRasterClip;
181 0 : fRasterClip = &fRasterClipStorage;
182 : } else {
183 0 : fRasterClip = prev->fRasterClip;
184 : }
185 :
186 0 : fFilter = prev->fFilter;
187 0 : SkSafeRef(fFilter);
188 :
189 0 : fTopLayer = prev->fTopLayer;
190 : } else { // no prev
191 0 : fMatrixStorage.reset();
192 :
193 0 : fMatrix = &fMatrixStorage;
194 0 : fRasterClip = &fRasterClipStorage;
195 0 : fFilter = NULL;
196 0 : fTopLayer = NULL;
197 : }
198 0 : fLayer = NULL;
199 :
200 : // don't bother initializing fNext
201 : inc_rec();
202 0 : }
203 0 : ~MCRec() {
204 0 : SkSafeUnref(fFilter);
205 0 : SkDELETE(fLayer);
206 : dec_rec();
207 0 : }
208 :
209 : private:
210 : SkMatrix fMatrixStorage;
211 : SkRasterClip fRasterClipStorage;
212 : };
213 :
214 0 : class SkDrawIter : public SkDraw {
215 : public:
216 0 : SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
217 0 : fCanvas = canvas;
218 0 : canvas->updateDeviceCMCache();
219 :
220 0 : fClipStack = &canvas->getTotalClipStack();
221 0 : fBounder = canvas->getBounder();
222 0 : fCurrLayer = canvas->fMCRec->fTopLayer;
223 0 : fSkipEmptyClips = skipEmptyClips;
224 0 : }
225 :
226 0 : bool next() {
227 : // skip over recs with empty clips
228 0 : if (fSkipEmptyClips) {
229 0 : while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
230 0 : fCurrLayer = fCurrLayer->fNext;
231 : }
232 : }
233 :
234 0 : if (NULL != fCurrLayer) {
235 0 : const DeviceCM* rec = fCurrLayer;
236 :
237 0 : fMatrix = rec->fMatrix;
238 0 : fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
239 0 : fRC = &rec->fClip;
240 0 : fDevice = rec->fDevice;
241 0 : fBitmap = &fDevice->accessBitmap(true);
242 0 : fPaint = rec->fPaint;
243 0 : fMVMatrix = rec->fMVMatrix;
244 0 : fExtMatrix = rec->fExtMatrix;
245 0 : SkDEBUGCODE(this->validate();)
246 :
247 0 : fCurrLayer = rec->fNext;
248 0 : if (fBounder) {
249 0 : fBounder->setClip(fClip);
250 : }
251 : // fCurrLayer may be NULL now
252 :
253 0 : fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip, *fClipStack);
254 0 : return true;
255 : }
256 0 : return false;
257 : }
258 :
259 0 : SkDevice* getDevice() const { return fDevice; }
260 0 : int getX() const { return fDevice->getOrigin().x(); }
261 0 : int getY() const { return fDevice->getOrigin().y(); }
262 0 : const SkMatrix& getMatrix() const { return *fMatrix; }
263 0 : const SkRegion& getClip() const { return *fClip; }
264 0 : const SkPaint* getPaint() const { return fPaint; }
265 :
266 : private:
267 : SkCanvas* fCanvas;
268 : const DeviceCM* fCurrLayer;
269 : const SkPaint* fPaint; // May be null.
270 : SkBool8 fSkipEmptyClips;
271 :
272 : typedef SkDraw INHERITED;
273 : };
274 :
275 : /////////////////////////////////////////////////////////////////////////////
276 :
277 : class AutoDrawLooper {
278 : public:
279 0 : AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) {
280 0 : fCanvas = canvas;
281 0 : fLooper = paint.getLooper();
282 0 : fFilter = canvas->getDrawFilter();
283 0 : fPaint = NULL;
284 0 : fSaveCount = canvas->getSaveCount();
285 0 : fDone = false;
286 :
287 0 : if (fLooper) {
288 0 : fLooper->init(canvas);
289 : }
290 0 : }
291 :
292 0 : ~AutoDrawLooper() {
293 0 : SkASSERT(fCanvas->getSaveCount() == fSaveCount);
294 0 : }
295 :
296 0 : const SkPaint& paint() const {
297 0 : SkASSERT(fPaint);
298 0 : return *fPaint;
299 : }
300 :
301 : bool next(SkDrawFilter::Type drawType);
302 :
303 : private:
304 : SkLazyPaint fLazyPaint;
305 : SkCanvas* fCanvas;
306 : const SkPaint& fOrigPaint;
307 : SkDrawLooper* fLooper;
308 : SkDrawFilter* fFilter;
309 : const SkPaint* fPaint;
310 : int fSaveCount;
311 : bool fDone;
312 : };
313 :
314 0 : bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
315 0 : fPaint = NULL;
316 0 : if (fDone) {
317 0 : return false;
318 : }
319 :
320 0 : if (fLooper || fFilter) {
321 0 : SkPaint* paint = fLazyPaint.set(fOrigPaint);
322 0 : if (fLooper && !fLooper->next(fCanvas, paint)) {
323 0 : fDone = true;
324 0 : return false;
325 : }
326 0 : if (fFilter) {
327 0 : fFilter->filter(paint, drawType);
328 0 : if (NULL == fLooper) {
329 : // no looper means we only draw once
330 0 : fDone = true;
331 : }
332 : }
333 0 : fPaint = paint;
334 : } else {
335 0 : fDone = true;
336 0 : fPaint = &fOrigPaint;
337 : }
338 :
339 : // call this after any possible paint modifiers
340 0 : if (fPaint->nothingToDraw()) {
341 0 : fPaint = NULL;
342 0 : return false;
343 : }
344 0 : return true;
345 : }
346 :
347 : /* Stack helper for managing a SkBounder. In the destructor, if we were
348 : given a bounder, we call its commit() method, signifying that we are
349 : done accumulating bounds for that draw.
350 : */
351 : class SkAutoBounderCommit {
352 : public:
353 0 : SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
354 0 : ~SkAutoBounderCommit() {
355 0 : if (NULL != fBounder) {
356 0 : fBounder->commit();
357 : }
358 0 : }
359 : private:
360 : SkBounder* fBounder;
361 : };
362 :
363 : #include "SkColorPriv.h"
364 :
365 : class AutoValidator {
366 : public:
367 : AutoValidator(SkDevice* device) : fDevice(device) {}
368 : ~AutoValidator() {
369 : #ifdef SK_DEBUG
370 : const SkBitmap& bm = fDevice->accessBitmap(false);
371 : if (bm.config() == SkBitmap::kARGB_4444_Config) {
372 : for (int y = 0; y < bm.height(); y++) {
373 : const SkPMColor16* p = bm.getAddr16(0, y);
374 : for (int x = 0; x < bm.width(); x++) {
375 : SkPMColor16 c = p[x];
376 : SkPMColor16Assert(c);
377 : }
378 : }
379 : }
380 : #endif
381 : }
382 : private:
383 : SkDevice* fDevice;
384 : };
385 :
386 : ////////// macros to place around the internal draw calls //////////////////
387 :
388 : #define LOOPER_BEGIN(paint, type) \
389 : /* AutoValidator validator(fMCRec->fTopLayer->fDevice); */ \
390 : AutoDrawLooper looper(this, paint); \
391 : while (looper.next(type)) { \
392 : SkAutoBounderCommit ac(fBounder); \
393 : SkDrawIter iter(this);
394 :
395 : #define LOOPER_END }
396 :
397 : ////////////////////////////////////////////////////////////////////////////
398 :
399 0 : SkDevice* SkCanvas::init(SkDevice* device) {
400 0 : fBounder = NULL;
401 0 : fLocalBoundsCompareType.setEmpty();
402 0 : fLocalBoundsCompareTypeDirty = true;
403 0 : fLocalBoundsCompareTypeBW.setEmpty();
404 0 : fLocalBoundsCompareTypeDirtyBW = true;
405 0 : fLastDeviceToGainFocus = NULL;
406 0 : fDeviceCMDirty = false;
407 0 : fLayerCount = 0;
408 :
409 0 : fMCRec = (MCRec*)fMCStack.push_back();
410 0 : new (fMCRec) MCRec(NULL, 0);
411 :
412 0 : fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL));
413 0 : fMCRec->fTopLayer = fMCRec->fLayer;
414 0 : fMCRec->fNext = NULL;
415 :
416 0 : fExternalMatrix.reset();
417 0 : fExternalInverse.reset();
418 0 : fUseExternalMatrix = false;
419 :
420 0 : return this->setDevice(device);
421 : }
422 :
423 0 : SkCanvas::SkCanvas()
424 0 : : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
425 : inc_canvas();
426 :
427 0 : this->init(NULL);
428 0 : }
429 :
430 0 : SkCanvas::SkCanvas(SkDevice* device)
431 0 : : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
432 : inc_canvas();
433 :
434 0 : this->init(device);
435 0 : }
436 :
437 0 : SkCanvas::SkCanvas(const SkBitmap& bitmap)
438 0 : : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
439 : inc_canvas();
440 :
441 0 : this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
442 0 : }
443 :
444 0 : SkCanvas::~SkCanvas() {
445 : // free up the contents of our deque
446 0 : this->restoreToCount(1); // restore everything but the last
447 0 : SkASSERT(0 == fLayerCount);
448 :
449 0 : this->internalRestore(); // restore the last, since we're going away
450 :
451 0 : SkSafeUnref(fBounder);
452 :
453 : dec_canvas();
454 0 : }
455 :
456 0 : SkBounder* SkCanvas::setBounder(SkBounder* bounder) {
457 0 : SkRefCnt_SafeAssign(fBounder, bounder);
458 0 : return bounder;
459 : }
460 :
461 0 : SkDrawFilter* SkCanvas::getDrawFilter() const {
462 0 : return fMCRec->fFilter;
463 : }
464 :
465 0 : SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
466 0 : SkRefCnt_SafeAssign(fMCRec->fFilter, filter);
467 0 : return filter;
468 : }
469 :
470 : ///////////////////////////////////////////////////////////////////////////////
471 :
472 0 : SkISize SkCanvas::getDeviceSize() const {
473 0 : SkDevice* d = this->getDevice();
474 0 : return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
475 : }
476 :
477 0 : SkDevice* SkCanvas::getDevice() const {
478 : // return root device
479 0 : SkDeque::F2BIter iter(fMCStack);
480 0 : MCRec* rec = (MCRec*)iter.next();
481 0 : SkASSERT(rec && rec->fLayer);
482 0 : return rec->fLayer->fDevice;
483 : }
484 :
485 0 : SkDevice* SkCanvas::getTopDevice() const {
486 0 : return fMCRec->fTopLayer->fDevice;
487 : }
488 :
489 0 : SkDevice* SkCanvas::setDevice(SkDevice* device) {
490 : // return root device
491 0 : SkDeque::F2BIter iter(fMCStack);
492 0 : MCRec* rec = (MCRec*)iter.next();
493 0 : SkASSERT(rec && rec->fLayer);
494 0 : SkDevice* rootDevice = rec->fLayer->fDevice;
495 :
496 0 : if (rootDevice == device) {
497 0 : return device;
498 : }
499 :
500 : /* Notify the devices that they are going in/out of scope, so they can do
501 : things like lock/unlock their pixels, etc.
502 : */
503 0 : if (device) {
504 0 : device->lockPixels();
505 : }
506 0 : if (rootDevice) {
507 0 : rootDevice->unlockPixels();
508 : }
509 :
510 0 : SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
511 0 : rootDevice = device;
512 :
513 0 : fDeviceCMDirty = true;
514 :
515 : /* Now we update our initial region to have the bounds of the new device,
516 : and then intersect all of the clips in our stack with these bounds,
517 : to ensure that we can't draw outside of the device's bounds (and trash
518 : memory).
519 :
520 : NOTE: this is only a partial-fix, since if the new device is larger than
521 : the previous one, we don't know how to "enlarge" the clips in our stack,
522 : so drawing may be artificially restricted. Without keeping a history of
523 : all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
524 : reconstruct the correct clips, so this approximation will have to do.
525 : The caller really needs to restore() back to the base if they want to
526 : accurately take advantage of the new device bounds.
527 : */
528 :
529 0 : if (NULL == device) {
530 0 : rec->fRasterClip->setEmpty();
531 0 : while ((rec = (MCRec*)iter.next()) != NULL) {
532 0 : (void)rec->fRasterClip->setEmpty();
533 : }
534 0 : fClipStack.reset();
535 : } else {
536 : // compute our total bounds for all devices
537 : SkIRect bounds;
538 :
539 0 : bounds.set(0, 0, device->width(), device->height());
540 :
541 : // now jam our 1st clip to be bounds, and intersect the rest with that
542 0 : rec->fRasterClip->setRect(bounds);
543 0 : while ((rec = (MCRec*)iter.next()) != NULL) {
544 0 : (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
545 : }
546 : }
547 0 : return device;
548 : }
549 :
550 0 : SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
551 0 : SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
552 0 : device->unref();
553 0 : return device;
554 : }
555 :
556 0 : bool SkCanvas::readPixels(SkBitmap* bitmap,
557 : int x, int y,
558 : Config8888 config8888) {
559 0 : SkDevice* device = this->getDevice();
560 0 : if (!device) {
561 0 : return false;
562 : }
563 0 : return device->readPixels(bitmap, x, y, config8888);
564 : }
565 :
566 0 : bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
567 0 : SkDevice* device = this->getDevice();
568 :
569 : SkIRect bounds;
570 0 : bounds.set(0, 0, device->width(), device->height());
571 0 : if (!bounds.intersect(srcRect)) {
572 0 : return false;
573 : }
574 :
575 0 : SkBitmap tmp;
576 : tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
577 0 : bounds.height());
578 0 : if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
579 0 : bitmap->swap(tmp);
580 0 : return true;
581 : } else {
582 0 : return false;
583 : }
584 : }
585 :
586 0 : void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
587 : Config8888 config8888) {
588 0 : SkDevice* device = this->getDevice();
589 0 : if (device) {
590 0 : device->writePixels(bitmap, x, y, config8888);
591 : }
592 0 : }
593 :
594 : //////////////////////////////////////////////////////////////////////////////
595 :
596 0 : void SkCanvas::updateDeviceCMCache() {
597 0 : if (fDeviceCMDirty) {
598 0 : const SkMatrix& totalMatrix = this->getTotalMatrix();
599 0 : const SkRasterClip& totalClip = *fMCRec->fRasterClip;
600 0 : DeviceCM* layer = fMCRec->fTopLayer;
601 :
602 0 : if (NULL == layer->fNext) { // only one layer
603 0 : layer->updateMC(totalMatrix, totalClip, fClipStack, NULL);
604 0 : if (fUseExternalMatrix) {
605 : layer->updateExternalMatrix(fExternalMatrix,
606 0 : fExternalInverse);
607 : }
608 : } else {
609 0 : SkRasterClip clip(totalClip);
610 0 : do {
611 0 : layer->updateMC(totalMatrix, clip, fClipStack, &clip);
612 0 : if (fUseExternalMatrix) {
613 : layer->updateExternalMatrix(fExternalMatrix,
614 0 : fExternalInverse);
615 : }
616 : } while ((layer = layer->fNext) != NULL);
617 : }
618 0 : fDeviceCMDirty = false;
619 : }
620 0 : }
621 :
622 0 : void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
623 : const SkRegion& clip,
624 : const SkClipStack& clipStack) {
625 0 : SkASSERT(device);
626 0 : if (fLastDeviceToGainFocus != device) {
627 0 : device->gainFocus(this, matrix, clip, clipStack);
628 0 : fLastDeviceToGainFocus = device;
629 : }
630 0 : }
631 :
632 : ///////////////////////////////////////////////////////////////////////////////
633 :
634 0 : int SkCanvas::internalSave(SaveFlags flags) {
635 0 : int saveCount = this->getSaveCount(); // record this before the actual save
636 :
637 0 : MCRec* newTop = (MCRec*)fMCStack.push_back();
638 0 : new (newTop) MCRec(fMCRec, flags); // balanced in restore()
639 :
640 0 : newTop->fNext = fMCRec;
641 0 : fMCRec = newTop;
642 :
643 0 : fClipStack.save();
644 0 : SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
645 :
646 0 : return saveCount;
647 : }
648 :
649 0 : int SkCanvas::save(SaveFlags flags) {
650 : // call shared impl
651 0 : return this->internalSave(flags);
652 : }
653 :
654 : #define C32MASK (1 << SkBitmap::kARGB_8888_Config)
655 : #define C16MASK (1 << SkBitmap::kRGB_565_Config)
656 : #define C8MASK (1 << SkBitmap::kA8_Config)
657 :
658 0 : static SkBitmap::Config resolve_config(SkCanvas* canvas,
659 : const SkIRect& bounds,
660 : SkCanvas::SaveFlags flags,
661 : bool* isOpaque) {
662 0 : *isOpaque = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) == 0;
663 :
664 : #if 0
665 : // loop through and union all the configs we may draw into
666 : uint32_t configMask = 0;
667 : for (int i = canvas->countLayerDevices() - 1; i >= 0; --i)
668 : {
669 : SkDevice* device = canvas->getLayerDevice(i);
670 : if (device->intersects(bounds))
671 : configMask |= 1 << device->config();
672 : }
673 :
674 : // if the caller wants alpha or fullcolor, we can't return 565
675 : if (flags & (SkCanvas::kFullColorLayer_SaveFlag |
676 : SkCanvas::kHasAlphaLayer_SaveFlag))
677 : configMask &= ~C16MASK;
678 :
679 : switch (configMask) {
680 : case C8MASK: // if we only have A8, return that
681 : return SkBitmap::kA8_Config;
682 :
683 : case C16MASK: // if we only have 565, return that
684 : return SkBitmap::kRGB_565_Config;
685 :
686 : default:
687 : return SkBitmap::kARGB_8888_Config; // default answer
688 : }
689 : #else
690 0 : return SkBitmap::kARGB_8888_Config; // default answer
691 : #endif
692 : }
693 :
694 0 : static bool bounds_affects_clip(SkCanvas::SaveFlags flags) {
695 0 : return (flags & SkCanvas::kClipToLayer_SaveFlag) != 0;
696 : }
697 :
698 0 : int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
699 : SaveFlags flags) {
700 : // do this before we create the layer. We don't call the public save() since
701 : // that would invoke a possibly overridden virtual
702 0 : int count = this->internalSave(flags);
703 :
704 0 : fDeviceCMDirty = true;
705 :
706 : SkIRect clipBounds;
707 0 : if (!this->getClipDeviceBounds(&clipBounds)) {
708 0 : return count;
709 : }
710 :
711 : SkIRect ir;
712 0 : if (NULL != bounds) {
713 : SkRect r;
714 :
715 0 : this->getTotalMatrix().mapRect(&r, *bounds);
716 0 : r.roundOut(&ir);
717 : // early exit if the layer's bounds are clipped out
718 0 : if (!ir.intersect(clipBounds)) {
719 0 : if (bounds_affects_clip(flags)) {
720 0 : fMCRec->fRasterClip->setEmpty();
721 : }
722 0 : return count;
723 : }
724 : } else { // no user bounds, so just use the clip
725 0 : ir = clipBounds;
726 : }
727 :
728 0 : fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
729 : // early exit if the clip is now empty
730 0 : if (bounds_affects_clip(flags) &&
731 0 : !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
732 0 : return count;
733 : }
734 :
735 : bool isOpaque;
736 0 : SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
737 :
738 : SkDevice* device;
739 0 : if (paint && paint->getImageFilter()) {
740 : device = this->createCompatibleDevice(config, ir.width(), ir.height(),
741 0 : isOpaque);
742 : } else {
743 : device = this->createLayerDevice(config, ir.width(), ir.height(),
744 0 : isOpaque);
745 : }
746 0 : if (NULL == device) {
747 0 : SkDebugf("Unable to create device for layer.");
748 0 : return count;
749 : }
750 :
751 0 : device->setOrigin(ir.fLeft, ir.fTop);
752 0 : DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
753 0 : device->unref();
754 :
755 0 : layer->fNext = fMCRec->fTopLayer;
756 0 : fMCRec->fLayer = layer;
757 0 : fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
758 :
759 0 : fLayerCount += 1;
760 0 : return count;
761 : }
762 :
763 0 : int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
764 : SaveFlags flags) {
765 0 : if (0xFF == alpha) {
766 0 : return this->saveLayer(bounds, NULL, flags);
767 : } else {
768 0 : SkPaint tmpPaint;
769 0 : tmpPaint.setAlpha(alpha);
770 0 : return this->saveLayer(bounds, &tmpPaint, flags);
771 : }
772 : }
773 :
774 0 : void SkCanvas::restore() {
775 : // check for underflow
776 0 : if (fMCStack.count() > 1) {
777 0 : this->internalRestore();
778 : }
779 0 : }
780 :
781 0 : void SkCanvas::internalRestore() {
782 0 : SkASSERT(fMCStack.count() != 0);
783 :
784 0 : fDeviceCMDirty = true;
785 0 : fLocalBoundsCompareTypeDirty = true;
786 0 : fLocalBoundsCompareTypeDirtyBW = true;
787 :
788 0 : fClipStack.restore();
789 : // reserve our layer (if any)
790 0 : DeviceCM* layer = fMCRec->fLayer; // may be null
791 : // now detach it from fMCRec so we can pop(). Gets freed after its drawn
792 0 : fMCRec->fLayer = NULL;
793 :
794 : // now do the normal restore()
795 0 : fMCRec->~MCRec(); // balanced in save()
796 0 : fMCStack.pop_back();
797 0 : fMCRec = (MCRec*)fMCStack.back();
798 :
799 : /* Time to draw the layer's offscreen. We can't call the public drawSprite,
800 : since if we're being recorded, we don't want to record this (the
801 : recorder will have already recorded the restore).
802 : */
803 0 : if (NULL != layer) {
804 0 : if (layer->fNext) {
805 0 : const SkIPoint& origin = layer->fDevice->getOrigin();
806 : this->drawDevice(layer->fDevice, origin.x(), origin.y(),
807 0 : layer->fPaint);
808 : // reset this, since drawDevice will have set it to true
809 0 : fDeviceCMDirty = true;
810 :
811 0 : SkASSERT(fLayerCount > 0);
812 0 : fLayerCount -= 1;
813 : }
814 0 : SkDELETE(layer);
815 : }
816 :
817 0 : SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
818 0 : }
819 :
820 0 : int SkCanvas::getSaveCount() const {
821 0 : return fMCStack.count();
822 : }
823 :
824 0 : void SkCanvas::restoreToCount(int count) {
825 : // sanity check
826 0 : if (count < 1) {
827 0 : count = 1;
828 : }
829 :
830 0 : int n = this->getSaveCount() - count;
831 0 : for (int i = 0; i < n; ++i) {
832 0 : this->restore();
833 : }
834 0 : }
835 :
836 0 : bool SkCanvas::isDrawingToLayer() const {
837 0 : return fLayerCount > 0;
838 : }
839 :
840 : /////////////////////////////////////////////////////////////////////////////
841 :
842 : // can't draw it if its empty, or its too big for a fixed-point width or height
843 0 : static bool reject_bitmap(const SkBitmap& bitmap) {
844 0 : return bitmap.width() <= 0 || bitmap.height() <= 0
845 : #ifndef SK_ALLOW_OVER_32K_BITMAPS
846 0 : || bitmap.width() > 32767 || bitmap.height() > 32767
847 : #endif
848 : ;
849 : }
850 :
851 0 : void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
852 : const SkMatrix& matrix, const SkPaint* paint) {
853 0 : if (reject_bitmap(bitmap)) {
854 0 : return;
855 : }
856 :
857 0 : SkLazyPaint lazy;
858 0 : if (NULL == paint) {
859 0 : paint = lazy.init();
860 : }
861 0 : this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
862 : }
863 :
864 : #include "SkImageFilter.h"
865 :
866 : class DeviceImageFilterProxy : public SkImageFilter::Proxy {
867 : public:
868 0 : DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
869 :
870 : virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE;
871 : virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
872 : const SkMatrix& ctm,
873 : SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
874 :
875 : private:
876 : SkDevice* fDevice;
877 : };
878 :
879 0 : SkDevice* DeviceImageFilterProxy::createDevice(int w, int h) {
880 : return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
881 0 : w, h, false);
882 : }
883 :
884 0 : bool DeviceImageFilterProxy::filterImage(SkImageFilter* filter,
885 : const SkBitmap& src,
886 : const SkMatrix& ctm,
887 : SkBitmap* result,
888 : SkIPoint* offset) {
889 0 : return fDevice->filterImage(filter, src, ctm, result, offset);
890 : }
891 :
892 0 : void SkCanvas::drawDevice(SkDevice* device, int x, int y,
893 : const SkPaint* paint) {
894 0 : SkPaint tmp;
895 0 : if (NULL == paint) {
896 0 : tmp.setDither(true);
897 0 : paint = &tmp;
898 : }
899 :
900 0 : LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
901 0 : while (iter.next()) {
902 0 : paint = &looper.paint();
903 0 : SkImageFilter* filter = paint->getImageFilter();
904 0 : SkIPoint pos = { x - iter.getX(), y - iter.getY() };
905 0 : if (filter) {
906 0 : DeviceImageFilterProxy proxy(device);
907 0 : SkBitmap dst;
908 0 : const SkBitmap& src = device->accessBitmap(false);
909 0 : if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) {
910 0 : SkPaint tmp(*paint);
911 0 : tmp.setImageFilter(NULL);
912 0 : iter.fDevice->drawSprite(iter, dst, pos.x(), pos.y(), tmp);
913 : }
914 : } else {
915 0 : iter.fDevice->drawDevice(iter, device, pos.x(), pos.y(), *paint);
916 : }
917 : }
918 : LOOPER_END
919 0 : }
920 :
921 : /////////////////////////////////////////////////////////////////////////////
922 :
923 0 : bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
924 0 : fDeviceCMDirty = true;
925 0 : fLocalBoundsCompareTypeDirty = true;
926 0 : fLocalBoundsCompareTypeDirtyBW = true;
927 0 : return fMCRec->fMatrix->preTranslate(dx, dy);
928 : }
929 :
930 0 : bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
931 0 : fDeviceCMDirty = true;
932 0 : fLocalBoundsCompareTypeDirty = true;
933 0 : fLocalBoundsCompareTypeDirtyBW = true;
934 0 : return fMCRec->fMatrix->preScale(sx, sy);
935 : }
936 :
937 0 : bool SkCanvas::rotate(SkScalar degrees) {
938 0 : fDeviceCMDirty = true;
939 0 : fLocalBoundsCompareTypeDirty = true;
940 0 : fLocalBoundsCompareTypeDirtyBW = true;
941 0 : return fMCRec->fMatrix->preRotate(degrees);
942 : }
943 :
944 0 : bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
945 0 : fDeviceCMDirty = true;
946 0 : fLocalBoundsCompareTypeDirty = true;
947 0 : fLocalBoundsCompareTypeDirtyBW = true;
948 0 : return fMCRec->fMatrix->preSkew(sx, sy);
949 : }
950 :
951 0 : bool SkCanvas::concat(const SkMatrix& matrix) {
952 0 : fDeviceCMDirty = true;
953 0 : fLocalBoundsCompareTypeDirty = true;
954 0 : fLocalBoundsCompareTypeDirtyBW = true;
955 0 : return fMCRec->fMatrix->preConcat(matrix);
956 : }
957 :
958 0 : void SkCanvas::setMatrix(const SkMatrix& matrix) {
959 0 : fDeviceCMDirty = true;
960 0 : fLocalBoundsCompareTypeDirty = true;
961 0 : fLocalBoundsCompareTypeDirtyBW = true;
962 0 : *fMCRec->fMatrix = matrix;
963 0 : }
964 :
965 : // this is not virtual, so it must call a virtual method so that subclasses
966 : // will see its action
967 0 : void SkCanvas::resetMatrix() {
968 : SkMatrix matrix;
969 :
970 0 : matrix.reset();
971 0 : this->setMatrix(matrix);
972 0 : }
973 :
974 : //////////////////////////////////////////////////////////////////////////////
975 :
976 0 : bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
977 0 : AutoValidateClip avc(this);
978 :
979 0 : fDeviceCMDirty = true;
980 0 : fLocalBoundsCompareTypeDirty = true;
981 0 : fLocalBoundsCompareTypeDirtyBW = true;
982 :
983 0 : if (fMCRec->fMatrix->rectStaysRect()) {
984 : // for these simpler matrices, we can stay a rect ever after applying
985 : // the matrix. This means we don't have to a) make a path, and b) tell
986 : // the region code to scan-convert the path, only to discover that it
987 : // is really just a rect.
988 : SkRect r;
989 :
990 0 : fMCRec->fMatrix->mapRect(&r, rect);
991 0 : fClipStack.clipDevRect(r, op, doAA);
992 0 : return fMCRec->fRasterClip->op(r, op, doAA);
993 : } else {
994 : // since we're rotate or some such thing, we convert the rect to a path
995 : // and clip against that, since it can handle any matrix. However, to
996 : // avoid recursion in the case where we are subclassed (e.g. Pictures)
997 : // we explicitly call "our" version of clipPath.
998 0 : SkPath path;
999 :
1000 0 : path.addRect(rect);
1001 0 : return this->SkCanvas::clipPath(path, op, doAA);
1002 : }
1003 : }
1004 :
1005 0 : static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
1006 : const SkPath& devPath, SkRegion::Op op, bool doAA) {
1007 : // base is used to limit the size (and therefore memory allocation) of the
1008 : // region that results from scan converting devPath.
1009 0 : SkRegion base;
1010 :
1011 0 : if (SkRegion::kIntersect_Op == op) {
1012 : // since we are intersect, we can do better (tighter) with currRgn's
1013 : // bounds, than just using the device. However, if currRgn is complex,
1014 : // our region blitter may hork, so we do that case in two steps.
1015 0 : if (currClip->isRect()) {
1016 0 : return currClip->setPath(devPath, *currClip, doAA);
1017 : } else {
1018 0 : base.setRect(currClip->getBounds());
1019 0 : SkRasterClip clip;
1020 0 : clip.setPath(devPath, base, doAA);
1021 0 : return currClip->op(clip, op);
1022 : }
1023 : } else {
1024 0 : const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
1025 0 : base.setRect(0, 0, bm.width(), bm.height());
1026 :
1027 0 : if (SkRegion::kReplace_Op == op) {
1028 0 : return currClip->setPath(devPath, base, doAA);
1029 : } else {
1030 0 : SkRasterClip clip;
1031 0 : clip.setPath(devPath, base, doAA);
1032 0 : return currClip->op(clip, op);
1033 : }
1034 : }
1035 : }
1036 :
1037 0 : bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
1038 0 : AutoValidateClip avc(this);
1039 :
1040 0 : fDeviceCMDirty = true;
1041 0 : fLocalBoundsCompareTypeDirty = true;
1042 0 : fLocalBoundsCompareTypeDirtyBW = true;
1043 :
1044 0 : SkPath devPath;
1045 0 : path.transform(*fMCRec->fMatrix, &devPath);
1046 :
1047 : // Check if the transfomation, or the original path itself
1048 : // made us empty. Note this can also happen if we contained NaN
1049 : // values. computing the bounds detects this, and will set our
1050 : // bounds to empty if that is the case. (see SkRect::set(pts, count))
1051 0 : if (devPath.getBounds().isEmpty()) {
1052 : // resetting the path will remove any NaN or other wanky values
1053 : // that might upset our scan converter.
1054 0 : devPath.reset();
1055 : }
1056 :
1057 : // if we called path.swap() we could avoid a deep copy of this path
1058 0 : fClipStack.clipDevPath(devPath, op, doAA);
1059 :
1060 0 : return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
1061 : }
1062 :
1063 0 : bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1064 0 : AutoValidateClip avc(this);
1065 :
1066 0 : fDeviceCMDirty = true;
1067 0 : fLocalBoundsCompareTypeDirty = true;
1068 0 : fLocalBoundsCompareTypeDirtyBW = true;
1069 :
1070 : // todo: signal fClipStack that we have a region, and therefore (I guess)
1071 : // we have to ignore it, and use the region directly?
1072 0 : fClipStack.clipDevRect(rgn.getBounds());
1073 :
1074 0 : return fMCRec->fRasterClip->op(rgn, op);
1075 : }
1076 :
1077 : #ifdef SK_DEBUG
1078 0 : void SkCanvas::validateClip() const {
1079 : // construct clipRgn from the clipstack
1080 0 : const SkDevice* device = this->getDevice();
1081 : SkIRect ir;
1082 0 : ir.set(0, 0, device->width(), device->height());
1083 0 : SkRasterClip tmpClip(ir);
1084 :
1085 0 : SkClipStack::B2FIter iter(fClipStack);
1086 : const SkClipStack::B2FIter::Clip* clip;
1087 0 : while ((clip = iter.next()) != NULL) {
1088 0 : if (clip->fPath) {
1089 0 : clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
1090 0 : } else if (clip->fRect) {
1091 0 : clip->fRect->round(&ir);
1092 0 : tmpClip.op(ir, clip->fOp);
1093 : } else {
1094 0 : tmpClip.setEmpty();
1095 : }
1096 : }
1097 :
1098 : #if 0 // enable this locally for testing
1099 : // now compare against the current rgn
1100 : const SkRegion& rgn = this->getTotalClip();
1101 : SkASSERT(rgn == tmpClip);
1102 : #endif
1103 0 : }
1104 : #endif
1105 :
1106 : ///////////////////////////////////////////////////////////////////////////////
1107 :
1108 0 : void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
1109 : SkRect r;
1110 : SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
1111 0 : fLocalBoundsCompareTypeBW;
1112 :
1113 0 : if (!this->getClipBounds(&r, et)) {
1114 0 : rCompare.setEmpty();
1115 : } else {
1116 : rCompare.set(SkScalarToCompareType(r.fLeft),
1117 : SkScalarToCompareType(r.fTop),
1118 : SkScalarToCompareType(r.fRight),
1119 0 : SkScalarToCompareType(r.fBottom));
1120 : }
1121 0 : }
1122 :
1123 : /* current impl ignores edgetype, and relies on
1124 : getLocalClipBoundsCompareType(), which always returns a value assuming
1125 : antialiasing (worst case)
1126 : */
1127 0 : bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
1128 :
1129 0 : if (!rect.isFinite())
1130 0 : return true;
1131 :
1132 0 : if (fMCRec->fRasterClip->isEmpty()) {
1133 0 : return true;
1134 : }
1135 :
1136 0 : if (fMCRec->fMatrix->hasPerspective()) {
1137 : SkRect dst;
1138 0 : fMCRec->fMatrix->mapRect(&dst, rect);
1139 : SkIRect idst;
1140 0 : dst.roundOut(&idst);
1141 0 : return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
1142 : } else {
1143 0 : const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
1144 :
1145 : // for speed, do the most likely reject compares first
1146 0 : SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
1147 0 : SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
1148 0 : if (userT >= clipR.fBottom || userB <= clipR.fTop) {
1149 0 : return true;
1150 : }
1151 0 : SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
1152 0 : SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
1153 0 : if (userL >= clipR.fRight || userR <= clipR.fLeft) {
1154 0 : return true;
1155 : }
1156 0 : return false;
1157 : }
1158 : }
1159 :
1160 0 : bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
1161 0 : return path.isEmpty() || this->quickReject(path.getBounds(), et);
1162 : }
1163 :
1164 0 : bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
1165 : /* current impl ignores edgetype, and relies on
1166 : getLocalClipBoundsCompareType(), which always returns a value assuming
1167 : antialiasing (worst case)
1168 : */
1169 :
1170 0 : if (fMCRec->fRasterClip->isEmpty()) {
1171 0 : return true;
1172 : }
1173 :
1174 0 : SkScalarCompareType userT = SkScalarToCompareType(top);
1175 0 : SkScalarCompareType userB = SkScalarToCompareType(bottom);
1176 :
1177 : // check for invalid user Y coordinates (i.e. empty)
1178 : // reed: why do we need to do this check, since it slows us down?
1179 0 : if (userT >= userB) {
1180 0 : return true;
1181 : }
1182 :
1183 : // check if we are above or below the local clip bounds
1184 0 : const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
1185 0 : return userT >= clipR.fBottom || userB <= clipR.fTop;
1186 : }
1187 :
1188 0 : bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
1189 : SkIRect ibounds;
1190 0 : if (!getClipDeviceBounds(&ibounds)) {
1191 0 : return false;
1192 : }
1193 :
1194 : SkMatrix inverse;
1195 : // if we can't invert the CTM, we can't return local clip bounds
1196 0 : if (!fMCRec->fMatrix->invert(&inverse)) {
1197 0 : if (bounds) {
1198 0 : bounds->setEmpty();
1199 : }
1200 0 : return false;
1201 : }
1202 :
1203 0 : if (NULL != bounds) {
1204 : SkRect r;
1205 : // adjust it outwards if we are antialiasing
1206 0 : int inset = (kAA_EdgeType == et);
1207 : r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
1208 0 : ibounds.fRight + inset, ibounds.fBottom + inset);
1209 0 : inverse.mapRect(bounds, r);
1210 : }
1211 0 : return true;
1212 : }
1213 :
1214 0 : bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
1215 0 : const SkRasterClip& clip = *fMCRec->fRasterClip;
1216 0 : if (clip.isEmpty()) {
1217 0 : if (bounds) {
1218 0 : bounds->setEmpty();
1219 : }
1220 0 : return false;
1221 : }
1222 :
1223 0 : if (NULL != bounds) {
1224 0 : *bounds = clip.getBounds();
1225 : }
1226 0 : return true;
1227 : }
1228 :
1229 0 : const SkMatrix& SkCanvas::getTotalMatrix() const {
1230 0 : return *fMCRec->fMatrix;
1231 : }
1232 :
1233 0 : SkCanvas::ClipType SkCanvas::getClipType() const {
1234 0 : if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
1235 0 : if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
1236 0 : return kComplex_ClipType;
1237 : }
1238 :
1239 0 : const SkRegion& SkCanvas::getTotalClip() const {
1240 0 : return fMCRec->fRasterClip->forceGetBW();
1241 : }
1242 :
1243 0 : const SkClipStack& SkCanvas::getTotalClipStack() const {
1244 0 : return fClipStack;
1245 : }
1246 :
1247 0 : void SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
1248 0 : if (NULL == matrix || matrix->isIdentity()) {
1249 0 : if (fUseExternalMatrix) {
1250 0 : fDeviceCMDirty = true;
1251 : }
1252 0 : fUseExternalMatrix = false;
1253 : } else {
1254 0 : fUseExternalMatrix = true;
1255 0 : fDeviceCMDirty = true; // |= (fExternalMatrix != *matrix)
1256 :
1257 0 : fExternalMatrix = *matrix;
1258 0 : matrix->invert(&fExternalInverse);
1259 : }
1260 0 : }
1261 :
1262 0 : SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
1263 : int width, int height,
1264 : bool isOpaque) {
1265 0 : SkDevice* device = this->getTopDevice();
1266 0 : if (device) {
1267 : return device->createCompatibleDeviceForSaveLayer(config, width, height,
1268 0 : isOpaque);
1269 : } else {
1270 0 : return NULL;
1271 : }
1272 : }
1273 :
1274 0 : SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
1275 : int width, int height,
1276 : bool isOpaque) {
1277 0 : SkDevice* device = this->getDevice();
1278 0 : if (device) {
1279 0 : return device->createCompatibleDevice(config, width, height, isOpaque);
1280 : } else {
1281 0 : return NULL;
1282 : }
1283 : }
1284 :
1285 :
1286 : //////////////////////////////////////////////////////////////////////////////
1287 : // These are the virtual drawing methods
1288 : //////////////////////////////////////////////////////////////////////////////
1289 :
1290 0 : void SkCanvas::clear(SkColor color) {
1291 0 : SkDrawIter iter(this);
1292 :
1293 0 : while (iter.next()) {
1294 0 : iter.fDevice->clear(color);
1295 : }
1296 0 : }
1297 :
1298 0 : void SkCanvas::drawPaint(const SkPaint& paint) {
1299 0 : this->internalDrawPaint(paint);
1300 0 : }
1301 :
1302 0 : void SkCanvas::internalDrawPaint(const SkPaint& paint) {
1303 0 : LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
1304 :
1305 0 : while (iter.next()) {
1306 0 : iter.fDevice->drawPaint(iter, looper.paint());
1307 : }
1308 :
1309 : LOOPER_END
1310 0 : }
1311 :
1312 0 : void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
1313 : const SkPaint& paint) {
1314 0 : if ((long)count <= 0) {
1315 0 : return;
1316 : }
1317 :
1318 0 : SkASSERT(pts != NULL);
1319 :
1320 0 : LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
1321 :
1322 0 : while (iter.next()) {
1323 0 : iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
1324 : }
1325 :
1326 : LOOPER_END
1327 : }
1328 :
1329 0 : void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
1330 0 : if (paint.canComputeFastBounds()) {
1331 : SkRect storage;
1332 0 : if (this->quickReject(paint.computeFastBounds(r, &storage),
1333 0 : paint2EdgeType(&paint))) {
1334 0 : return;
1335 : }
1336 : }
1337 :
1338 0 : LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
1339 :
1340 0 : while (iter.next()) {
1341 0 : iter.fDevice->drawRect(iter, r, looper.paint());
1342 : }
1343 :
1344 : LOOPER_END
1345 : }
1346 :
1347 0 : void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
1348 0 : if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
1349 : SkRect storage;
1350 0 : const SkRect& bounds = path.getBounds();
1351 0 : if (this->quickReject(paint.computeFastBounds(bounds, &storage),
1352 0 : paint2EdgeType(&paint))) {
1353 0 : return;
1354 : }
1355 : }
1356 0 : if (path.isEmpty()) {
1357 0 : if (path.isInverseFillType()) {
1358 0 : this->internalDrawPaint(paint);
1359 : }
1360 0 : return;
1361 : }
1362 :
1363 0 : LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1364 :
1365 0 : while (iter.next()) {
1366 0 : iter.fDevice->drawPath(iter, path, looper.paint());
1367 : }
1368 :
1369 : LOOPER_END
1370 : }
1371 :
1372 0 : void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
1373 : const SkPaint* paint) {
1374 0 : SkDEBUGCODE(bitmap.validate();)
1375 :
1376 0 : if (NULL == paint || paint->canComputeFastBounds()) {
1377 : SkRect fastBounds;
1378 : fastBounds.set(x, y,
1379 0 : x + SkIntToScalar(bitmap.width()),
1380 0 : y + SkIntToScalar(bitmap.height()));
1381 0 : if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
1382 0 : return;
1383 : }
1384 : }
1385 :
1386 : SkMatrix matrix;
1387 0 : matrix.setTranslate(x, y);
1388 0 : this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1389 : }
1390 :
1391 : // this one is non-virtual, so it can be called safely by other canvas apis
1392 0 : void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1393 : const SkRect& dst, const SkPaint* paint) {
1394 0 : if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
1395 0 : return;
1396 : }
1397 :
1398 : // do this now, to avoid the cost of calling extract for RLE bitmaps
1399 0 : if (NULL == paint || paint->canComputeFastBounds()) {
1400 0 : if (this->quickReject(dst, paint2EdgeType(paint))) {
1401 0 : return;
1402 : }
1403 : }
1404 :
1405 0 : const SkBitmap* bitmapPtr = &bitmap;
1406 :
1407 : SkMatrix matrix;
1408 : SkRect tmpSrc;
1409 0 : if (src) {
1410 0 : tmpSrc.set(*src);
1411 : // if the extract process clipped off the top or left of the
1412 : // original, we adjust for that here to get the position right.
1413 0 : if (tmpSrc.fLeft > 0) {
1414 0 : tmpSrc.fRight -= tmpSrc.fLeft;
1415 0 : tmpSrc.fLeft = 0;
1416 : }
1417 0 : if (tmpSrc.fTop > 0) {
1418 0 : tmpSrc.fBottom -= tmpSrc.fTop;
1419 0 : tmpSrc.fTop = 0;
1420 : }
1421 : } else {
1422 : tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
1423 0 : SkIntToScalar(bitmap.height()));
1424 : }
1425 0 : matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1426 :
1427 : // ensure that src is "valid" before we pass it to our internal routines
1428 : // and to SkDevice. i.e. sure it is contained inside the original bitmap.
1429 : SkIRect tmpISrc;
1430 0 : if (src) {
1431 0 : tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
1432 0 : if (!tmpISrc.intersect(*src)) {
1433 0 : return;
1434 : }
1435 0 : src = &tmpISrc;
1436 : }
1437 0 : this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
1438 : }
1439 :
1440 0 : void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
1441 : const SkRect& dst, const SkPaint* paint) {
1442 0 : SkDEBUGCODE(bitmap.validate();)
1443 0 : this->internalDrawBitmapRect(bitmap, src, dst, paint);
1444 0 : }
1445 :
1446 0 : void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1447 : const SkPaint* paint) {
1448 0 : SkDEBUGCODE(bitmap.validate();)
1449 0 : this->internalDrawBitmap(bitmap, NULL, matrix, paint);
1450 0 : }
1451 :
1452 0 : void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
1453 : const SkMatrix& matrix, const SkPaint& paint) {
1454 0 : SkDEBUGCODE(bitmap.validate();)
1455 :
1456 0 : LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
1457 :
1458 0 : while (iter.next()) {
1459 0 : iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
1460 : }
1461 :
1462 : LOOPER_END
1463 0 : }
1464 :
1465 0 : void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
1466 : const SkIRect& center, const SkRect& dst,
1467 : const SkPaint* paint) {
1468 0 : if (NULL == paint || paint->canComputeFastBounds()) {
1469 0 : if (this->quickReject(dst, paint2EdgeType(paint))) {
1470 0 : return;
1471 : }
1472 : }
1473 :
1474 0 : const int32_t w = bitmap.width();
1475 0 : const int32_t h = bitmap.height();
1476 :
1477 0 : SkIRect c = center;
1478 : // pin center to the bounds of the bitmap
1479 0 : c.fLeft = SkMax32(0, center.fLeft);
1480 0 : c.fTop = SkMax32(0, center.fTop);
1481 0 : c.fRight = SkPin32(center.fRight, c.fLeft, w);
1482 0 : c.fBottom = SkPin32(center.fBottom, c.fTop, h);
1483 :
1484 0 : const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w };
1485 0 : const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h };
1486 : SkScalar dstX[4] = {
1487 0 : dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
1488 0 : dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
1489 0 : };
1490 : SkScalar dstY[4] = {
1491 0 : dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
1492 0 : dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
1493 0 : };
1494 :
1495 0 : if (dstX[1] > dstX[2]) {
1496 0 : dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
1497 0 : dstX[2] = dstX[1];
1498 : }
1499 :
1500 0 : if (dstY[1] > dstY[2]) {
1501 0 : dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
1502 0 : dstY[2] = dstY[1];
1503 : }
1504 :
1505 : SkIRect s;
1506 : SkRect d;
1507 0 : for (int y = 0; y < 3; y++) {
1508 0 : s.fTop = srcY[y];
1509 0 : s.fBottom = srcY[y+1];
1510 0 : d.fTop = dstY[y];
1511 0 : d.fBottom = dstY[y+1];
1512 0 : for (int x = 0; x < 3; x++) {
1513 0 : s.fLeft = srcX[x];
1514 0 : s.fRight = srcX[x+1];
1515 0 : d.fLeft = dstX[x];
1516 0 : d.fRight = dstX[x+1];
1517 0 : this->internalDrawBitmapRect(bitmap, &s, d, paint);
1518 : }
1519 : }
1520 : }
1521 :
1522 0 : void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1523 : const SkRect& dst, const SkPaint* paint) {
1524 0 : SkDEBUGCODE(bitmap.validate();)
1525 :
1526 : // Need a device entry-point, so gpu can use a mesh
1527 0 : this->internalDrawBitmapNine(bitmap, center, dst, paint);
1528 0 : }
1529 :
1530 0 : void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
1531 : const SkPaint* paint) {
1532 0 : SkDEBUGCODE(bitmap.validate();)
1533 :
1534 0 : if (reject_bitmap(bitmap)) {
1535 0 : return;
1536 : }
1537 :
1538 0 : SkPaint tmp;
1539 0 : if (NULL == paint) {
1540 0 : paint = &tmp;
1541 : }
1542 :
1543 0 : LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
1544 :
1545 0 : while (iter.next()) {
1546 0 : iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
1547 0 : looper.paint());
1548 : }
1549 : LOOPER_END
1550 : }
1551 :
1552 0 : class SkDeviceFilteredPaint {
1553 : public:
1554 0 : SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
1555 : SkDevice::TextFlags flags;
1556 0 : if (device->filterTextFlags(paint, &flags)) {
1557 0 : SkPaint* newPaint = fLazy.set(paint);
1558 0 : newPaint->setFlags(flags.fFlags);
1559 0 : newPaint->setHinting(flags.fHinting);
1560 0 : fPaint = newPaint;
1561 : } else {
1562 0 : fPaint = &paint;
1563 : }
1564 0 : }
1565 :
1566 0 : const SkPaint& paint() const { return *fPaint; }
1567 :
1568 : private:
1569 : const SkPaint* fPaint;
1570 : SkLazyPaint fLazy;
1571 : };
1572 :
1573 0 : void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
1574 : const SkRect& r, SkScalar textSize) {
1575 0 : if (paint.getStyle() == SkPaint::kFill_Style) {
1576 0 : draw.fDevice->drawRect(draw, r, paint);
1577 : } else {
1578 0 : SkPaint p(paint);
1579 0 : p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
1580 0 : draw.fDevice->drawRect(draw, r, p);
1581 : }
1582 0 : }
1583 :
1584 0 : void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
1585 : const char text[], size_t byteLength,
1586 : SkScalar x, SkScalar y) {
1587 0 : SkASSERT(byteLength == 0 || text != NULL);
1588 :
1589 : // nothing to draw
1590 0 : if (text == NULL || byteLength == 0 ||
1591 0 : draw.fClip->isEmpty() ||
1592 0 : (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1593 0 : return;
1594 : }
1595 :
1596 0 : SkScalar width = 0;
1597 : SkPoint start;
1598 :
1599 0 : start.set(0, 0); // to avoid warning
1600 0 : if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
1601 : SkPaint::kStrikeThruText_Flag)) {
1602 0 : width = paint.measureText(text, byteLength);
1603 :
1604 0 : SkScalar offsetX = 0;
1605 0 : if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1606 0 : offsetX = SkScalarHalf(width);
1607 0 : } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
1608 0 : offsetX = width;
1609 : }
1610 0 : start.set(x - offsetX, y);
1611 : }
1612 :
1613 0 : if (0 == width) {
1614 0 : return;
1615 : }
1616 :
1617 0 : uint32_t flags = paint.getFlags();
1618 :
1619 0 : if (flags & (SkPaint::kUnderlineText_Flag |
1620 : SkPaint::kStrikeThruText_Flag)) {
1621 0 : SkScalar textSize = paint.getTextSize();
1622 0 : SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
1623 : SkRect r;
1624 :
1625 0 : r.fLeft = start.fX;
1626 0 : r.fRight = start.fX + width;
1627 :
1628 0 : if (flags & SkPaint::kUnderlineText_Flag) {
1629 0 : SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
1630 : start.fY);
1631 0 : r.fTop = offset;
1632 0 : r.fBottom = offset + height;
1633 0 : DrawRect(draw, paint, r, textSize);
1634 : }
1635 0 : if (flags & SkPaint::kStrikeThruText_Flag) {
1636 0 : SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
1637 : start.fY);
1638 0 : r.fTop = offset;
1639 0 : r.fBottom = offset + height;
1640 0 : DrawRect(draw, paint, r, textSize);
1641 : }
1642 : }
1643 : }
1644 :
1645 0 : void SkCanvas::drawText(const void* text, size_t byteLength,
1646 : SkScalar x, SkScalar y, const SkPaint& paint) {
1647 0 : LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1648 :
1649 0 : while (iter.next()) {
1650 0 : SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1651 0 : iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
1652 0 : DrawTextDecorations(iter, dfp.paint(),
1653 0 : static_cast<const char*>(text), byteLength, x, y);
1654 : }
1655 :
1656 : LOOPER_END
1657 0 : }
1658 :
1659 0 : void SkCanvas::drawPosText(const void* text, size_t byteLength,
1660 : const SkPoint pos[], const SkPaint& paint) {
1661 0 : LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1662 :
1663 0 : while (iter.next()) {
1664 0 : SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1665 : iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
1666 0 : dfp.paint());
1667 : }
1668 :
1669 : LOOPER_END
1670 0 : }
1671 :
1672 0 : void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
1673 : const SkScalar xpos[], SkScalar constY,
1674 : const SkPaint& paint) {
1675 0 : LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1676 :
1677 0 : while (iter.next()) {
1678 0 : SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
1679 : iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
1680 0 : dfp.paint());
1681 : }
1682 :
1683 : LOOPER_END
1684 0 : }
1685 :
1686 0 : void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
1687 : const SkPath& path, const SkMatrix* matrix,
1688 : const SkPaint& paint) {
1689 0 : LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1690 :
1691 0 : while (iter.next()) {
1692 : iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
1693 0 : matrix, looper.paint());
1694 : }
1695 :
1696 : LOOPER_END
1697 0 : }
1698 :
1699 : #ifdef SK_BUILD_FOR_ANDROID
1700 : void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
1701 : const SkPoint pos[], const SkPaint& paint,
1702 : const SkPath& path, const SkMatrix* matrix) {
1703 : LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
1704 :
1705 : while (iter.next()) {
1706 : iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
1707 : looper.paint(), path, matrix);
1708 : }
1709 :
1710 : LOOPER_END
1711 : }
1712 : #endif
1713 :
1714 0 : void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
1715 : const SkPoint verts[], const SkPoint texs[],
1716 : const SkColor colors[], SkXfermode* xmode,
1717 : const uint16_t indices[], int indexCount,
1718 : const SkPaint& paint) {
1719 0 : LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
1720 :
1721 0 : while (iter.next()) {
1722 : iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
1723 : colors, xmode, indices, indexCount,
1724 0 : looper.paint());
1725 : }
1726 :
1727 : LOOPER_END
1728 0 : }
1729 :
1730 0 : void SkCanvas::drawData(const void* data, size_t length) {
1731 : // do nothing. Subclasses may do something with the data
1732 0 : }
1733 :
1734 : //////////////////////////////////////////////////////////////////////////////
1735 : // These methods are NOT virtual, and therefore must call back into virtual
1736 : // methods, rather than actually drawing themselves.
1737 : //////////////////////////////////////////////////////////////////////////////
1738 :
1739 0 : void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b,
1740 : SkXfermode::Mode mode) {
1741 0 : SkPaint paint;
1742 :
1743 0 : paint.setARGB(a, r, g, b);
1744 0 : if (SkXfermode::kSrcOver_Mode != mode) {
1745 0 : paint.setXfermodeMode(mode);
1746 : }
1747 0 : this->drawPaint(paint);
1748 0 : }
1749 :
1750 0 : void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) {
1751 0 : SkPaint paint;
1752 :
1753 0 : paint.setColor(c);
1754 0 : if (SkXfermode::kSrcOver_Mode != mode) {
1755 0 : paint.setXfermodeMode(mode);
1756 : }
1757 0 : this->drawPaint(paint);
1758 0 : }
1759 :
1760 0 : void SkCanvas::drawPoint(SkScalar x, SkScalar y, const SkPaint& paint) {
1761 : SkPoint pt;
1762 :
1763 0 : pt.set(x, y);
1764 0 : this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1765 0 : }
1766 :
1767 0 : void SkCanvas::drawPoint(SkScalar x, SkScalar y, SkColor color) {
1768 : SkPoint pt;
1769 0 : SkPaint paint;
1770 :
1771 0 : pt.set(x, y);
1772 0 : paint.setColor(color);
1773 0 : this->drawPoints(kPoints_PointMode, 1, &pt, paint);
1774 0 : }
1775 :
1776 0 : void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1,
1777 : const SkPaint& paint) {
1778 : SkPoint pts[2];
1779 :
1780 0 : pts[0].set(x0, y0);
1781 0 : pts[1].set(x1, y1);
1782 0 : this->drawPoints(kLines_PointMode, 2, pts, paint);
1783 0 : }
1784 :
1785 0 : void SkCanvas::drawRectCoords(SkScalar left, SkScalar top,
1786 : SkScalar right, SkScalar bottom,
1787 : const SkPaint& paint) {
1788 : SkRect r;
1789 :
1790 0 : r.set(left, top, right, bottom);
1791 0 : this->drawRect(r, paint);
1792 0 : }
1793 :
1794 0 : void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius,
1795 : const SkPaint& paint) {
1796 0 : if (radius < 0) {
1797 0 : radius = 0;
1798 : }
1799 :
1800 : SkRect r;
1801 0 : r.set(cx - radius, cy - radius, cx + radius, cy + radius);
1802 :
1803 0 : if (paint.canComputeFastBounds()) {
1804 : SkRect storage;
1805 0 : if (this->quickReject(paint.computeFastBounds(r, &storage),
1806 0 : paint2EdgeType(&paint))) {
1807 0 : return;
1808 : }
1809 : }
1810 :
1811 0 : SkPath path;
1812 0 : path.addOval(r);
1813 0 : this->drawPath(path, paint);
1814 : }
1815 :
1816 0 : void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
1817 : const SkPaint& paint) {
1818 0 : if (rx > 0 && ry > 0) {
1819 0 : if (paint.canComputeFastBounds()) {
1820 : SkRect storage;
1821 0 : if (this->quickReject(paint.computeFastBounds(r, &storage),
1822 0 : paint2EdgeType(&paint))) {
1823 0 : return;
1824 : }
1825 : }
1826 :
1827 0 : SkPath path;
1828 0 : path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
1829 0 : this->drawPath(path, paint);
1830 : } else {
1831 0 : this->drawRect(r, paint);
1832 : }
1833 : }
1834 :
1835 0 : void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
1836 0 : if (paint.canComputeFastBounds()) {
1837 : SkRect storage;
1838 0 : if (this->quickReject(paint.computeFastBounds(oval, &storage),
1839 0 : paint2EdgeType(&paint))) {
1840 0 : return;
1841 : }
1842 : }
1843 :
1844 0 : SkPath path;
1845 0 : path.addOval(oval);
1846 0 : this->drawPath(path, paint);
1847 : }
1848 :
1849 0 : void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle,
1850 : SkScalar sweepAngle, bool useCenter,
1851 : const SkPaint& paint) {
1852 0 : if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
1853 0 : this->drawOval(oval, paint);
1854 : } else {
1855 0 : SkPath path;
1856 0 : if (useCenter) {
1857 0 : path.moveTo(oval.centerX(), oval.centerY());
1858 : }
1859 0 : path.arcTo(oval, startAngle, sweepAngle, !useCenter);
1860 0 : if (useCenter) {
1861 0 : path.close();
1862 : }
1863 0 : this->drawPath(path, paint);
1864 : }
1865 0 : }
1866 :
1867 0 : void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
1868 : const SkPath& path, SkScalar hOffset,
1869 : SkScalar vOffset, const SkPaint& paint) {
1870 : SkMatrix matrix;
1871 :
1872 0 : matrix.setTranslate(hOffset, vOffset);
1873 0 : this->drawTextOnPath(text, byteLength, path, &matrix, paint);
1874 0 : }
1875 :
1876 : ///////////////////////////////////////////////////////////////////////////////
1877 :
1878 0 : void SkCanvas::drawPicture(SkPicture& picture) {
1879 0 : int saveCount = save();
1880 0 : picture.draw(this);
1881 0 : restoreToCount(saveCount);
1882 0 : }
1883 :
1884 : ///////////////////////////////////////////////////////////////////////////////
1885 : ///////////////////////////////////////////////////////////////////////////////
1886 :
1887 0 : SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
1888 : SK_COMPILE_ASSERT(sizeof(fStorage) >= sizeof(SkDrawIter), fStorage_too_small);
1889 :
1890 0 : SkASSERT(canvas);
1891 :
1892 0 : fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
1893 0 : fDone = !fImpl->next();
1894 0 : }
1895 :
1896 0 : SkCanvas::LayerIter::~LayerIter() {
1897 0 : fImpl->~SkDrawIter();
1898 0 : }
1899 :
1900 0 : void SkCanvas::LayerIter::next() {
1901 0 : fDone = !fImpl->next();
1902 0 : }
1903 :
1904 0 : SkDevice* SkCanvas::LayerIter::device() const {
1905 0 : return fImpl->getDevice();
1906 : }
1907 :
1908 0 : const SkMatrix& SkCanvas::LayerIter::matrix() const {
1909 0 : return fImpl->getMatrix();
1910 : }
1911 :
1912 0 : const SkPaint& SkCanvas::LayerIter::paint() const {
1913 0 : const SkPaint* paint = fImpl->getPaint();
1914 0 : if (NULL == paint) {
1915 0 : paint = &fDefaultPaint;
1916 : }
1917 0 : return *paint;
1918 : }
1919 :
1920 0 : const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); }
1921 0 : int SkCanvas::LayerIter::x() const { return fImpl->getX(); }
1922 4392 : int SkCanvas::LayerIter::y() const { return fImpl->getY(); }
|