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
12SkIRect 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
22void SkClipStackDevice::onSave() {
23 fClipStack.save();
24}
25
26void SkClipStackDevice::onRestore() {
27 fClipStack.restore();
28}
29
30void SkClipStackDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
31 fClipStack.clipRect(rect, this->localToDevice(), op, aa);
32}
33
34void SkClipStackDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
35 fClipStack.clipRRect(rrect, this->localToDevice(), op, aa);
36}
37
38void SkClipStackDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
39 fClipStack.clipPath(path, this->localToDevice(), op, aa);
40}
41
42void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
43 SkIPoint origin = this->getOrigin();
44 SkRegion tmp;
45 SkPath path;
46 rgn.getBoundaryPath(&path);
47 path.transform(SkMatrix::MakeTrans(-origin));
48 fClipStack.clipPath(path, SkMatrix::I(), op, false);
49}
50
51void SkClipStackDevice::onSetDeviceClipRestriction(SkIRect* clipRestriction) {
52 if (clipRestriction->isEmpty()) {
53 fClipStack.setDeviceClipRestriction(*clipRestriction);
54 } else {
55 SkIPoint origin = this->getOrigin();
56 SkIRect rect = clipRestriction->makeOffset(-origin);
57 fClipStack.setDeviceClipRestriction(rect);
58 fClipStack.clipDevRect(rect, SkClipOp::kIntersect);
59 }
60}
61
62bool SkClipStackDevice::onClipIsAA() const {
63 SkClipStack::B2TIter iter(fClipStack);
64 const SkClipStack::Element* element;
65
66 while ((element = iter.next()) != nullptr) {
67 if (element->isAA()) {
68 return true;
69 }
70 }
71 return false;
72}
73
74bool SkClipStackDevice::onClipIsWideOpen() const {
75 return fClipStack.quickContains(SkRect::MakeIWH(this->width(), this->height()));
76}
77
78void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const {
79 SkClipStack::BoundsType boundType;
80 bool isIntersectionOfRects;
81 SkRect bounds;
82 fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
83 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
84 rgn->setRect(bounds.round());
85 } else {
86 SkRegion boundsRgn({0, 0, this->width(), this->height()});
87 SkPath tmpPath;
88
89 *rgn = boundsRgn;
90 SkClipStack::B2TIter iter(fClipStack);
91 while (auto elem = iter.next()) {
92 tmpPath.rewind();
93 elem->asDeviceSpacePath(&tmpPath);
94 SkRegion tmpRgn;
95 tmpRgn.setPath(tmpPath, boundsRgn);
96 rgn->op(tmpRgn, SkRegion::Op(elem->getOp()));
97 }
98 }
99}
100
101SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const {
102 if (fClipStack.isWideOpen()) {
103 return ClipType::kRect;
104 }
105 if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) {
106 return ClipType::kEmpty;
107 } else {
108 SkClipStack::BoundsType boundType;
109 bool isIntersectionOfRects;
110 SkRect bounds;
111 fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
112 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
113 return ClipType::kRect;
114 } else {
115 return ClipType::kComplex;
116 }
117 }
118}
119