• 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