1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h"
9cb93a386Sopenharmony_ci#include "src/utils/SkDashPathPriv.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ciint GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) {
12cb93a386Sopenharmony_ci    static_assert(sizeof(uint32_t) == sizeof(SkScalar));
13cb93a386Sopenharmony_ci    int size = 0;
14cb93a386Sopenharmony_ci    if (style.isDashed()) {
15cb93a386Sopenharmony_ci        // One scalar for scale, one for dash phase, and one for each dash value.
16cb93a386Sopenharmony_ci        size += 2 + style.dashIntervalCnt();
17cb93a386Sopenharmony_ci    } else if (style.pathEffect()) {
18cb93a386Sopenharmony_ci        // No key for a generic path effect.
19cb93a386Sopenharmony_ci        return -1;
20cb93a386Sopenharmony_ci    }
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci    if (Apply::kPathEffectOnly == apply) {
23cb93a386Sopenharmony_ci        return size;
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci    if (style.strokeRec().needToApply()) {
27cb93a386Sopenharmony_ci        // One for res scale, one for style/cap/join, one for miter limit, and one for width.
28cb93a386Sopenharmony_ci        size += 4;
29cb93a386Sopenharmony_ci    }
30cb93a386Sopenharmony_ci    return size;
31cb93a386Sopenharmony_ci}
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_civoid GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply, SkScalar scale,
34cb93a386Sopenharmony_ci                       uint32_t flags) {
35cb93a386Sopenharmony_ci    SkASSERT(key);
36cb93a386Sopenharmony_ci    SkASSERT(KeySize(style, apply) >= 0);
37cb93a386Sopenharmony_ci    static_assert(sizeof(uint32_t) == sizeof(SkScalar));
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    int i = 0;
40cb93a386Sopenharmony_ci    // The scale can influence both the path effect and stroking. We want to preserve the
41cb93a386Sopenharmony_ci    // property that the following two are equal:
42cb93a386Sopenharmony_ci    // 1. WriteKey with apply == kPathEffectAndStrokeRec
43cb93a386Sopenharmony_ci    // 2. WriteKey with apply == kPathEffectOnly followed by WriteKey of a GrStyle made
44cb93a386Sopenharmony_ci    //    from SkStrokeRec output by the the path effect (and no additional path effect).
45cb93a386Sopenharmony_ci    // Since the scale can affect both parts of 2 we write it into the key twice.
46cb93a386Sopenharmony_ci    if (style.isDashed()) {
47cb93a386Sopenharmony_ci        static_assert(sizeof(style.dashPhase()) == sizeof(uint32_t));
48cb93a386Sopenharmony_ci        SkScalar phase = style.dashPhase();
49cb93a386Sopenharmony_ci        memcpy(&key[i++], &scale, sizeof(SkScalar));
50cb93a386Sopenharmony_ci        memcpy(&key[i++], &phase, sizeof(SkScalar));
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci        int32_t count = style.dashIntervalCnt();
53cb93a386Sopenharmony_ci        // Dash count should always be even.
54cb93a386Sopenharmony_ci        SkASSERT(0 == (count & 0x1));
55cb93a386Sopenharmony_ci        const SkScalar *intervals = style.dashIntervals();
56cb93a386Sopenharmony_ci        int intervalByteCnt = count * sizeof(SkScalar);
57cb93a386Sopenharmony_ci        memcpy(&key[i], intervals, intervalByteCnt);
58cb93a386Sopenharmony_ci        i += count;
59cb93a386Sopenharmony_ci    } else {
60cb93a386Sopenharmony_ci        SkASSERT(!style.pathEffect());
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    if (Apply::kPathEffectAndStrokeRec == apply && style.strokeRec().needToApply()) {
64cb93a386Sopenharmony_ci        memcpy(&key[i++], &scale, sizeof(SkScalar));
65cb93a386Sopenharmony_ci        enum {
66cb93a386Sopenharmony_ci            kStyleBits = 2,
67cb93a386Sopenharmony_ci            kJoinBits = 2,
68cb93a386Sopenharmony_ci            kCapBits = 32 - kStyleBits - kJoinBits,
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci            kJoinShift = kStyleBits,
71cb93a386Sopenharmony_ci            kCapShift = kJoinShift + kJoinBits,
72cb93a386Sopenharmony_ci        };
73cb93a386Sopenharmony_ci        static_assert(SkStrokeRec::kStyleCount <= (1 << kStyleBits));
74cb93a386Sopenharmony_ci        static_assert(SkPaint::kJoinCount <= (1 << kJoinBits));
75cb93a386Sopenharmony_ci        static_assert(SkPaint::kCapCount <= (1 << kCapBits));
76cb93a386Sopenharmony_ci        // The cap type only matters for unclosed shapes. However, a path effect could unclose
77cb93a386Sopenharmony_ci        // the shape before it is stroked.
78cb93a386Sopenharmony_ci        SkPaint::Cap cap = SkPaint::kDefault_Cap;
79cb93a386Sopenharmony_ci        if (!(flags & kClosed_KeyFlag) || style.pathEffect()) {
80cb93a386Sopenharmony_ci            cap = style.strokeRec().getCap();
81cb93a386Sopenharmony_ci        }
82cb93a386Sopenharmony_ci        SkScalar miter = -1.f;
83cb93a386Sopenharmony_ci        SkPaint::Join join = SkPaint::kDefault_Join;
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci        // Dashing will not insert joins but other path effects may.
86cb93a386Sopenharmony_ci        if (!(flags & kNoJoins_KeyFlag) || style.hasNonDashPathEffect()) {
87cb93a386Sopenharmony_ci            join = style.strokeRec().getJoin();
88cb93a386Sopenharmony_ci            // Miter limit only affects miter joins
89cb93a386Sopenharmony_ci            if (SkPaint::kMiter_Join == join) {
90cb93a386Sopenharmony_ci                miter = style.strokeRec().getMiter();
91cb93a386Sopenharmony_ci            }
92cb93a386Sopenharmony_ci        }
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci        key[i++] = style.strokeRec().getStyle() |
95cb93a386Sopenharmony_ci                   join << kJoinShift |
96cb93a386Sopenharmony_ci                   cap << kCapShift;
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci        memcpy(&key[i++], &miter, sizeof(miter));
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci        SkScalar width = style.strokeRec().getWidth();
101cb93a386Sopenharmony_ci        memcpy(&key[i++], &width, sizeof(width));
102cb93a386Sopenharmony_ci    }
103cb93a386Sopenharmony_ci    SkASSERT(KeySize(style, apply) == i);
104cb93a386Sopenharmony_ci}
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_civoid GrStyle::initPathEffect(sk_sp<SkPathEffect> pe) {
107cb93a386Sopenharmony_ci    SkASSERT(!fPathEffect);
108cb93a386Sopenharmony_ci    SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType);
109cb93a386Sopenharmony_ci    SkASSERT(0 == fDashInfo.fIntervals.count());
110cb93a386Sopenharmony_ci    if (!pe) {
111cb93a386Sopenharmony_ci        return;
112cb93a386Sopenharmony_ci    }
113cb93a386Sopenharmony_ci    SkPathEffect::DashInfo info;
114cb93a386Sopenharmony_ci    if (SkPathEffect::kDash_DashType == pe->asADash(&info)) {
115cb93a386Sopenharmony_ci        SkStrokeRec::Style recStyle = fStrokeRec.getStyle();
116cb93a386Sopenharmony_ci        if (recStyle != SkStrokeRec::kFill_Style && recStyle != SkStrokeRec::kStrokeAndFill_Style) {
117cb93a386Sopenharmony_ci            fDashInfo.fType = SkPathEffect::kDash_DashType;
118cb93a386Sopenharmony_ci            fDashInfo.fIntervals.reset(info.fCount);
119cb93a386Sopenharmony_ci            fDashInfo.fPhase = info.fPhase;
120cb93a386Sopenharmony_ci            info.fIntervals = fDashInfo.fIntervals.get();
121cb93a386Sopenharmony_ci            pe->asADash(&info);
122cb93a386Sopenharmony_ci            fPathEffect = std::move(pe);
123cb93a386Sopenharmony_ci        }
124cb93a386Sopenharmony_ci    } else {
125cb93a386Sopenharmony_ci        fPathEffect = std::move(pe);
126cb93a386Sopenharmony_ci    }
127cb93a386Sopenharmony_ci}
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_cibool GrStyle::applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const {
130cb93a386Sopenharmony_ci    if (!fPathEffect) {
131cb93a386Sopenharmony_ci        return false;
132cb93a386Sopenharmony_ci    }
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci    // TODO: [skbug.com/11957] Plumb CTM callers and pass it to filterPath().
135cb93a386Sopenharmony_ci    SkASSERT(!fPathEffect->needsCTM());
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci    if (SkPathEffect::kDash_DashType == fDashInfo.fType) {
138cb93a386Sopenharmony_ci        // We apply the dash ourselves here rather than using the path effect. This is so that
139cb93a386Sopenharmony_ci        // we can control whether the dasher applies the strokeRec for special cases. Our keying
140cb93a386Sopenharmony_ci        // depends on the strokeRec being applied separately.
141cb93a386Sopenharmony_ci        SkASSERT(!fPathEffect->needsCTM());  // Make sure specified PE doesn't need CTM
142cb93a386Sopenharmony_ci        SkScalar phase = fDashInfo.fPhase;
143cb93a386Sopenharmony_ci        const SkScalar* intervals = fDashInfo.fIntervals.get();
144cb93a386Sopenharmony_ci        int intervalCnt = fDashInfo.fIntervals.count();
145cb93a386Sopenharmony_ci        SkScalar initialLength;
146cb93a386Sopenharmony_ci        int initialIndex;
147cb93a386Sopenharmony_ci        SkScalar intervalLength;
148cb93a386Sopenharmony_ci        SkDashPath::CalcDashParameters(phase, intervals, intervalCnt, &initialLength,
149cb93a386Sopenharmony_ci                                       &initialIndex, &intervalLength);
150cb93a386Sopenharmony_ci        if (!SkDashPath::InternalFilter(dst, src, strokeRec,
151cb93a386Sopenharmony_ci                                        nullptr, intervals, intervalCnt,
152cb93a386Sopenharmony_ci                                        initialLength, initialIndex, intervalLength,
153cb93a386Sopenharmony_ci                                        SkDashPath::StrokeRecApplication::kDisallow)) {
154cb93a386Sopenharmony_ci            return false;
155cb93a386Sopenharmony_ci        }
156cb93a386Sopenharmony_ci    } else if (!fPathEffect->filterPath(dst, src, strokeRec, nullptr)) {
157cb93a386Sopenharmony_ci        return false;
158cb93a386Sopenharmony_ci    }
159cb93a386Sopenharmony_ci    dst->setIsVolatile(true);
160cb93a386Sopenharmony_ci    return true;
161cb93a386Sopenharmony_ci}
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_cibool GrStyle::applyPathEffectToPath(SkPath *dst, SkStrokeRec *remainingStroke,
164cb93a386Sopenharmony_ci                                    const SkPath &src, SkScalar resScale) const {
165cb93a386Sopenharmony_ci    SkASSERT(dst);
166cb93a386Sopenharmony_ci    SkStrokeRec strokeRec = fStrokeRec;
167cb93a386Sopenharmony_ci    strokeRec.setResScale(resScale);
168cb93a386Sopenharmony_ci    if (!this->applyPathEffect(dst, &strokeRec, src)) {
169cb93a386Sopenharmony_ci        return false;
170cb93a386Sopenharmony_ci    }
171cb93a386Sopenharmony_ci    *remainingStroke = strokeRec;
172cb93a386Sopenharmony_ci    return true;
173cb93a386Sopenharmony_ci}
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_cibool GrStyle::applyToPath(SkPath* dst, SkStrokeRec::InitStyle* style, const SkPath& src,
176cb93a386Sopenharmony_ci                          SkScalar resScale) const {
177cb93a386Sopenharmony_ci    SkASSERT(style);
178cb93a386Sopenharmony_ci    SkASSERT(dst);
179cb93a386Sopenharmony_ci    SkStrokeRec strokeRec = fStrokeRec;
180cb93a386Sopenharmony_ci    strokeRec.setResScale(resScale);
181cb93a386Sopenharmony_ci    const SkPath* pathForStrokeRec = &src;
182cb93a386Sopenharmony_ci    if (this->applyPathEffect(dst, &strokeRec, src)) {
183cb93a386Sopenharmony_ci        pathForStrokeRec = dst;
184cb93a386Sopenharmony_ci    } else if (fPathEffect) {
185cb93a386Sopenharmony_ci        return false;
186cb93a386Sopenharmony_ci    }
187cb93a386Sopenharmony_ci    if (strokeRec.needToApply()) {
188cb93a386Sopenharmony_ci        if (!strokeRec.applyToPath(dst, *pathForStrokeRec)) {
189cb93a386Sopenharmony_ci            return false;
190cb93a386Sopenharmony_ci        }
191cb93a386Sopenharmony_ci        dst->setIsVolatile(true);
192cb93a386Sopenharmony_ci        *style = SkStrokeRec::kFill_InitStyle;
193cb93a386Sopenharmony_ci    } else if (!fPathEffect) {
194cb93a386Sopenharmony_ci        // Nothing to do for path effect or stroke, fail.
195cb93a386Sopenharmony_ci        return false;
196cb93a386Sopenharmony_ci    } else {
197cb93a386Sopenharmony_ci        SkASSERT(SkStrokeRec::kFill_Style == strokeRec.getStyle() ||
198cb93a386Sopenharmony_ci                 SkStrokeRec::kHairline_Style == strokeRec.getStyle());
199cb93a386Sopenharmony_ci        *style = strokeRec.getStyle() == SkStrokeRec::kFill_Style
200cb93a386Sopenharmony_ci                 ? SkStrokeRec::kFill_InitStyle
201cb93a386Sopenharmony_ci                 : SkStrokeRec::kHairline_InitStyle;
202cb93a386Sopenharmony_ci    }
203cb93a386Sopenharmony_ci    return true;
204cb93a386Sopenharmony_ci}
205