• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/SkClipStackDevice.h"
9 #include "src/core/SkDraw.h"
10 #include "src/core/SkRasterClip.h"
11 
onDevClipBounds() const12 SkIRect SkClipStackDevice::onDevClipBounds() 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->localToDevice(), 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->localToDevice(), 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->localToDevice(), op, aa);
40 }
41 
onClipShader(sk_sp<SkShader> shader)42 void SkClipStackDevice::onClipShader(sk_sp<SkShader> shader) {
43     fClipStack.clipShader(std::move(shader));
44 }
45 
onClipRegion(const SkRegion & rgn,SkClipOp op)46 void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
47     SkIPoint origin = this->getOrigin();
48     SkRegion tmp;
49     SkPath path;
50     rgn.getBoundaryPath(&path);
51     path.transform(SkMatrix::Translate(-origin));
52     fClipStack.clipPath(path, SkMatrix::I(), op, false);
53 }
54 
onReplaceClip(const SkIRect & rect)55 void SkClipStackDevice::onReplaceClip(const SkIRect& rect) {
56     SkRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect));
57     fClipStack.replaceClip(deviceRect, /*doAA=*/false);
58 }
59 
onClipIsAA() const60 bool SkClipStackDevice::onClipIsAA() const {
61     SkClipStack::B2TIter        iter(fClipStack);
62     const SkClipStack::Element* element;
63 
64     while ((element = iter.next()) != nullptr) {
65         if (element->isAA()) {
66             return true;
67         }
68     }
69     return false;
70 }
71 
onClipIsWideOpen() const72 bool SkClipStackDevice::onClipIsWideOpen() const {
73     return fClipStack.quickContains(SkRect::MakeIWH(this->width(), this->height()));
74 }
75 
onAsRgnClip(SkRegion * rgn) const76 void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const {
77     SkClipStack::BoundsType boundType;
78     bool isIntersectionOfRects;
79     SkRect bounds;
80     fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
81     if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
82         rgn->setRect(bounds.round());
83     } else {
84         SkRegion boundsRgn({0, 0, this->width(), this->height()});
85         SkPath tmpPath;
86 
87         *rgn = boundsRgn;
88         SkClipStack::B2TIter iter(fClipStack);
89         while (auto elem = iter.next()) {
90             tmpPath.rewind();
91             elem->asDeviceSpacePath(&tmpPath);
92             SkRegion tmpRgn;
93             tmpRgn.setPath(tmpPath, boundsRgn);
94             if (elem->isReplaceOp()) {
95                 // All replace elements are rectangles
96                 // TODO: SkClipStack can be simplified to be I,D,R ops now, which means element
97                 // iteration can be from top of the stack to the most recent replace element.
98                 // When that's done, this loop will be simplifiable.
99                 rgn->setRect(elem->getDeviceSpaceRect().round());
100             } else {
101                 rgn->op(tmpRgn, static_cast<SkRegion::Op>(elem->getOp()));
102             }
103         }
104     }
105 }
106 
onGetClipType() const107 SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const {
108     if (fClipStack.isWideOpen()) {
109         return ClipType::kRect;
110     }
111     if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) {
112         return ClipType::kEmpty;
113     } else {
114         SkClipStack::BoundsType boundType;
115         bool isIntersectionOfRects;
116         SkRect bounds;
117         fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
118         if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
119             return ClipType::kRect;
120         } else {
121             return ClipType::kComplex;
122         }
123     }
124 }
125