1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkClipStackDevice.h"
9 #include "SkDraw.h"
10 #include "SkRasterClip.h"
11 
devClipBounds() const12 SkIRect SkClipStackDevice::devClipBounds() const {
13     SkIRect r = fClipStack.bounds(this->imageInfo().bounds()).roundOut();
14     if (!r.isEmpty()) {
15         SkASSERT(this->imageInfo().bounds().contains(r));
16     }
17     return r;
18 }
19 
20 ///////////////////////////////////////////////////////////////////////////////////////////////////
21 
onSave()22 void SkClipStackDevice::onSave() {
23     fClipStack.save();
24 }
25 
onRestore()26 void SkClipStackDevice::onRestore() {
27     fClipStack.restore();
28 }
29 
onClipRect(const SkRect & rect,SkClipOp op,bool aa)30 void SkClipStackDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
31     fClipStack.clipRect(rect, this->ctm(), op, aa);
32 }
33 
onClipRRect(const SkRRect & rrect,SkClipOp op,bool aa)34 void SkClipStackDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
35     fClipStack.clipRRect(rrect, this->ctm(), op, aa);
36 }
37 
onClipPath(const SkPath & path,SkClipOp op,bool aa)38 void SkClipStackDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
39     fClipStack.clipPath(path, this->ctm(), op, aa);
40 }
41 
onClipRegion(const SkRegion & rgn,SkClipOp op)42 void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
43     SkIPoint origin = this->getOrigin();
44     SkRegion tmp;
45     const SkRegion* ptr = &rgn;
46     if (origin.fX | origin.fY) {
47         // translate from "global/canvas" coordinates to relative to this device
48         rgn.translate(-origin.fX, -origin.fY, &tmp);
49         ptr = &tmp;
50     }
51     fClipStack.clipDevRect(ptr->getBounds(), op);
52 }
53 
onSetDeviceClipRestriction(SkIRect * clipRestriction)54 void SkClipStackDevice::onSetDeviceClipRestriction(SkIRect* clipRestriction) {
55     if (clipRestriction->isEmpty()) {
56         fClipStack.setDeviceClipRestriction(*clipRestriction);
57     } else {
58         SkIPoint origin = this->getOrigin();
59         SkIRect rect = clipRestriction->makeOffset(-origin.x(), -origin.y());
60         fClipStack.setDeviceClipRestriction(rect);
61         fClipStack.clipDevRect(rect, SkClipOp::kIntersect);
62     }
63 }
64 
onClipIsAA() const65 bool SkClipStackDevice::onClipIsAA() const {
66     SkClipStack::B2TIter        iter(fClipStack);
67     const SkClipStack::Element* element;
68 
69     while ((element = iter.next()) != nullptr) {
70         if (element->isAA()) {
71             return true;
72         }
73     }
74     return false;
75 }
76 
onAsRgnClip(SkRegion * rgn) const77 void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const {
78     SkClipStack::BoundsType boundType;
79     bool isIntersectionOfRects;
80     SkRect bounds;
81     fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
82     if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
83         rgn->setRect(bounds.round());
84     } else {
85         SkPath path;
86         fClipStack.asPath(&path);
87         rgn->setPath(path, SkRegion(SkIRect::MakeWH(this->width(), this->height())));
88     }
89 }
90 
onGetClipType() const91 SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const {
92     if (fClipStack.isWideOpen()) {
93         return kRect_ClipType;
94     }
95     if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) {
96         return kEmpty_ClipType;
97     } else {
98         SkClipStack::BoundsType boundType;
99         bool isIntersectionOfRects;
100         SkRect bounds;
101         fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
102         if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
103             return kRect_ClipType;
104         } else {
105             return kComplex_ClipType;
106         }
107     }
108 }
109