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