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/geometry/GrStyledShape.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/private/SkIDChangeListener.h"
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_ci#include <utility>
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ciGrStyledShape& GrStyledShape::operator=(const GrStyledShape& that) {
15cb93a386Sopenharmony_ci    fShape      = that.fShape;
16cb93a386Sopenharmony_ci    fStyle      = that.fStyle;
17cb93a386Sopenharmony_ci    fGenID      = that.fGenID;
18cb93a386Sopenharmony_ci    fSimplified = that.fSimplified;
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci    fInheritedKey.reset(that.fInheritedKey.count());
21cb93a386Sopenharmony_ci    sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
22cb93a386Sopenharmony_ci                      sizeof(uint32_t) * fInheritedKey.count());
23cb93a386Sopenharmony_ci    if (that.fInheritedPathForListeners.isValid()) {
24cb93a386Sopenharmony_ci        fInheritedPathForListeners.set(*that.fInheritedPathForListeners);
25cb93a386Sopenharmony_ci    } else {
26cb93a386Sopenharmony_ci        fInheritedPathForListeners.reset();
27cb93a386Sopenharmony_ci    }
28cb93a386Sopenharmony_ci    return *this;
29cb93a386Sopenharmony_ci}
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cistatic bool is_inverted(bool originalIsInverted, GrStyledShape::FillInversion inversion) {
32cb93a386Sopenharmony_ci    switch (inversion) {
33cb93a386Sopenharmony_ci        case GrStyledShape::FillInversion::kPreserve:
34cb93a386Sopenharmony_ci            return originalIsInverted;
35cb93a386Sopenharmony_ci        case GrStyledShape::FillInversion::kFlip:
36cb93a386Sopenharmony_ci            return !originalIsInverted;
37cb93a386Sopenharmony_ci        case GrStyledShape::FillInversion::kForceInverted:
38cb93a386Sopenharmony_ci            return true;
39cb93a386Sopenharmony_ci        case GrStyledShape::FillInversion::kForceNoninverted:
40cb93a386Sopenharmony_ci            return false;
41cb93a386Sopenharmony_ci    }
42cb93a386Sopenharmony_ci    return false;
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ciGrStyledShape GrStyledShape::MakeFilled(const GrStyledShape& original, FillInversion inversion) {
46cb93a386Sopenharmony_ci    bool newIsInverted = is_inverted(original.fShape.inverted(), inversion);
47cb93a386Sopenharmony_ci    if (original.style().isSimpleFill() && newIsInverted == original.fShape.inverted()) {
48cb93a386Sopenharmony_ci        // By returning the original rather than falling through we can preserve any inherited style
49cb93a386Sopenharmony_ci        // key. Otherwise, we wipe it out below since the style change invalidates it.
50cb93a386Sopenharmony_ci        return original;
51cb93a386Sopenharmony_ci    }
52cb93a386Sopenharmony_ci    GrStyledShape result;
53cb93a386Sopenharmony_ci    SkASSERT(result.fStyle.isSimpleFill());
54cb93a386Sopenharmony_ci    if (original.fInheritedPathForListeners.isValid()) {
55cb93a386Sopenharmony_ci        result.fInheritedPathForListeners.set(*original.fInheritedPathForListeners);
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    result.fShape = original.fShape;
59cb93a386Sopenharmony_ci    result.fGenID = original.fGenID;
60cb93a386Sopenharmony_ci    result.fShape.setInverted(newIsInverted);
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    if (!original.style().isSimpleFill()) {
63cb93a386Sopenharmony_ci        // Going from a non-filled style to fill may allow additional simplifications (e.g.
64cb93a386Sopenharmony_ci        // closing an open rect that wasn't closed in the original shape because it had
65cb93a386Sopenharmony_ci        // stroke style).
66cb93a386Sopenharmony_ci        result.simplify();
67cb93a386Sopenharmony_ci        // The above simplify() call only sets simplified to true if its geometry was changed,
68cb93a386Sopenharmony_ci        // since it already sees its style as a simple fill. Since the original style was not a
69cb93a386Sopenharmony_ci        // simple fill, MakeFilled always simplifies.
70cb93a386Sopenharmony_ci        result.fSimplified = true;
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ci    // Verify that lines/points were converted to empty by the style change
74cb93a386Sopenharmony_ci    SkASSERT((!original.fShape.isLine() && !original.fShape.isPoint()) || result.fShape.isEmpty());
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    // We don't copy the inherited key since it can contain path effect information that we just
77cb93a386Sopenharmony_ci    // stripped.
78cb93a386Sopenharmony_ci    return result;
79cb93a386Sopenharmony_ci}
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ciSkRect GrStyledShape::styledBounds() const {
82cb93a386Sopenharmony_ci    if (this->isEmpty() && !fStyle.hasNonDashPathEffect()) {
83cb93a386Sopenharmony_ci        return SkRect::MakeEmpty();
84cb93a386Sopenharmony_ci    }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    SkRect bounds;
87cb93a386Sopenharmony_ci    fStyle.adjustBounds(&bounds, this->bounds());
88cb93a386Sopenharmony_ci    return bounds;
89cb93a386Sopenharmony_ci}
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci// If the path is small enough to be keyed from its data this returns key length, otherwise -1.
92cb93a386Sopenharmony_cistatic int path_key_from_data_size(const SkPath& path) {
93cb93a386Sopenharmony_ci    const int verbCnt = path.countVerbs();
94cb93a386Sopenharmony_ci    if (verbCnt > GrStyledShape::kMaxKeyFromDataVerbCnt) {
95cb93a386Sopenharmony_ci        return -1;
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci    const int pointCnt = path.countPoints();
98cb93a386Sopenharmony_ci    const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci    static_assert(sizeof(SkPoint) == 2 * sizeof(uint32_t));
101cb93a386Sopenharmony_ci    static_assert(sizeof(SkScalar) == sizeof(uint32_t));
102cb93a386Sopenharmony_ci    // 1 is for the verb count. Each verb is a byte but we'll pad the verb data out to
103cb93a386Sopenharmony_ci    // a uint32_t length.
104cb93a386Sopenharmony_ci    return 1 + (SkAlign4(verbCnt) >> 2) + 2 * pointCnt + conicWeightCnt;
105cb93a386Sopenharmony_ci}
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci// Writes the path data key into the passed pointer.
108cb93a386Sopenharmony_cistatic void write_path_key_from_data(const SkPath& path, uint32_t* origKey) {
109cb93a386Sopenharmony_ci    uint32_t* key = origKey;
110cb93a386Sopenharmony_ci    // The check below should take care of negative values casted positive.
111cb93a386Sopenharmony_ci    const int verbCnt = path.countVerbs();
112cb93a386Sopenharmony_ci    const int pointCnt = path.countPoints();
113cb93a386Sopenharmony_ci    const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
114cb93a386Sopenharmony_ci    SkASSERT(verbCnt <= GrStyledShape::kMaxKeyFromDataVerbCnt);
115cb93a386Sopenharmony_ci    SkASSERT(pointCnt && verbCnt);
116cb93a386Sopenharmony_ci    *key++ = verbCnt;
117cb93a386Sopenharmony_ci    memcpy(key, SkPathPriv::VerbData(path), verbCnt * sizeof(uint8_t));
118cb93a386Sopenharmony_ci    int verbKeySize = SkAlign4(verbCnt);
119cb93a386Sopenharmony_ci    // pad out to uint32_t alignment using value that will stand out when debugging.
120cb93a386Sopenharmony_ci    uint8_t* pad = reinterpret_cast<uint8_t*>(key)+ verbCnt;
121cb93a386Sopenharmony_ci    memset(pad, 0xDE, verbKeySize - verbCnt);
122cb93a386Sopenharmony_ci    key += verbKeySize >> 2;
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci    memcpy(key, SkPathPriv::PointData(path), sizeof(SkPoint) * pointCnt);
125cb93a386Sopenharmony_ci    static_assert(sizeof(SkPoint) == 2 * sizeof(uint32_t));
126cb93a386Sopenharmony_ci    key += 2 * pointCnt;
127cb93a386Sopenharmony_ci    sk_careful_memcpy(key, SkPathPriv::ConicWeightData(path), sizeof(SkScalar) * conicWeightCnt);
128cb93a386Sopenharmony_ci    static_assert(sizeof(SkScalar) == sizeof(uint32_t));
129cb93a386Sopenharmony_ci    SkDEBUGCODE(key += conicWeightCnt);
130cb93a386Sopenharmony_ci    SkASSERT(key - origKey == path_key_from_data_size(path));
131cb93a386Sopenharmony_ci}
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ciint GrStyledShape::unstyledKeySize() const {
134cb93a386Sopenharmony_ci    if (fInheritedKey.count()) {
135cb93a386Sopenharmony_ci        return fInheritedKey.count();
136cb93a386Sopenharmony_ci    }
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci    int count = 1; // Every key has the state flags from the GrShape
139cb93a386Sopenharmony_ci    switch(fShape.type()) {
140cb93a386Sopenharmony_ci        case GrShape::Type::kPoint:
141cb93a386Sopenharmony_ci            static_assert(0 == sizeof(SkPoint) % sizeof(uint32_t));
142cb93a386Sopenharmony_ci            count += sizeof(SkPoint) / sizeof(uint32_t);
143cb93a386Sopenharmony_ci            break;
144cb93a386Sopenharmony_ci        case GrShape::Type::kRect:
145cb93a386Sopenharmony_ci            static_assert(0 == sizeof(SkRect) % sizeof(uint32_t));
146cb93a386Sopenharmony_ci            count += sizeof(SkRect) / sizeof(uint32_t);
147cb93a386Sopenharmony_ci            break;
148cb93a386Sopenharmony_ci        case GrShape::Type::kRRect:
149cb93a386Sopenharmony_ci            static_assert(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
150cb93a386Sopenharmony_ci            count += SkRRect::kSizeInMemory / sizeof(uint32_t);
151cb93a386Sopenharmony_ci            break;
152cb93a386Sopenharmony_ci        case GrShape::Type::kArc:
153cb93a386Sopenharmony_ci            static_assert(0 == sizeof(GrArc) % sizeof(uint32_t));
154cb93a386Sopenharmony_ci            count += sizeof(GrArc) / sizeof(uint32_t);
155cb93a386Sopenharmony_ci            break;
156cb93a386Sopenharmony_ci        case GrShape::Type::kLine:
157cb93a386Sopenharmony_ci            static_assert(0 == sizeof(GrLineSegment) % sizeof(uint32_t));
158cb93a386Sopenharmony_ci            count += sizeof(GrLineSegment) / sizeof(uint32_t);
159cb93a386Sopenharmony_ci            break;
160cb93a386Sopenharmony_ci        case GrShape::Type::kPath: {
161cb93a386Sopenharmony_ci            if (0 == fGenID) {
162cb93a386Sopenharmony_ci                return -1; // volatile, so won't be keyed
163cb93a386Sopenharmony_ci            }
164cb93a386Sopenharmony_ci            int dataKeySize = path_key_from_data_size(fShape.path());
165cb93a386Sopenharmony_ci            if (dataKeySize >= 0) {
166cb93a386Sopenharmony_ci                count += dataKeySize;
167cb93a386Sopenharmony_ci            } else {
168cb93a386Sopenharmony_ci                count++; // Just adds the gen ID.
169cb93a386Sopenharmony_ci            }
170cb93a386Sopenharmony_ci            break; }
171cb93a386Sopenharmony_ci        default:
172cb93a386Sopenharmony_ci            // else it's empty, which just needs the state flags for its key
173cb93a386Sopenharmony_ci            SkASSERT(fShape.isEmpty());
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci    return count;
176cb93a386Sopenharmony_ci}
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_civoid GrStyledShape::writeUnstyledKey(uint32_t* key) const {
179cb93a386Sopenharmony_ci    SkASSERT(this->unstyledKeySize());
180cb93a386Sopenharmony_ci    SkDEBUGCODE(uint32_t* origKey = key;)
181cb93a386Sopenharmony_ci    if (fInheritedKey.count()) {
182cb93a386Sopenharmony_ci        memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count());
183cb93a386Sopenharmony_ci        SkDEBUGCODE(key += fInheritedKey.count();)
184cb93a386Sopenharmony_ci    } else {
185cb93a386Sopenharmony_ci        // Dir and start are only used for rect and rrect shapes, so are not included in other
186cb93a386Sopenharmony_ci        // shape type keys. Make sure that they are the defaults for other shapes so it doesn't
187cb93a386Sopenharmony_ci        // matter that we universally include them in the flag key value.
188cb93a386Sopenharmony_ci        SkASSERT((fShape.isRect() || fShape.isRRect()) ||
189cb93a386Sopenharmony_ci                 (fShape.dir() == GrShape::kDefaultDir &&
190cb93a386Sopenharmony_ci                  fShape.startIndex() == GrShape::kDefaultStart));
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci        // Every key starts with the state from the GrShape (this includes path fill type,
193cb93a386Sopenharmony_ci        // and any tracked winding, start, inversion, as well as the class of geometry).
194cb93a386Sopenharmony_ci        *key++ = fShape.stateKey();
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci        switch(fShape.type()) {
197cb93a386Sopenharmony_ci            case GrShape::Type::kPath: {
198cb93a386Sopenharmony_ci                SkASSERT(fGenID != 0);
199cb93a386Sopenharmony_ci                // Ensure that the path's inversion matches our state so that the path's key suffices.
200cb93a386Sopenharmony_ci                SkASSERT(fShape.inverted() == fShape.path().isInverseFillType());
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci                int dataKeySize = path_key_from_data_size(fShape.path());
203cb93a386Sopenharmony_ci                if (dataKeySize >= 0) {
204cb93a386Sopenharmony_ci                    write_path_key_from_data(fShape.path(), key);
205cb93a386Sopenharmony_ci                    return;
206cb93a386Sopenharmony_ci                } else {
207cb93a386Sopenharmony_ci                    *key++ = fGenID;
208cb93a386Sopenharmony_ci                }
209cb93a386Sopenharmony_ci                break; }
210cb93a386Sopenharmony_ci            case GrShape::Type::kPoint:
211cb93a386Sopenharmony_ci                memcpy(key, &fShape.point(), sizeof(SkPoint));
212cb93a386Sopenharmony_ci                key += sizeof(SkPoint) / sizeof(uint32_t);
213cb93a386Sopenharmony_ci                break;
214cb93a386Sopenharmony_ci            case GrShape::Type::kRect:
215cb93a386Sopenharmony_ci                memcpy(key, &fShape.rect(), sizeof(SkRect));
216cb93a386Sopenharmony_ci                key += sizeof(SkRect) / sizeof(uint32_t);
217cb93a386Sopenharmony_ci                break;
218cb93a386Sopenharmony_ci            case GrShape::Type::kRRect:
219cb93a386Sopenharmony_ci                fShape.rrect().writeToMemory(key);
220cb93a386Sopenharmony_ci                key += SkRRect::kSizeInMemory / sizeof(uint32_t);
221cb93a386Sopenharmony_ci                break;
222cb93a386Sopenharmony_ci            case GrShape::Type::kArc:
223cb93a386Sopenharmony_ci                // Write dense floats first
224cb93a386Sopenharmony_ci                memcpy(key, &fShape.arc(), sizeof(SkRect) + 2 * sizeof(float));
225cb93a386Sopenharmony_ci                key += (sizeof(GrArc) / sizeof(uint32_t) - 1);
226cb93a386Sopenharmony_ci                // Then write the final bool as an int, to make sure upper bits are set
227cb93a386Sopenharmony_ci                *key++ = fShape.arc().fUseCenter ? 1 : 0;
228cb93a386Sopenharmony_ci                break;
229cb93a386Sopenharmony_ci            case GrShape::Type::kLine:
230cb93a386Sopenharmony_ci                memcpy(key, &fShape.line(), sizeof(GrLineSegment));
231cb93a386Sopenharmony_ci                key += sizeof(GrLineSegment) / sizeof(uint32_t);
232cb93a386Sopenharmony_ci                break;
233cb93a386Sopenharmony_ci            default:
234cb93a386Sopenharmony_ci                // Nothing other than the flag state is needed in the key for an empty shape
235cb93a386Sopenharmony_ci                SkASSERT(fShape.isEmpty());
236cb93a386Sopenharmony_ci        }
237cb93a386Sopenharmony_ci    }
238cb93a386Sopenharmony_ci    SkASSERT(key - origKey == this->unstyledKeySize());
239cb93a386Sopenharmony_ci}
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_civoid GrStyledShape::setInheritedKey(const GrStyledShape &parent, GrStyle::Apply apply,
242cb93a386Sopenharmony_ci                                    SkScalar scale) {
243cb93a386Sopenharmony_ci    SkASSERT(!fInheritedKey.count());
244cb93a386Sopenharmony_ci    // If the output shape turns out to be simple, then we will just use its geometric key
245cb93a386Sopenharmony_ci    if (fShape.isPath()) {
246cb93a386Sopenharmony_ci        // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key as
247cb93a386Sopenharmony_ci        // ApplyFullStyle(shape).
248cb93a386Sopenharmony_ci        // The full key is structured as (geo,path_effect,stroke).
249cb93a386Sopenharmony_ci        // If we do ApplyPathEffect we get geo,path_effect as the inherited key. If we then
250cb93a386Sopenharmony_ci        // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited key
251cb93a386Sopenharmony_ci        // and then append the style key (which should now be stroke only) at the end.
252cb93a386Sopenharmony_ci        int parentCnt = parent.fInheritedKey.count();
253cb93a386Sopenharmony_ci        bool useParentGeoKey = !parentCnt;
254cb93a386Sopenharmony_ci        if (useParentGeoKey) {
255cb93a386Sopenharmony_ci            parentCnt = parent.unstyledKeySize();
256cb93a386Sopenharmony_ci            if (parentCnt < 0) {
257cb93a386Sopenharmony_ci                // The parent's geometry has no key so we will have no key.
258cb93a386Sopenharmony_ci                fGenID = 0;
259cb93a386Sopenharmony_ci                return;
260cb93a386Sopenharmony_ci            }
261cb93a386Sopenharmony_ci        }
262cb93a386Sopenharmony_ci        uint32_t styleKeyFlags = 0;
263cb93a386Sopenharmony_ci        if (parent.knownToBeClosed()) {
264cb93a386Sopenharmony_ci            styleKeyFlags |= GrStyle::kClosed_KeyFlag;
265cb93a386Sopenharmony_ci        }
266cb93a386Sopenharmony_ci        if (parent.asLine(nullptr, nullptr)) {
267cb93a386Sopenharmony_ci            styleKeyFlags |= GrStyle::kNoJoins_KeyFlag;
268cb93a386Sopenharmony_ci        }
269cb93a386Sopenharmony_ci        int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags);
270cb93a386Sopenharmony_ci        if (styleCnt < 0) {
271cb93a386Sopenharmony_ci            // The style doesn't allow a key, set the path gen ID to 0 so that we fail when
272cb93a386Sopenharmony_ci            // we try to get a key for the shape.
273cb93a386Sopenharmony_ci            fGenID = 0;
274cb93a386Sopenharmony_ci            return;
275cb93a386Sopenharmony_ci        }
276cb93a386Sopenharmony_ci        fInheritedKey.reset(parentCnt + styleCnt);
277cb93a386Sopenharmony_ci        if (useParentGeoKey) {
278cb93a386Sopenharmony_ci            // This will be the geo key.
279cb93a386Sopenharmony_ci            parent.writeUnstyledKey(fInheritedKey.get());
280cb93a386Sopenharmony_ci        } else {
281cb93a386Sopenharmony_ci            // This should be (geo,path_effect).
282cb93a386Sopenharmony_ci            memcpy(fInheritedKey.get(), parent.fInheritedKey.get(),
283cb93a386Sopenharmony_ci                   parentCnt * sizeof(uint32_t));
284cb93a386Sopenharmony_ci        }
285cb93a386Sopenharmony_ci        // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke)
286cb93a386Sopenharmony_ci        GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply, scale,
287cb93a386Sopenharmony_ci                          styleKeyFlags);
288cb93a386Sopenharmony_ci    }
289cb93a386Sopenharmony_ci}
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_ciconst SkPath* GrStyledShape::originalPathForListeners() const {
292cb93a386Sopenharmony_ci    if (fInheritedPathForListeners.isValid()) {
293cb93a386Sopenharmony_ci        return fInheritedPathForListeners.get();
294cb93a386Sopenharmony_ci    } else if (fShape.isPath() && !fShape.path().isVolatile()) {
295cb93a386Sopenharmony_ci        return &fShape.path();
296cb93a386Sopenharmony_ci    }
297cb93a386Sopenharmony_ci    return nullptr;
298cb93a386Sopenharmony_ci}
299cb93a386Sopenharmony_ci
300cb93a386Sopenharmony_civoid GrStyledShape::addGenIDChangeListener(sk_sp<SkIDChangeListener> listener) const {
301cb93a386Sopenharmony_ci    if (const auto* lp = this->originalPathForListeners()) {
302cb93a386Sopenharmony_ci        SkPathPriv::AddGenIDChangeListener(*lp, std::move(listener));
303cb93a386Sopenharmony_ci    }
304cb93a386Sopenharmony_ci}
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ciGrStyledShape GrStyledShape::MakeArc(const SkRect& oval, SkScalar startAngleDegrees,
307cb93a386Sopenharmony_ci                                     SkScalar sweepAngleDegrees, bool useCenter,
308cb93a386Sopenharmony_ci                                     const GrStyle& style, DoSimplify doSimplify) {
309cb93a386Sopenharmony_ci    GrStyledShape result;
310cb93a386Sopenharmony_ci    result.fShape.setArc({oval.makeSorted(), startAngleDegrees, sweepAngleDegrees, useCenter});
311cb93a386Sopenharmony_ci    result.fStyle = style;
312cb93a386Sopenharmony_ci    if (doSimplify == DoSimplify::kYes) {
313cb93a386Sopenharmony_ci        result.simplify();
314cb93a386Sopenharmony_ci    }
315cb93a386Sopenharmony_ci    return result;
316cb93a386Sopenharmony_ci}
317cb93a386Sopenharmony_ci
318cb93a386Sopenharmony_ciGrStyledShape::GrStyledShape(const GrStyledShape& that)
319cb93a386Sopenharmony_ci        : fShape(that.fShape)
320cb93a386Sopenharmony_ci        , fStyle(that.fStyle)
321cb93a386Sopenharmony_ci        , fGenID(that.fGenID)
322cb93a386Sopenharmony_ci        , fSimplified(that.fSimplified) {
323cb93a386Sopenharmony_ci    fInheritedKey.reset(that.fInheritedKey.count());
324cb93a386Sopenharmony_ci    sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
325cb93a386Sopenharmony_ci                      sizeof(uint32_t) * fInheritedKey.count());
326cb93a386Sopenharmony_ci    if (that.fInheritedPathForListeners.isValid()) {
327cb93a386Sopenharmony_ci        fInheritedPathForListeners.set(*that.fInheritedPathForListeners);
328cb93a386Sopenharmony_ci    }
329cb93a386Sopenharmony_ci}
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ciGrStyledShape::GrStyledShape(const GrStyledShape& parent, GrStyle::Apply apply, SkScalar scale) {
332cb93a386Sopenharmony_ci    // TODO: Add some quantization of scale for better cache performance here or leave that up
333cb93a386Sopenharmony_ci    // to caller?
334cb93a386Sopenharmony_ci    // TODO: For certain shapes and stroke params we could ignore the scale. (e.g. miter or bevel
335cb93a386Sopenharmony_ci    // stroke of a rect).
336cb93a386Sopenharmony_ci    if (!parent.style().applies() ||
337cb93a386Sopenharmony_ci        (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect())) {
338cb93a386Sopenharmony_ci        *this = parent;
339cb93a386Sopenharmony_ci        return;
340cb93a386Sopenharmony_ci    }
341cb93a386Sopenharmony_ci
342cb93a386Sopenharmony_ci    SkPathEffect* pe = parent.fStyle.pathEffect();
343cb93a386Sopenharmony_ci    SkTLazy<SkPath> tmpPath;
344cb93a386Sopenharmony_ci    const GrStyledShape* parentForKey = &parent;
345cb93a386Sopenharmony_ci    SkTLazy<GrStyledShape> tmpParent;
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci    // Start out as an empty path that is filled in by the applied style
348cb93a386Sopenharmony_ci    fShape.setPath(SkPath());
349cb93a386Sopenharmony_ci
350cb93a386Sopenharmony_ci    if (pe) {
351cb93a386Sopenharmony_ci        const SkPath* srcForPathEffect;
352cb93a386Sopenharmony_ci        if (parent.fShape.isPath()) {
353cb93a386Sopenharmony_ci            srcForPathEffect = &parent.fShape.path();
354cb93a386Sopenharmony_ci        } else {
355cb93a386Sopenharmony_ci            srcForPathEffect = tmpPath.init();
356cb93a386Sopenharmony_ci            parent.asPath(tmpPath.get());
357cb93a386Sopenharmony_ci        }
358cb93a386Sopenharmony_ci        // Should we consider bounds? Would have to include in key, but it'd be nice to know
359cb93a386Sopenharmony_ci        // if the bounds actually modified anything before including in key.
360cb93a386Sopenharmony_ci        SkStrokeRec strokeRec = parent.fStyle.strokeRec();
361cb93a386Sopenharmony_ci        if (!parent.fStyle.applyPathEffectToPath(&fShape.path(), &strokeRec, *srcForPathEffect,
362cb93a386Sopenharmony_ci                                                 scale)) {
363cb93a386Sopenharmony_ci            tmpParent.init(*srcForPathEffect, GrStyle(strokeRec, nullptr));
364cb93a386Sopenharmony_ci            *this = tmpParent->applyStyle(apply, scale);
365cb93a386Sopenharmony_ci            return;
366cb93a386Sopenharmony_ci        }
367cb93a386Sopenharmony_ci        // A path effect has access to change the res scale but we aren't expecting it to and it
368cb93a386Sopenharmony_ci        // would mess up our key computation.
369cb93a386Sopenharmony_ci        SkASSERT(scale == strokeRec.getResScale());
370cb93a386Sopenharmony_ci        if (GrStyle::Apply::kPathEffectAndStrokeRec == apply && strokeRec.needToApply()) {
371cb93a386Sopenharmony_ci            // The intermediate shape may not be a general path. If we we're just applying
372cb93a386Sopenharmony_ci            // the path effect then attemptToReduceFromPath would catch it. This means that
373cb93a386Sopenharmony_ci            // when we subsequently applied the remaining strokeRec we would have a non-path
374cb93a386Sopenharmony_ci            // parent shape that would be used to determine the the stroked path's key.
375cb93a386Sopenharmony_ci            // We detect that case here and change parentForKey to a temporary that represents
376cb93a386Sopenharmony_ci            // the simpler shape so that applying both path effect and the strokerec all at
377cb93a386Sopenharmony_ci            // once produces the same key.
378cb93a386Sopenharmony_ci            tmpParent.init(fShape.path(), GrStyle(strokeRec, nullptr));
379cb93a386Sopenharmony_ci            tmpParent->setInheritedKey(parent, GrStyle::Apply::kPathEffectOnly, scale);
380cb93a386Sopenharmony_ci            if (!tmpPath.isValid()) {
381cb93a386Sopenharmony_ci                tmpPath.init();
382cb93a386Sopenharmony_ci            }
383cb93a386Sopenharmony_ci            tmpParent->asPath(tmpPath.get());
384cb93a386Sopenharmony_ci            SkStrokeRec::InitStyle fillOrHairline;
385cb93a386Sopenharmony_ci            // The parent shape may have simplified away the strokeRec, check for that here.
386cb93a386Sopenharmony_ci            if (tmpParent->style().applies()) {
387cb93a386Sopenharmony_ci                SkAssertResult(tmpParent.get()->style().applyToPath(&fShape.path(), &fillOrHairline,
388cb93a386Sopenharmony_ci                                                                    *tmpPath.get(), scale));
389cb93a386Sopenharmony_ci            } else if (tmpParent->style().isSimpleFill()) {
390cb93a386Sopenharmony_ci                fillOrHairline = SkStrokeRec::kFill_InitStyle;
391cb93a386Sopenharmony_ci            } else {
392cb93a386Sopenharmony_ci                SkASSERT(tmpParent.get()->style().isSimpleHairline());
393cb93a386Sopenharmony_ci                fillOrHairline = SkStrokeRec::kHairline_InitStyle;
394cb93a386Sopenharmony_ci            }
395cb93a386Sopenharmony_ci            fStyle.resetToInitStyle(fillOrHairline);
396cb93a386Sopenharmony_ci            parentForKey = tmpParent.get();
397cb93a386Sopenharmony_ci        } else {
398cb93a386Sopenharmony_ci            fStyle = GrStyle(strokeRec, nullptr);
399cb93a386Sopenharmony_ci        }
400cb93a386Sopenharmony_ci    } else {
401cb93a386Sopenharmony_ci        const SkPath* srcForParentStyle;
402cb93a386Sopenharmony_ci        if (parent.fShape.isPath()) {
403cb93a386Sopenharmony_ci            srcForParentStyle = &parent.fShape.path();
404cb93a386Sopenharmony_ci        } else {
405cb93a386Sopenharmony_ci            srcForParentStyle = tmpPath.init();
406cb93a386Sopenharmony_ci            parent.asPath(tmpPath.get());
407cb93a386Sopenharmony_ci        }
408cb93a386Sopenharmony_ci        SkStrokeRec::InitStyle fillOrHairline;
409cb93a386Sopenharmony_ci        SkASSERT(parent.fStyle.applies());
410cb93a386Sopenharmony_ci        SkASSERT(!parent.fStyle.pathEffect());
411cb93a386Sopenharmony_ci        SkAssertResult(parent.fStyle.applyToPath(&fShape.path(), &fillOrHairline,
412cb93a386Sopenharmony_ci                                                 *srcForParentStyle, scale));
413cb93a386Sopenharmony_ci        fStyle.resetToInitStyle(fillOrHairline);
414cb93a386Sopenharmony_ci    }
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci    if (parent.fInheritedPathForListeners.isValid()) {
417cb93a386Sopenharmony_ci        fInheritedPathForListeners.set(*parent.fInheritedPathForListeners);
418cb93a386Sopenharmony_ci    } else if (parent.fShape.isPath() && !parent.fShape.path().isVolatile()) {
419cb93a386Sopenharmony_ci        fInheritedPathForListeners.set(parent.fShape.path());
420cb93a386Sopenharmony_ci    }
421cb93a386Sopenharmony_ci    this->simplify();
422cb93a386Sopenharmony_ci    this->setInheritedKey(*parentForKey, apply, scale);
423cb93a386Sopenharmony_ci}
424cb93a386Sopenharmony_ci
425cb93a386Sopenharmony_cibool GrStyledShape::asRRect(SkRRect* rrect, SkPathDirection* dir, unsigned* start,
426cb93a386Sopenharmony_ci                            bool* inverted) const {
427cb93a386Sopenharmony_ci    if (!fShape.isRRect() && !fShape.isRect()) {
428cb93a386Sopenharmony_ci        return false;
429cb93a386Sopenharmony_ci    }
430cb93a386Sopenharmony_ci
431cb93a386Sopenharmony_ci    // Validity check here, if we don't have a path effect on the style, we should have passed
432cb93a386Sopenharmony_ci    // appropriate flags to GrShape::simplify() to have reset these parameters.
433cb93a386Sopenharmony_ci    SkASSERT(fStyle.hasPathEffect() || (fShape.dir() == GrShape::kDefaultDir &&
434cb93a386Sopenharmony_ci                                        fShape.startIndex() == GrShape::kDefaultStart));
435cb93a386Sopenharmony_ci
436cb93a386Sopenharmony_ci    // If the shape is a regular rect, map to round rect winding parameters, including accounting
437cb93a386Sopenharmony_ci    // for the automatic sorting of edges that SkRRect::MakeRect() performs.
438cb93a386Sopenharmony_ci    if (fShape.isRect()) {
439cb93a386Sopenharmony_ci        if (rrect) {
440cb93a386Sopenharmony_ci            *rrect = SkRRect::MakeRect(fShape.rect());
441cb93a386Sopenharmony_ci        }
442cb93a386Sopenharmony_ci        // Don't bother mapping these if we don't have a path effect, however.
443cb93a386Sopenharmony_ci        if (!fStyle.hasPathEffect()) {
444cb93a386Sopenharmony_ci            if (dir) {
445cb93a386Sopenharmony_ci                *dir = GrShape::kDefaultDir;
446cb93a386Sopenharmony_ci            }
447cb93a386Sopenharmony_ci            if (start) {
448cb93a386Sopenharmony_ci                *start = GrShape::kDefaultStart;
449cb93a386Sopenharmony_ci            }
450cb93a386Sopenharmony_ci        } else {
451cb93a386Sopenharmony_ci            // In SkPath a rect starts at index 0 by default. This is the top left corner. However,
452cb93a386Sopenharmony_ci            // we store rects as rrects. RRects don't preserve the invertedness, but rather sort the
453cb93a386Sopenharmony_ci            // rect edges. Thus, we may need to modify the rrect's start index and direction.
454cb93a386Sopenharmony_ci            SkPathDirection rectDir = fShape.dir();
455cb93a386Sopenharmony_ci            unsigned rectStart = fShape.startIndex();
456cb93a386Sopenharmony_ci
457cb93a386Sopenharmony_ci            if (fShape.rect().fLeft > fShape.rect().fRight) {
458cb93a386Sopenharmony_ci                // Toggle direction, and modify index by mapping through the array
459cb93a386Sopenharmony_ci                static const unsigned kMapping[] = {1, 0, 3, 2};
460cb93a386Sopenharmony_ci                rectDir = rectDir == SkPathDirection::kCCW ? SkPathDirection::kCW
461cb93a386Sopenharmony_ci                                                           : SkPathDirection::kCCW;
462cb93a386Sopenharmony_ci                rectStart = kMapping[rectStart];
463cb93a386Sopenharmony_ci            }
464cb93a386Sopenharmony_ci            if (fShape.rect().fTop > fShape.rect().fBottom) {
465cb93a386Sopenharmony_ci                // Toggle direction and map index by 3 - start
466cb93a386Sopenharmony_ci                // NOTE: if we earlier flipped for X as well, this results in no net direction
467cb93a386Sopenharmony_ci                // change and effectively flipping the start index to the diagonal corners of the
468cb93a386Sopenharmony_ci                // rect (matching what we'd expect for a rect with both X and Y flipped).
469cb93a386Sopenharmony_ci                rectDir = rectDir == SkPathDirection::kCCW ? SkPathDirection::kCW
470cb93a386Sopenharmony_ci                                                           : SkPathDirection::kCCW;
471cb93a386Sopenharmony_ci                rectStart = 3 - rectStart;
472cb93a386Sopenharmony_ci            }
473cb93a386Sopenharmony_ci
474cb93a386Sopenharmony_ci            if (dir) {
475cb93a386Sopenharmony_ci                *dir = rectDir;
476cb93a386Sopenharmony_ci            }
477cb93a386Sopenharmony_ci            if (start) {
478cb93a386Sopenharmony_ci                // Convert to round rect indexing
479cb93a386Sopenharmony_ci                *start = 2 * rectStart;
480cb93a386Sopenharmony_ci            }
481cb93a386Sopenharmony_ci        }
482cb93a386Sopenharmony_ci    } else {
483cb93a386Sopenharmony_ci        // Straight forward export
484cb93a386Sopenharmony_ci        if (rrect) {
485cb93a386Sopenharmony_ci            *rrect = fShape.rrect();
486cb93a386Sopenharmony_ci        }
487cb93a386Sopenharmony_ci        if (dir) {
488cb93a386Sopenharmony_ci            *dir = fShape.dir();
489cb93a386Sopenharmony_ci        }
490cb93a386Sopenharmony_ci        if (start) {
491cb93a386Sopenharmony_ci            *start = fShape.startIndex();
492cb93a386Sopenharmony_ci            // Canonicalize the index if the rrect is an oval, which GrShape doesn't treat special
493cb93a386Sopenharmony_ci            // but we do for dashing placement
494cb93a386Sopenharmony_ci            if (fShape.rrect().isOval()) {
495cb93a386Sopenharmony_ci                *start &= 0b110;
496cb93a386Sopenharmony_ci            }
497cb93a386Sopenharmony_ci        }
498cb93a386Sopenharmony_ci    }
499cb93a386Sopenharmony_ci
500cb93a386Sopenharmony_ci    if (inverted) {
501cb93a386Sopenharmony_ci        *inverted = fShape.inverted();
502cb93a386Sopenharmony_ci    }
503cb93a386Sopenharmony_ci
504cb93a386Sopenharmony_ci    return true;
505cb93a386Sopenharmony_ci}
506cb93a386Sopenharmony_ci
507cb93a386Sopenharmony_cibool GrStyledShape::asLine(SkPoint pts[2], bool* inverted) const {
508cb93a386Sopenharmony_ci    if (!fShape.isLine()) {
509cb93a386Sopenharmony_ci        return false;
510cb93a386Sopenharmony_ci    }
511cb93a386Sopenharmony_ci
512cb93a386Sopenharmony_ci    if (pts) {
513cb93a386Sopenharmony_ci        pts[0] = fShape.line().fP1;
514cb93a386Sopenharmony_ci        pts[1] = fShape.line().fP2;
515cb93a386Sopenharmony_ci    }
516cb93a386Sopenharmony_ci    if (inverted) {
517cb93a386Sopenharmony_ci        *inverted = fShape.inverted();
518cb93a386Sopenharmony_ci    }
519cb93a386Sopenharmony_ci    return true;
520cb93a386Sopenharmony_ci}
521cb93a386Sopenharmony_ci
522cb93a386Sopenharmony_cibool GrStyledShape::asNestedRects(SkRect rects[2]) const {
523cb93a386Sopenharmony_ci    if (!fShape.isPath()) {
524cb93a386Sopenharmony_ci        return false;
525cb93a386Sopenharmony_ci    }
526cb93a386Sopenharmony_ci
527cb93a386Sopenharmony_ci    // TODO: it would be better two store DRRects natively in the shape rather than converting
528cb93a386Sopenharmony_ci    // them to a path and then reextracting the nested rects
529cb93a386Sopenharmony_ci    if (fShape.path().isInverseFillType()) {
530cb93a386Sopenharmony_ci        return false;
531cb93a386Sopenharmony_ci    }
532cb93a386Sopenharmony_ci
533cb93a386Sopenharmony_ci    SkPathDirection dirs[2];
534cb93a386Sopenharmony_ci    if (!SkPathPriv::IsNestedFillRects(fShape.path(), rects, dirs)) {
535cb93a386Sopenharmony_ci        return false;
536cb93a386Sopenharmony_ci    }
537cb93a386Sopenharmony_ci
538cb93a386Sopenharmony_ci    if (SkPathFillType::kWinding == fShape.path().getFillType() && dirs[0] == dirs[1]) {
539cb93a386Sopenharmony_ci        // The two rects need to be wound opposite to each other
540cb93a386Sopenharmony_ci        return false;
541cb93a386Sopenharmony_ci    }
542cb93a386Sopenharmony_ci
543cb93a386Sopenharmony_ci    // Right now, nested rects where the margin is not the same width
544cb93a386Sopenharmony_ci    // all around do not render correctly
545cb93a386Sopenharmony_ci    const SkScalar* outer = rects[0].asScalars();
546cb93a386Sopenharmony_ci    const SkScalar* inner = rects[1].asScalars();
547cb93a386Sopenharmony_ci
548cb93a386Sopenharmony_ci    bool allEq = true;
549cb93a386Sopenharmony_ci
550cb93a386Sopenharmony_ci    SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
551cb93a386Sopenharmony_ci    bool allGoE1 = margin >= SK_Scalar1;
552cb93a386Sopenharmony_ci
553cb93a386Sopenharmony_ci    for (int i = 1; i < 4; ++i) {
554cb93a386Sopenharmony_ci        SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
555cb93a386Sopenharmony_ci        if (temp < SK_Scalar1) {
556cb93a386Sopenharmony_ci            allGoE1 = false;
557cb93a386Sopenharmony_ci        }
558cb93a386Sopenharmony_ci        if (!SkScalarNearlyEqual(margin, temp)) {
559cb93a386Sopenharmony_ci            allEq = false;
560cb93a386Sopenharmony_ci        }
561cb93a386Sopenharmony_ci    }
562cb93a386Sopenharmony_ci
563cb93a386Sopenharmony_ci    return allEq || allGoE1;
564cb93a386Sopenharmony_ci}
565cb93a386Sopenharmony_ci
566cb93a386Sopenharmony_ciclass AutoRestoreInverseness {
567cb93a386Sopenharmony_cipublic:
568cb93a386Sopenharmony_ci    AutoRestoreInverseness(GrShape* shape, const GrStyle& style)
569cb93a386Sopenharmony_ci            // Dashing ignores inverseness skbug.com/5421.
570cb93a386Sopenharmony_ci            : fShape(shape), fInverted(!style.isDashed() && fShape->inverted()) {}
571cb93a386Sopenharmony_ci
572cb93a386Sopenharmony_ci    ~AutoRestoreInverseness() {
573cb93a386Sopenharmony_ci        // Restore invertedness after any modifications were made to the shape type
574cb93a386Sopenharmony_ci        fShape->setInverted(fInverted);
575cb93a386Sopenharmony_ci        SkASSERT(!fShape->isPath() || fInverted == fShape->path().isInverseFillType());
576cb93a386Sopenharmony_ci    }
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_ciprivate:
579cb93a386Sopenharmony_ci    GrShape* fShape;
580cb93a386Sopenharmony_ci    bool fInverted;
581cb93a386Sopenharmony_ci};
582cb93a386Sopenharmony_ci
583cb93a386Sopenharmony_civoid GrStyledShape::simplify() {
584cb93a386Sopenharmony_ci    AutoRestoreInverseness ari(&fShape, fStyle);
585cb93a386Sopenharmony_ci
586cb93a386Sopenharmony_ci    unsigned simplifyFlags = 0;
587cb93a386Sopenharmony_ci    if (fStyle.isSimpleFill()) {
588cb93a386Sopenharmony_ci        simplifyFlags = GrShape::kAll_Flags;
589cb93a386Sopenharmony_ci    } else if (!fStyle.hasPathEffect()) {
590cb93a386Sopenharmony_ci        // Everything but arcs with caps that might extend beyond the oval edge can ignore winding
591cb93a386Sopenharmony_ci        if (!fShape.isArc() || fStyle.strokeRec().getCap() == SkPaint::kButt_Cap) {
592cb93a386Sopenharmony_ci            simplifyFlags |= GrShape::kIgnoreWinding_Flag;
593cb93a386Sopenharmony_ci        }
594cb93a386Sopenharmony_ci        simplifyFlags |= GrShape::kMakeCanonical_Flag;
595cb93a386Sopenharmony_ci    } // else if there's a path effect, every destructive simplification is disabledd
596cb93a386Sopenharmony_ci
597cb93a386Sopenharmony_ci    // Remember if the original shape was closed; in the event we simplify to a point or line
598cb93a386Sopenharmony_ci    // because of degenerate geometry, we need to update joins and caps.
599cb93a386Sopenharmony_ci    GrShape::Type oldType = fShape.type();
600cb93a386Sopenharmony_ci    fClosed = fShape.simplify(simplifyFlags);
601cb93a386Sopenharmony_ci    fSimplified = oldType != fShape.type();
602cb93a386Sopenharmony_ci
603cb93a386Sopenharmony_ci    if (fShape.isPath()) {
604cb93a386Sopenharmony_ci        // The shape remains a path, so configure the gen ID and canonicalize fill type if possible
605cb93a386Sopenharmony_ci        if (fInheritedKey.count() || fShape.path().isVolatile()) {
606cb93a386Sopenharmony_ci            fGenID = 0;
607cb93a386Sopenharmony_ci        } else {
608cb93a386Sopenharmony_ci            fGenID = fShape.path().getGenerationID();
609cb93a386Sopenharmony_ci        }
610cb93a386Sopenharmony_ci        if (!fStyle.hasNonDashPathEffect() &&
611cb93a386Sopenharmony_ci            (fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style ||
612cb93a386Sopenharmony_ci             fStyle.strokeRec().getStyle() == SkStrokeRec::kHairline_Style ||
613cb93a386Sopenharmony_ci             fShape.path().isConvex())) {
614cb93a386Sopenharmony_ci            // Stroke styles don't differentiate between winding and even/odd. There is no
615cb93a386Sopenharmony_ci            // distinction between even/odd and non-zero winding count for convex paths.
616cb93a386Sopenharmony_ci            // Moreover, dashing ignores inverseness (skbug.com/5421)
617cb93a386Sopenharmony_ci            fShape.path().setFillType(GrShape::kDefaultFillType);
618cb93a386Sopenharmony_ci        }
619cb93a386Sopenharmony_ci    } else {
620cb93a386Sopenharmony_ci        fInheritedKey.reset(0);
621cb93a386Sopenharmony_ci        // Whenever we simplify to a non-path, break the chain so we no longer refer to the
622cb93a386Sopenharmony_ci        // original path. This prevents attaching genID listeners to temporary paths created when
623cb93a386Sopenharmony_ci        // drawing simple shapes.
624cb93a386Sopenharmony_ci        fInheritedPathForListeners.reset();
625cb93a386Sopenharmony_ci        // Further simplifications to the shape based on the style
626cb93a386Sopenharmony_ci        this->simplifyStroke();
627cb93a386Sopenharmony_ci    }
628cb93a386Sopenharmony_ci}
629cb93a386Sopenharmony_ci
630cb93a386Sopenharmony_civoid GrStyledShape::simplifyStroke() {
631cb93a386Sopenharmony_ci    AutoRestoreInverseness ari(&fShape, fStyle);
632cb93a386Sopenharmony_ci
633cb93a386Sopenharmony_ci    // For stroke+filled rects, a mitered shape becomes a larger rect and a rounded shape
634cb93a386Sopenharmony_ci    // becomes a round rect.
635cb93a386Sopenharmony_ci    if (!fStyle.hasPathEffect() && fShape.isRect() &&
636cb93a386Sopenharmony_ci        fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
637cb93a386Sopenharmony_ci        if (fStyle.strokeRec().getJoin() == SkPaint::kBevel_Join ||
638cb93a386Sopenharmony_ci            (fStyle.strokeRec().getJoin() == SkPaint::kMiter_Join &&
639cb93a386Sopenharmony_ci             fStyle.strokeRec().getMiter() < SK_ScalarSqrt2)) {
640cb93a386Sopenharmony_ci            // Bevel-stroked rect needs path rendering
641cb93a386Sopenharmony_ci            return;
642cb93a386Sopenharmony_ci        }
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_ci        SkScalar r = fStyle.strokeRec().getWidth() / 2;
645cb93a386Sopenharmony_ci        fShape.rect().outset(r, r);
646cb93a386Sopenharmony_ci        if (fStyle.strokeRec().getJoin() == SkPaint::kRound_Join) {
647cb93a386Sopenharmony_ci            // There's no dashing to worry about if we got here, so it's okay that this resets
648cb93a386Sopenharmony_ci            // winding parameters
649cb93a386Sopenharmony_ci            fShape.setRRect(SkRRect::MakeRectXY(fShape.rect(), r, r));
650cb93a386Sopenharmony_ci        }
651cb93a386Sopenharmony_ci        fStyle = GrStyle::SimpleFill();
652cb93a386Sopenharmony_ci        fSimplified = true;
653cb93a386Sopenharmony_ci        return;
654cb93a386Sopenharmony_ci    }
655cb93a386Sopenharmony_ci
656cb93a386Sopenharmony_ci    // Otherwise, if we're a point or a line, we might be able to explicitly apply some of the
657cb93a386Sopenharmony_ci    // stroking (and even some of the dashing). Any other shape+style is too complicated to reduce.
658cb93a386Sopenharmony_ci    if ((!fShape.isPoint() && !fShape.isLine()) || fStyle.hasNonDashPathEffect() ||
659cb93a386Sopenharmony_ci        fStyle.strokeRec().isHairlineStyle()) {
660cb93a386Sopenharmony_ci        return;
661cb93a386Sopenharmony_ci    }
662cb93a386Sopenharmony_ci
663cb93a386Sopenharmony_ci    // Tracks style simplifications, even if the geometry can't be further simplified.
664cb93a386Sopenharmony_ci    bool styleSimplified = false;
665cb93a386Sopenharmony_ci    if (fStyle.isDashed()) {
666cb93a386Sopenharmony_ci        // For dashing a point, if the first interval is on, we can drop the dash and just draw
667cb93a386Sopenharmony_ci        // the caps. For dashing a line, if every off interval is 0 length, its a stroke.
668cb93a386Sopenharmony_ci        bool dropDash = false;
669cb93a386Sopenharmony_ci        if (fShape.isPoint()) {
670cb93a386Sopenharmony_ci            dropDash = fStyle.dashIntervalCnt() > 0 &&
671cb93a386Sopenharmony_ci                       SkToBool(fStyle.dashIntervals()[0]);
672cb93a386Sopenharmony_ci        } else {
673cb93a386Sopenharmony_ci            dropDash = true;
674cb93a386Sopenharmony_ci            for (int i = 1; i < fStyle.dashIntervalCnt(); i += 2) {
675cb93a386Sopenharmony_ci                if (SkToBool(fStyle.dashIntervals()[i])) {
676cb93a386Sopenharmony_ci                    // An off interval has non-zero length so this won't convert to a simple line
677cb93a386Sopenharmony_ci                    dropDash = false;
678cb93a386Sopenharmony_ci                    break;
679cb93a386Sopenharmony_ci                }
680cb93a386Sopenharmony_ci            }
681cb93a386Sopenharmony_ci        }
682cb93a386Sopenharmony_ci
683cb93a386Sopenharmony_ci        if (!dropDash) {
684cb93a386Sopenharmony_ci            return;
685cb93a386Sopenharmony_ci        }
686cb93a386Sopenharmony_ci        // Fall through to modifying the shape to respect the new stroke geometry
687cb93a386Sopenharmony_ci        fStyle = GrStyle(fStyle.strokeRec(), nullptr);
688cb93a386Sopenharmony_ci        // Since the reduced the line or point after dashing is dependent on the caps of the dashes,
689cb93a386Sopenharmony_ci        // we reset to be unclosed so we don't override the style based on joins later.
690cb93a386Sopenharmony_ci        fClosed = false;
691cb93a386Sopenharmony_ci        styleSimplified = true;
692cb93a386Sopenharmony_ci    }
693cb93a386Sopenharmony_ci
694cb93a386Sopenharmony_ci    // At this point, we're a line or point with no path effects. Any fill portion of the style
695cb93a386Sopenharmony_ci    // is empty, so a fill-only style can be empty, and a stroke+fill becomes a stroke.
696cb93a386Sopenharmony_ci    if (fStyle.isSimpleFill()) {
697cb93a386Sopenharmony_ci        fShape.reset();
698cb93a386Sopenharmony_ci        fSimplified = true;
699cb93a386Sopenharmony_ci        return;
700cb93a386Sopenharmony_ci    } else if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
701cb93a386Sopenharmony_ci        // Stroke only
702cb93a386Sopenharmony_ci        SkStrokeRec rec = fStyle.strokeRec();
703cb93a386Sopenharmony_ci        rec.setStrokeStyle(fStyle.strokeRec().getWidth(), false);
704cb93a386Sopenharmony_ci        fStyle = GrStyle(rec, nullptr);
705cb93a386Sopenharmony_ci        styleSimplified = true;
706cb93a386Sopenharmony_ci    }
707cb93a386Sopenharmony_ci
708cb93a386Sopenharmony_ci    // A point or line that was formed by a degenerate closed shape needs its style updated to
709cb93a386Sopenharmony_ci    // reflect the fact that it doesn't actually produce caps.
710cb93a386Sopenharmony_ci    if (fClosed) {
711cb93a386Sopenharmony_ci        SkPaint::Cap cap;
712cb93a386Sopenharmony_ci        if (fShape.isLine() && fStyle.strokeRec().getJoin() == SkPaint::kRound_Join) {
713cb93a386Sopenharmony_ci            // As a closed shape, the line moves from a to b and back to a, producing a 180 degree
714cb93a386Sopenharmony_ci            // turn. With round joins, this would make a semi-circle at each end, which is visually
715cb93a386Sopenharmony_ci            // identical to a round cap on the reduced line geometry.
716cb93a386Sopenharmony_ci            cap = SkPaint::kRound_Cap;
717cb93a386Sopenharmony_ci        } else {
718cb93a386Sopenharmony_ci            // If this were a closed line, the 180 degree turn either is a miter join that exceeds
719cb93a386Sopenharmony_ci            // the miter limit and becomes a bevel, or a bevel join. In either case, the bevel shape
720cb93a386Sopenharmony_ci            // of a 180 degreen corner is equivalent to a butt cap.
721cb93a386Sopenharmony_ci            //  - to match the SVG spec, the 0-length sides of an empty rectangle are skipped, so
722cb93a386Sopenharmony_ci            //    it fits this closed line description (it is not two 90 degree turns that could
723cb93a386Sopenharmony_ci            //    produce miter geometry).
724cb93a386Sopenharmony_ci            cap = SkPaint::kButt_Cap;
725cb93a386Sopenharmony_ci        }
726cb93a386Sopenharmony_ci
727cb93a386Sopenharmony_ci        if (cap != fStyle.strokeRec().getCap() ||
728cb93a386Sopenharmony_ci            SkPaint::kDefault_Join != fStyle.strokeRec().getJoin()) {
729cb93a386Sopenharmony_ci            SkStrokeRec rec = fStyle.strokeRec();
730cb93a386Sopenharmony_ci            rec.setStrokeParams(cap, SkPaint::kDefault_Join, fStyle.strokeRec().getMiter());
731cb93a386Sopenharmony_ci            fStyle = GrStyle(rec, nullptr);
732cb93a386Sopenharmony_ci            styleSimplified = true;
733cb93a386Sopenharmony_ci        }
734cb93a386Sopenharmony_ci    }
735cb93a386Sopenharmony_ci
736cb93a386Sopenharmony_ci    if (fShape.isPoint()) {
737cb93a386Sopenharmony_ci        // The drawn geometry is entirely based on the cap style and stroke width. A butt cap point
738cb93a386Sopenharmony_ci        // doesn't draw anything, a round cap is an oval and a square cap is a square.
739cb93a386Sopenharmony_ci        if (fStyle.strokeRec().getCap() == SkPaint::kButt_Cap) {
740cb93a386Sopenharmony_ci            fShape.reset();
741cb93a386Sopenharmony_ci        } else {
742cb93a386Sopenharmony_ci            SkScalar w = fStyle.strokeRec().getWidth() / 2.f;
743cb93a386Sopenharmony_ci            SkRect r = {fShape.point().fX, fShape.point().fY, fShape.point().fX, fShape.point().fY};
744cb93a386Sopenharmony_ci            r.outset(w, w);
745cb93a386Sopenharmony_ci
746cb93a386Sopenharmony_ci            if (fStyle.strokeRec().getCap() == SkPaint::kRound_Cap) {
747cb93a386Sopenharmony_ci                fShape.setRRect(SkRRect::MakeOval(r));
748cb93a386Sopenharmony_ci            } else {
749cb93a386Sopenharmony_ci                fShape.setRect(r);
750cb93a386Sopenharmony_ci            }
751cb93a386Sopenharmony_ci        }
752cb93a386Sopenharmony_ci    } else {
753cb93a386Sopenharmony_ci        // Stroked lines reduce to rectangles or round rects when they are axis-aligned. If we
754cb93a386Sopenharmony_ci        // allowed rotation angle, this would work for any lines.
755cb93a386Sopenharmony_ci        SkRect rect;
756cb93a386Sopenharmony_ci        SkVector outset;
757cb93a386Sopenharmony_ci        if (fShape.line().fP1.fY == fShape.line().fP2.fY) {
758cb93a386Sopenharmony_ci            rect.fLeft = std::min(fShape.line().fP1.fX, fShape.line().fP2.fX);
759cb93a386Sopenharmony_ci            rect.fRight = std::max(fShape.line().fP1.fX, fShape.line().fP2.fX);
760cb93a386Sopenharmony_ci            rect.fTop = rect.fBottom = fShape.line().fP1.fY;
761cb93a386Sopenharmony_ci            outset.fY = fStyle.strokeRec().getWidth() / 2.f;
762cb93a386Sopenharmony_ci            outset.fX = SkPaint::kButt_Cap == fStyle.strokeRec().getCap() ? 0.f : outset.fY;
763cb93a386Sopenharmony_ci        } else if (fShape.line().fP1.fX == fShape.line().fP2.fX) {
764cb93a386Sopenharmony_ci            rect.fTop = std::min(fShape.line().fP1.fY, fShape.line().fP2.fY);
765cb93a386Sopenharmony_ci            rect.fBottom = std::max(fShape.line().fP1.fY, fShape.line().fP2.fY);
766cb93a386Sopenharmony_ci            rect.fLeft = rect.fRight = fShape.line().fP1.fX;
767cb93a386Sopenharmony_ci            outset.fX = fStyle.strokeRec().getWidth() / 2.f;
768cb93a386Sopenharmony_ci            outset.fY = SkPaint::kButt_Cap == fStyle.strokeRec().getCap() ? 0.f : outset.fX;
769cb93a386Sopenharmony_ci        } else {
770cb93a386Sopenharmony_ci            // Geometrically can't apply the style and turn into a fill, but might still be simpler
771cb93a386Sopenharmony_ci            // than before based solely on changes to fStyle.
772cb93a386Sopenharmony_ci            fSimplified |= styleSimplified;
773cb93a386Sopenharmony_ci            return;
774cb93a386Sopenharmony_ci        }
775cb93a386Sopenharmony_ci        rect.outset(outset.fX, outset.fY);
776cb93a386Sopenharmony_ci        if (rect.isEmpty()) {
777cb93a386Sopenharmony_ci            fShape.reset();
778cb93a386Sopenharmony_ci        } else if (fStyle.strokeRec().getCap() == SkPaint::kRound_Cap) {
779cb93a386Sopenharmony_ci            SkASSERT(outset.fX == outset.fY);
780cb93a386Sopenharmony_ci            fShape.setRRect(SkRRect::MakeRectXY(rect, outset.fX, outset.fY));
781cb93a386Sopenharmony_ci        } else {
782cb93a386Sopenharmony_ci            fShape.setRect(rect);
783cb93a386Sopenharmony_ci        }
784cb93a386Sopenharmony_ci    }
785cb93a386Sopenharmony_ci    // If we made it here, the stroke was fully applied to the new shape so we can become a fill.
786cb93a386Sopenharmony_ci    fStyle = GrStyle::SimpleFill();
787cb93a386Sopenharmony_ci    fSimplified = true;
788cb93a386Sopenharmony_ci    return;
789cb93a386Sopenharmony_ci}
790