1 /*
2  * Copyright 2013 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 "include/core/SkCanvas.h"
9 #include "include/core/SkMatrix.h"
10 #include "include/core/SkPaint.h"
11 #include "include/core/SkRect.h"
12 #include "src/core/SkArenaAlloc.h"
13 
14 #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
15 
16 #include "include/core/SkDrawLooper.h"
17 
applyToCTM(SkMatrix * ctm) const18 void SkDrawLooper::Context::Info::applyToCTM(SkMatrix* ctm) const {
19     if (fApplyPostCTM) {
20         ctm->postTranslate(fTranslate.fX, fTranslate.fY);
21     } else {
22         ctm->preTranslate(fTranslate.fX, fTranslate.fY);
23     }
24 }
25 
applyToCanvas(SkCanvas * canvas) const26 void SkDrawLooper::Context::Info::applyToCanvas(SkCanvas* canvas) const {
27     if (fApplyPostCTM) {
28         canvas->setMatrix(canvas->getLocalToDevice().postTranslate(fTranslate.fX, fTranslate.fY));
29     } else {
30         canvas->translate(fTranslate.fX, fTranslate.fY);
31     }
32 }
33 
canComputeFastBounds(const SkPaint & paint) const34 bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) const {
35     SkSTArenaAlloc<48> alloc;
36 
37     SkDrawLooper::Context* context = this->makeContext(&alloc);
38     for (;;) {
39         SkPaint p(paint);
40         SkDrawLooper::Context::Info info;
41         if (context->next(&info, &p)) {
42             if (!p.canComputeFastBounds()) {
43                 return false;
44             }
45         } else {
46             break;
47         }
48     }
49     return true;
50 }
51 
computeFastBounds(const SkPaint & paint,const SkRect & s,SkRect * dst) const52 void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& s,
53                                      SkRect* dst) const {
54     // src and dst rects may alias and we need to keep the original src, so copy it.
55     const SkRect src = s;
56 
57     SkSTArenaAlloc<48> alloc;
58 
59     *dst = src;   // catch case where there are no loops
60     SkDrawLooper::Context* context = this->makeContext(&alloc);
61 
62     for (bool firstTime = true;; firstTime = false) {
63         SkPaint p(paint);
64         SkDrawLooper::Context::Info info;
65         if (context->next(&info, &p)) {
66             SkRect r(src);
67 
68             p.computeFastBounds(r, &r);
69             r.offset(info.fTranslate.fX, info.fTranslate.fY);
70 
71             if (firstTime) {
72                 *dst = r;
73             } else {
74                 dst->join(r);
75             }
76         } else {
77             break;
78         }
79     }
80 }
81 
asABlurShadow(BlurShadowRec *) const82 bool SkDrawLooper::asABlurShadow(BlurShadowRec*) const {
83     return false;
84 }
85 
apply(SkCanvas * canvas,const SkPaint & paint,std::function<void (SkCanvas *,const SkPaint &)> proc)86 void SkDrawLooper::apply(SkCanvas* canvas, const SkPaint& paint,
87                          std::function<void(SkCanvas*, const SkPaint&)> proc) {
88     SkSTArenaAlloc<256> alloc;
89     Context* ctx = this->makeContext(&alloc);
90     if (ctx) {
91         Context::Info info;
92         for (;;) {
93             SkPaint p = paint;
94             if (!ctx->next(&info, &p)) {
95                 break;
96             }
97             canvas->save();
98             if (info.fApplyPostCTM) {
99                 canvas->setMatrix(canvas->getLocalToDevice().postTranslate(info.fTranslate.fX,
100                                                                            info.fTranslate.fY));
101             } else {
102                 canvas->translate(info.fTranslate.fX, info.fTranslate.fY);
103             }
104             proc(canvas, p);
105             canvas->restore();
106         }
107     }
108 }
109 
110 #endif
111