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 | |
15 | 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 | |
23 | 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 | |
33 | 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 | |
51 | 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 | |
81 | bool SkDrawLooper::asABlurShadow(BlurShadowRec*) const { |
82 | return false; |
83 | } |
84 | |
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 | |