1 | /* |
2 | * Copyright 2020 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 "modules/sksg/include/SkSGDashEffect.h" |
9 | |
10 | #include "include/core/SkCanvas.h" |
11 | #include "include/core/SkStrokeRec.h" |
12 | #include "include/effects/SkDashPathEffect.h" |
13 | |
14 | #include <algorithm> |
15 | |
16 | namespace sksg { |
17 | |
18 | namespace { |
19 | |
20 | sk_sp<SkPathEffect> make_dash(const std::vector<float> intervals, float phase) { |
21 | if (intervals.empty()) { |
22 | return nullptr; |
23 | } |
24 | |
25 | const auto* intervals_ptr = intervals.data(); |
26 | auto intervals_count = intervals.size(); |
27 | |
28 | SkSTArray<32, float, true> storage; |
29 | if (intervals_count & 1) { |
30 | intervals_count *= 2; |
31 | storage.resize(intervals_count); |
32 | intervals_ptr = storage.data(); |
33 | |
34 | std::copy(intervals.begin(), intervals.end(), storage.begin()); |
35 | std::copy(intervals.begin(), intervals.end(), storage.begin() + intervals.size()); |
36 | } |
37 | |
38 | return SkDashPathEffect::Make(intervals_ptr, SkToInt(intervals_count), phase); |
39 | } |
40 | |
41 | } // namespace |
42 | |
43 | DashEffect::DashEffect(sk_sp<GeometryNode> child) |
44 | : fChild(std::move(child)) { |
45 | this->observeInval(fChild); |
46 | } |
47 | |
48 | DashEffect::~DashEffect() { |
49 | this->unobserveInval(fChild); |
50 | } |
51 | |
52 | void DashEffect::onClip(SkCanvas* canvas, bool antiAlias) const { |
53 | canvas->clipPath(fDashedPath, SkClipOp::kIntersect, antiAlias); |
54 | } |
55 | |
56 | void DashEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { |
57 | canvas->drawPath(fDashedPath, paint); |
58 | } |
59 | |
60 | bool DashEffect::onContains(const SkPoint& p) const { |
61 | return fDashedPath.contains(p.x(), p.y()); |
62 | } |
63 | |
64 | SkPath DashEffect::onAsPath() const { |
65 | return fDashedPath; |
66 | } |
67 | |
68 | SkRect DashEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { |
69 | SkASSERT(this->hasInval()); |
70 | |
71 | const auto child_bounds = fChild->revalidate(ic, ctm); |
72 | const auto child_path = fChild->asPath(); |
73 | |
74 | fDashedPath.reset(); |
75 | |
76 | auto dash_patheffect = make_dash(fIntervals, fPhase); |
77 | SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle); |
78 | |
79 | if (!dash_patheffect || |
80 | !dash_patheffect->filterPath(&fDashedPath, child_path, &rec, &child_bounds)) { |
81 | fDashedPath = std::move(child_path); |
82 | } |
83 | fDashedPath.shrinkToFit(); |
84 | |
85 | return fDashedPath.computeTightBounds(); |
86 | } |
87 | |
88 | } // namespace sksg |
89 | |