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
16namespace sksg {
17
18namespace {
19
20sk_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
43DashEffect::DashEffect(sk_sp<GeometryNode> child)
44 : fChild(std::move(child)) {
45 this->observeInval(fChild);
46}
47
48DashEffect::~DashEffect() {
49 this->unobserveInval(fChild);
50}
51
52void DashEffect::onClip(SkCanvas* canvas, bool antiAlias) const {
53 canvas->clipPath(fDashedPath, SkClipOp::kIntersect, antiAlias);
54}
55
56void DashEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
57 canvas->drawPath(fDashedPath, paint);
58}
59
60bool DashEffect::onContains(const SkPoint& p) const {
61 return fDashedPath.contains(p.x(), p.y());
62}
63
64SkPath DashEffect::onAsPath() const {
65 return fDashedPath;
66}
67
68SkRect 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