• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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