1 /*
2 * Copyright 2019 Google LLC.
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 "experimental/xform/SkShape.h"
9 #include "experimental/xform/SkXform.h"
10 #include "include/core/SkCanvas.h"
11
12 #include "src/core/SkRasterClip.h"
13
14 class RasterClipCache : public ClipCache {
15 public:
RasterClipCache(const SkRasterClip & rc)16 RasterClipCache(const SkRasterClip& rc) : fRC(std::move(rc)) {}
17
18 SkRasterClip fRC;
19 };
20
peek_rasterclip(ClipCache * clip)21 static const SkRasterClip& peek_rasterclip(ClipCache* clip) {
22 return ((RasterClipCache*)clip)->fRC;
23 }
24
25 class RasterXformResolver : public XformResolver {
26 public:
RasterXformResolver(const SkIRect & bounds)27 RasterXformResolver(const SkIRect& bounds)
28 : fBounds(bounds)
29 , fCTM(SkMatrix::I())
30 , fRC(bounds)
31 {}
32
RasterXformResolver(Xform * parent)33 RasterXformResolver(Xform* parent) {
34 const SkRasterClip& rc = peek_rasterclip(parent->clip());
35 fBounds = rc.getBounds();
36 fCTM = parent->ctm();
37 fRC = rc;
38 }
39
concat(const SkMatrix & m)40 void concat(const SkMatrix& m) override {
41 fCTM.preConcat(m);
42 }
43
clipRect(const SkRect & r,SkClipOp op)44 void clipRect(const SkRect& r, SkClipOp op) override {
45 fRC.op(r, fCTM, fBounds, (SkRegion::Op)op, false);
46 fCache.reset(nullptr);
47 }
48
clipRRect(const SkRRect & rr,SkClipOp op)49 void clipRRect(const SkRRect& rr, SkClipOp op) override {
50 fRC.op(rr, fCTM, fBounds, (SkRegion::Op)op, false);
51 fCache.reset(nullptr);
52 }
clipPath(const SkPath & p,SkClipOp op)53 void clipPath(const SkPath& p, SkClipOp op) override {
54 fRC.op(p, fCTM, fBounds, (SkRegion::Op)op, false);
55 fCache.reset(nullptr);
56 }
57
ctm() const58 const SkMatrix& ctm() const { return fCTM; }
59
snapCache()60 sk_sp<ClipCache> snapCache() {
61 if (!fCache) {
62 fCache = sk_sp<ClipCache>(new RasterClipCache(fRC));
63 }
64 return fCache;
65 }
66
67 private:
68 SkIRect fBounds;
69 SkMatrix fCTM;
70 SkRasterClip fRC;
71 sk_sp<ClipCache> fCache;
72 };
73
drawRect(const SkRect & r,const SkPaint & p,Xform * x)74 void XContext::drawRect(const SkRect& r, const SkPaint& p, Xform* x) {
75 this->onDrawRect(r, p, x);
76 }
77
78 class CanvasXContext : public XContext {
79 public:
CanvasXContext(SkCanvas * canvas)80 CanvasXContext(SkCanvas* canvas) : fCanvas(canvas) {
81 fBounds = {
82 0, 0, canvas->getBaseLayerSize().width(), canvas->getBaseLayerSize().height()
83 };
84 }
85
86 protected:
count_nodes(const Xform * x)87 static int count_nodes(const Xform* x) {
88 int n = 0;
89 for (; x; x = x->parent()) {
90 n += 1;
91 }
92 return n;
93 }
94
onPush(Xform * x)95 void onPush(Xform* x) override {
96 int n = count_nodes(x);
97 fCounts.push_back(n);
98 if (n) {
99 int prevCount = fStack.count();
100 // now push the x tree such that we get [... grandparent, parent, x] in the array
101 Xform** ptr = fStack.append(n) + n;
102 Xform* xx = x;
103 while (n --> 0) {
104 *--ptr = xx;
105 xx = xx->parent();
106 }
107 // init with the old tail
108 if (prevCount > 0) {
109 RasterXformResolver res(fStack[prevCount - 1]);
110 for (int i = prevCount; i < fStack.count(); ++i) {
111 fStack[i]->visit(&res);
112 fStack[i]->setCache(res.ctm(), res.snapCache());
113 }
114 } else if (!x->genID()) {
115 RasterXformResolver res(fBounds);
116 for (int i = 0; i < fStack.count(); ++i) {
117 fStack[i]->visit(&res);
118 fStack[i]->setCache(res.ctm(), res.snapCache());
119 }
120 SkASSERT(x->genID());
121 }
122 }
123 }
124
onPop()125 void onPop() override {
126 int n = fCounts.top();
127 fCounts.pop();
128 if (n) {
129 fStack.setCount(fStack.count() - n);
130 }
131 }
132
onDrawRect(const SkRect & r,const SkPaint & p,Xform * x)133 void onDrawRect(const SkRect& r, const SkPaint& p, Xform* x) override {
134 Xform* parent = this->parentOrNull();
135 Xform::GenID parentID = parent ? parent->genID() : 0;
136 SkASSERT(parent == nullptr || parentID != 0);
137
138 if (x) {
139 SkASSERT(x->genID() != parentID || (x->genID() == 0 && parentID == 0));
140 if (x->genID() <= parentID) { // x is out of date
141 this->push(x); // will update caches
142 this->pop();
143 }
144 SkASSERT(x->genID() > parentID);
145 } else {
146 x = parent;
147 }
148
149 SkAutoCanvasRestore acr(fCanvas, false);
150 if (x) {
151 fCanvas->save();
152 fCanvas->concat(x->ctm());
153 fCanvas->clipRegion(peek_rasterclip(x->clip()).bwRgn());
154 }
155 fCanvas->drawRect(r, p);
156 }
157
158 private:
159 SkTDArray<Xform*> fStack;
160 SkTDArray<int> fCounts;
161
162 SkCanvas* fCanvas; // bare pointer
163 SkIRect fBounds;
164
parentOrNull()165 Xform* parentOrNull() {
166 return fStack.count() > 0 ? fStack.top() : nullptr;
167 }
168 };
169
Make(SkCanvas * canvas)170 std::unique_ptr<XContext> XContext::Make(SkCanvas* canvas) {
171 return std::unique_ptr<XContext>(new CanvasXContext(canvas));
172 }
173