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