/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "src/gpu/ganesh/geometry/GrStyledShape.h"

#include "include/core/SkArc.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkPoint.h"
#include "include/core/SkStrokeRec.h"
#include "include/private/SkIDChangeListener.h"
#include "include/private/base/SkAlign.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkMalloc.h"
#include "include/private/base/SkTo.h"

#include <algorithm>
#include <cstring>
#include <utility>


GrStyledShape& GrStyledShape::operator=(const GrStyledShape& that) {
    fShape      = that.fShape;
    fStyle      = that.fStyle;
    fGenID      = that.fGenID;
    fSimplified = that.fSimplified;

    fInheritedKey.reset(that.fInheritedKey.count());
    sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
                      sizeof(uint32_t) * fInheritedKey.count());
    if (that.fInheritedPathForListeners.has_value()) {
        fInheritedPathForListeners = *that.fInheritedPathForListeners;
    } else {
        fInheritedPathForListeners.reset();
    }
    return *this;
}

static bool is_inverted(bool originalIsInverted, GrStyledShape::FillInversion inversion) {
    switch (inversion) {
        case GrStyledShape::FillInversion::kPreserve:
            return originalIsInverted;
        case GrStyledShape::FillInversion::kFlip:
            return !originalIsInverted;
        case GrStyledShape::FillInversion::kForceInverted:
            return true;
        case GrStyledShape::FillInversion::kForceNoninverted:
            return false;
    }
    return false;
}

GrStyledShape GrStyledShape::MakeFilled(const GrStyledShape& original, FillInversion inversion) {
    bool newIsInverted = is_inverted(original.fShape.inverted(), inversion);
    if (original.style().isSimpleFill() && newIsInverted == original.fShape.inverted()) {
        // By returning the original rather than falling through we can preserve any inherited style
        // key. Otherwise, we wipe it out below since the style change invalidates it.
        return original;
    }
    GrStyledShape result;
    SkASSERT(result.fStyle.isSimpleFill());
    if (original.fInheritedPathForListeners.has_value()) {
        result.fInheritedPathForListeners = *original.fInheritedPathForListeners;
    }

    result.fShape = original.fShape;
    result.fGenID = original.fGenID;
    result.fShape.setInverted(newIsInverted);

    if (!original.style().isSimpleFill()) {
        // Going from a non-filled style to fill may allow additional simplifications (e.g.
        // closing an open rect that wasn't closed in the original shape because it had
        // stroke style).
        result.simplify();
        // The above simplify() call only sets simplified to true if its geometry was changed,
        // since it already sees its style as a simple fill. Since the original style was not a
        // simple fill, MakeFilled always simplifies.
        result.fSimplified = true;
    }

    // Verify that lines/points were converted to empty by the style change
    SkASSERT((!original.fShape.isLine() && !original.fShape.isPoint()) || result.fShape.isEmpty());

    // We don't copy the inherited key since it can contain path effect information that we just
    // stripped.
    return result;
}

SkRect GrStyledShape::styledBounds() const {
    if (this->isEmpty() && !fStyle.hasNonDashPathEffect()) {
        return SkRect::MakeEmpty();
    }

    SkRect bounds;
    fStyle.adjustBounds(&bounds, this->bounds());
    return bounds;
}

// If the path is small enough to be keyed from its data this returns key length, otherwise -1.
static int path_key_from_data_size(const SkPath& path) {
    const int verbCnt = path.countVerbs();
    if (verbCnt > GrStyledShape::kMaxKeyFromDataVerbCnt) {
        return -1;
    }
    const int pointCnt = path.countPoints();
    const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);

    static_assert(sizeof(SkPoint) == 2 * sizeof(uint32_t));
    static_assert(sizeof(SkScalar) == sizeof(uint32_t));
    // 1 is for the verb count. Each verb is a byte but we'll pad the verb data out to
    // a uint32_t length.
    return 1 + (SkAlign4(verbCnt) >> 2) + 2 * pointCnt + conicWeightCnt;
}

// Writes the path data key into the passed pointer.
static void write_path_key_from_data(const SkPath& path, uint32_t* origKey) {
    uint32_t* key = origKey;
    // The check below should take care of negative values casted positive.
    const int verbCnt = path.countVerbs();
    const int pointCnt = path.countPoints();
    const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
    SkASSERT(verbCnt <= GrStyledShape::kMaxKeyFromDataVerbCnt);
    SkASSERT(pointCnt && verbCnt);
    *key++ = verbCnt;
    memcpy(key, SkPathPriv::VerbData(path), verbCnt * sizeof(uint8_t));
    int verbKeySize = SkAlign4(verbCnt);
    // pad out to uint32_t alignment using value that will stand out when debugging.
    uint8_t* pad = reinterpret_cast<uint8_t*>(key)+ verbCnt;
    memset(pad, 0xDE, verbKeySize - verbCnt);
    key += verbKeySize >> 2;

    memcpy(key, SkPathPriv::PointData(path), sizeof(SkPoint) * pointCnt);
    static_assert(sizeof(SkPoint) == 2 * sizeof(uint32_t));
    key += 2 * pointCnt;
    sk_careful_memcpy(key, SkPathPriv::ConicWeightData(path), sizeof(SkScalar) * conicWeightCnt);
    static_assert(sizeof(SkScalar) == sizeof(uint32_t));
    SkDEBUGCODE(key += conicWeightCnt);
    SkASSERT(key - origKey == path_key_from_data_size(path));
}

int GrStyledShape::unstyledKeySize() const {
    if (fInheritedKey.count()) {
        return fInheritedKey.count();
    }

    int count = 1; // Every key has the state flags from the GrShape
    switch(fShape.type()) {
        case GrShape::Type::kPoint:
            static_assert(0 == sizeof(SkPoint) % sizeof(uint32_t));
            count += sizeof(SkPoint) / sizeof(uint32_t);
            break;
        case GrShape::Type::kRect:
            static_assert(0 == sizeof(SkRect) % sizeof(uint32_t));
            count += sizeof(SkRect) / sizeof(uint32_t);
            break;
        case GrShape::Type::kRRect:
            static_assert(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
            count += SkRRect::kSizeInMemory / sizeof(uint32_t);
            break;
        case GrShape::Type::kArc:
            static_assert(0 == sizeof(SkArc) % sizeof(uint32_t));
            count += sizeof(SkArc) / sizeof(uint32_t);
            break;
        case GrShape::Type::kLine:
            static_assert(0 == sizeof(GrLineSegment) % sizeof(uint32_t));
            count += sizeof(GrLineSegment) / sizeof(uint32_t);
            break;
        case GrShape::Type::kPath: {
            if (0 == fGenID) {
                return -1; // volatile, so won't be keyed
            }
            int dataKeySize = path_key_from_data_size(fShape.path());
            if (dataKeySize >= 0) {
                count += dataKeySize;
            } else {
                count++; // Just adds the gen ID.
            }
            break; }
        default:
            // else it's empty, which just needs the state flags for its key
            SkASSERT(fShape.isEmpty());
    }
    return count;
}

void GrStyledShape::writeUnstyledKey(uint32_t* key) const {
    SkASSERT(this->unstyledKeySize());
    SkDEBUGCODE(uint32_t* origKey = key;)
    if (fInheritedKey.count()) {
        memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count());
        SkDEBUGCODE(key += fInheritedKey.count();)
    } else {
        // Dir and start are only used for rect and rrect shapes, so are not included in other
        // shape type keys. Make sure that they are the defaults for other shapes so it doesn't
        // matter that we universally include them in the flag key value.
        SkASSERT((fShape.isRect() || fShape.isRRect()) ||
                 (fShape.dir() == GrShape::kDefaultDir &&
                  fShape.startIndex() == GrShape::kDefaultStart));

        // Every key starts with the state from the GrShape (this includes path fill type,
        // and any tracked winding, start, inversion, as well as the class of geometry).
        *key++ = fShape.stateKey();

        switch(fShape.type()) {
            case GrShape::Type::kPath: {
                SkASSERT(fGenID != 0);
                // Ensure that the path's inversion matches our state so that the path's key suffices.
                SkASSERT(fShape.inverted() == fShape.path().isInverseFillType());

                int dataKeySize = path_key_from_data_size(fShape.path());
                if (dataKeySize >= 0) {
                    write_path_key_from_data(fShape.path(), key);
                    return;
                } else {
                    *key++ = fGenID;
                }
                break; }
            case GrShape::Type::kPoint:
                memcpy(key, &fShape.point(), sizeof(SkPoint));
                key += sizeof(SkPoint) / sizeof(uint32_t);
                break;
            case GrShape::Type::kRect:
                memcpy(key, &fShape.rect(), sizeof(SkRect));
                key += sizeof(SkRect) / sizeof(uint32_t);
                break;
            case GrShape::Type::kRRect:
                fShape.rrect().writeToMemory(key);
                key += SkRRect::kSizeInMemory / sizeof(uint32_t);
                break;
            case GrShape::Type::kArc:
                // Write dense floats first
                memcpy(key, &fShape.arc(), sizeof(SkRect) + 2 * sizeof(float));
                key += (sizeof(SkArc) / sizeof(uint32_t) - 1);
                // Then write the final bool as an int, to make sure upper bits are set
                *key++ = fShape.arc().isWedge() ? 1 : 0;
                break;
            case GrShape::Type::kLine:
                memcpy(key, &fShape.line(), sizeof(GrLineSegment));
                key += sizeof(GrLineSegment) / sizeof(uint32_t);
                break;
            default:
                // Nothing other than the flag state is needed in the key for an empty shape
                SkASSERT(fShape.isEmpty());
        }
    }
    SkASSERT(key - origKey == this->unstyledKeySize());
}

void GrStyledShape::setInheritedKey(const GrStyledShape &parent, GrStyle::Apply apply,
                                    SkScalar scale) {
    SkASSERT(!fInheritedKey.count());
    // If the output shape turns out to be simple, then we will just use its geometric key
    if (fShape.isPath()) {
        // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key as
        // ApplyFullStyle(shape).
        // The full key is structured as (geo,path_effect,stroke).
        // If we do ApplyPathEffect we get geo,path_effect as the inherited key. If we then
        // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited key
        // and then append the style key (which should now be stroke only) at the end.
        int parentCnt = parent.fInheritedKey.count();
        bool useParentGeoKey = !parentCnt;
        if (useParentGeoKey) {
            parentCnt = parent.unstyledKeySize();
            if (parentCnt < 0) {
                // The parent's geometry has no key so we will have no key.
                fGenID = 0;
                return;
            }
        }
        uint32_t styleKeyFlags = 0;
        if (parent.knownToBeClosed()) {
            styleKeyFlags |= GrStyle::kClosed_KeyFlag;
        }
        if (parent.asLine(nullptr, nullptr)) {
            styleKeyFlags |= GrStyle::kNoJoins_KeyFlag;
        }
        int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags);
        if (styleCnt < 0) {
            // The style doesn't allow a key, set the path gen ID to 0 so that we fail when
            // we try to get a key for the shape.
            fGenID = 0;
            return;
        }
        fInheritedKey.reset(parentCnt + styleCnt);
        if (useParentGeoKey) {
            // This will be the geo key.
            parent.writeUnstyledKey(fInheritedKey.get());
        } else {
            // This should be (geo,path_effect).
            memcpy(fInheritedKey.get(), parent.fInheritedKey.get(),
                   parentCnt * sizeof(uint32_t));
        }
        // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke)
        GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply, scale,
                          styleKeyFlags);
    }
}

const SkPath* GrStyledShape::originalPathForListeners() const {
    if (fInheritedPathForListeners.has_value()) {
        return &fInheritedPathForListeners.value();
    } else if (fShape.isPath() && !fShape.path().isVolatile()) {
        return &fShape.path();
    }
    return nullptr;
}

void GrStyledShape::addGenIDChangeListener(sk_sp<SkIDChangeListener> listener) const {
    if (const auto* lp = this->originalPathForListeners()) {
        SkPathPriv::AddGenIDChangeListener(*lp, std::move(listener));
    }
}

GrStyledShape GrStyledShape::MakeArc(const SkArc& arc,
                                     const GrStyle& style,
                                     DoSimplify doSimplify) {
    GrStyledShape result;
    result.fShape.setArc(
            SkArc::Make(arc.fOval.makeSorted(), arc.fStartAngle, arc.fSweepAngle, arc.fType));
    result.fStyle = style;
    if (doSimplify == DoSimplify::kYes) {
        result.simplify();
    }
    return result;
}

GrStyledShape::GrStyledShape(const GrStyledShape& that)
        : fShape(that.fShape)
        , fStyle(that.fStyle)
        , fGenID(that.fGenID)
        , fSimplified(that.fSimplified) {
    fInheritedKey.reset(that.fInheritedKey.count());
    sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
                      sizeof(uint32_t) * fInheritedKey.count());
    if (that.fInheritedPathForListeners.has_value()) {
        fInheritedPathForListeners = *that.fInheritedPathForListeners;
    }
}

GrStyledShape::GrStyledShape(const GrStyledShape& parent, GrStyle::Apply apply, SkScalar scale) {
    // TODO: Add some quantization of scale for better cache performance here or leave that up
    // to caller?
    // TODO: For certain shapes and stroke params we could ignore the scale. (e.g. miter or bevel
    // stroke of a rect).
    if (!parent.style().applies() ||
        (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect())) {
        *this = parent;
        return;
    }

    SkPathEffect* pe = parent.fStyle.pathEffect();
    std::optional<SkPath> tmpPath;
    const GrStyledShape* parentForKey = &parent;
    std::optional<GrStyledShape> tmpParent;

    // Start out as an empty path that is filled in by the applied style
    fShape.setPath(SkPath());

    if (pe) {
        const SkPath* srcForPathEffect;
        if (parent.fShape.isPath()) {
            srcForPathEffect = &parent.fShape.path();
        } else {
            srcForPathEffect = &tmpPath.emplace(parent.asPath());
        }
        // Should we consider bounds? Would have to include in key, but it'd be nice to know
        // if the bounds actually modified anything before including in key.
        SkStrokeRec strokeRec = parent.fStyle.strokeRec();
        if (!parent.fStyle.applyPathEffectToPath(&fShape.path(), &strokeRec, *srcForPathEffect,
                                                 scale)) {
            tmpParent.emplace(*srcForPathEffect, GrStyle(strokeRec, nullptr));
            *this = tmpParent->applyStyle(apply, scale);
            return;
        }
        // A path effect has access to change the res scale but we aren't expecting it to and it
        // would mess up our key computation.
        SkASSERT(scale == strokeRec.getResScale());
        if (GrStyle::Apply::kPathEffectAndStrokeRec == apply && strokeRec.needToApply()) {
            // The intermediate shape may not be a general path. If we we're just applying
            // the path effect then attemptToReduceFromPath would catch it. This means that
            // when we subsequently applied the remaining strokeRec we would have a non-path
            // parent shape that would be used to determine the the stroked path's key.
            // We detect that case here and change parentForKey to a temporary that represents
            // the simpler shape so that applying both path effect and the strokerec all at
            // once produces the same key.
            tmpParent.emplace(fShape.path(), GrStyle(strokeRec, nullptr));
            tmpParent->setInheritedKey(parent, GrStyle::Apply::kPathEffectOnly, scale);
            if (!tmpPath.has_value()) {
                tmpPath.emplace();
            }
            tmpPath = tmpParent->asPath();
            SkStrokeRec::InitStyle fillOrHairline;
            // The parent shape may have simplified away the strokeRec, check for that here.
            if (tmpParent->style().applies()) {
                SkAssertResult(tmpParent->style().applyToPath(&fShape.path(), &fillOrHairline,
                                                              tmpPath.value(), scale));
            } else if (tmpParent->style().isSimpleFill()) {
                fillOrHairline = SkStrokeRec::kFill_InitStyle;
            } else {
                SkASSERT(tmpParent->style().isSimpleHairline());
                fillOrHairline = SkStrokeRec::kHairline_InitStyle;
            }
            fStyle.resetToInitStyle(fillOrHairline);
            parentForKey = &tmpParent.value();
        } else {
            fStyle = GrStyle(strokeRec, nullptr);
        }
    } else {
        const SkPath* srcForParentStyle;
        if (parent.fShape.isPath()) {
            srcForParentStyle = &parent.fShape.path();
        } else {
            srcForParentStyle = &tmpPath.emplace(parent.asPath());
        }
        SkStrokeRec::InitStyle fillOrHairline;
        SkASSERT(parent.fStyle.applies());
        SkASSERT(!parent.fStyle.pathEffect());
        SkAssertResult(parent.fStyle.applyToPath(&fShape.path(), &fillOrHairline,
                                                 *srcForParentStyle, scale));
        fStyle.resetToInitStyle(fillOrHairline);
    }

    if (parent.fInheritedPathForListeners.has_value()) {
        fInheritedPathForListeners = *parent.fInheritedPathForListeners;
    } else if (parent.fShape.isPath() && !parent.fShape.path().isVolatile()) {
        fInheritedPathForListeners = parent.fShape.path();
    }
    this->simplify();
    this->setInheritedKey(*parentForKey, apply, scale);
}

bool GrStyledShape::asRRect(SkRRect* rrect, bool* inverted) const {
    if (!fShape.isRRect() && !fShape.isRect()) {
        return false;
    }

    if (rrect) {
        *rrect = fShape.isRect() ? SkRRect::MakeRect(fShape.rect()) : fShape.rrect();
    }

    if (inverted) {
        *inverted = fShape.inverted();
    }

    return true;
}

bool GrStyledShape::asLine(SkPoint pts[2], bool* inverted) const {
    if (!fShape.isLine()) {
        return false;
    }

    if (pts) {
        pts[0] = fShape.line().fP1;
        pts[1] = fShape.line().fP2;
    }
    if (inverted) {
        *inverted = fShape.inverted();
    }
    return true;
}

bool GrStyledShape::asNestedRects(SkRect rects[2]) const {
    if (!fShape.isPath()) {
        return false;
    }

    // TODO: it would be better two store DRRects natively in the shape rather than converting
    // them to a path and then reextracting the nested rects
    if (fShape.path().isInverseFillType()) {
        return false;
    }

    SkPathDirection dirs[2];
    if (!SkPathPriv::IsNestedFillRects(fShape.path(), rects, dirs)) {
        return false;
    }

    if (SkPathFillType::kWinding == fShape.path().getFillType() && dirs[0] == dirs[1]) {
        // The two rects need to be wound opposite to each other
        return false;
    }

    // Right now, nested rects where the margin is not the same width
    // all around do not render correctly
    const SkScalar* outer = rects[0].asScalars();
    const SkScalar* inner = rects[1].asScalars();

    bool allEq = true;

    SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
    bool allGoE1 = margin >= SK_Scalar1;

    for (int i = 1; i < 4; ++i) {
        SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
        if (temp < SK_Scalar1) {
            allGoE1 = false;
        }
        if (!SkScalarNearlyEqual(margin, temp)) {
            allEq = false;
        }
    }

    return allEq || allGoE1;
}

class AutoRestoreInverseness {
public:
    AutoRestoreInverseness(GrShape* shape, const GrStyle& style)
            // Dashing ignores inverseness skbug.com/40036591.
            : fShape(shape), fInverted(!style.isDashed() && fShape->inverted()) {}

    ~AutoRestoreInverseness() {
        // Restore invertedness after any modifications were made to the shape type
        fShape->setInverted(fInverted);
        SkASSERT(!fShape->isPath() || fInverted == fShape->path().isInverseFillType());
    }

private:
    GrShape* fShape;
    bool fInverted;
};

void GrStyledShape::simplify() {
    AutoRestoreInverseness ari(&fShape, fStyle);

    unsigned simplifyFlags = 0;
    if (fStyle.isSimpleFill()) {
        simplifyFlags = GrShape::kAll_Flags;
    } else if (!fStyle.hasPathEffect()) {
        // Everything but arcs with caps that might extend beyond the oval edge can ignore winding
        if (!fShape.isArc() || fStyle.strokeRec().getCap() == SkPaint::kButt_Cap) {
            simplifyFlags |= GrShape::kIgnoreWinding_Flag;
        }
        simplifyFlags |= GrShape::kMakeCanonical_Flag;
    } // else if there's a path effect, every destructive simplification is disabledd

    // Remember if the original shape was closed; in the event we simplify to a point or line
    // because of degenerate geometry, we need to update joins and caps.
    GrShape::Type oldType = fShape.type();
    fClosed = fShape.simplify(simplifyFlags);
    fSimplified = oldType != fShape.type();

    if (fShape.isPath()) {
        // The shape remains a path, so configure the gen ID and canonicalize fill type if possible
        if (fInheritedKey.count() || fShape.path().isVolatile()) {
            fGenID = 0;
        } else {
            fGenID = fShape.path().getGenerationID();
        }
        if (!fStyle.hasNonDashPathEffect() &&
            (fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style ||
             fStyle.strokeRec().getStyle() == SkStrokeRec::kHairline_Style ||
             fShape.path().isConvex())) {
            // Stroke styles don't differentiate between winding and even/odd. There is no
            // distinction between even/odd and non-zero winding count for convex paths.
            // Moreover, dashing ignores inverseness (skbug.com/40036591)
            fShape.path().setFillType(GrShape::kDefaultFillType);
        }
    } else {
        fInheritedKey.reset(0);
        // Whenever we simplify to a non-path, break the chain so we no longer refer to the
        // original path. This prevents attaching genID listeners to temporary paths created when
        // drawing simple shapes.
        fInheritedPathForListeners.reset();
        // Further simplifications to the shape based on the style
        this->simplifyStroke();
    }
}

void GrStyledShape::simplifyStroke() {
    AutoRestoreInverseness ari(&fShape, fStyle);

    // For stroke+filled rects, a mitered shape becomes a larger rect and a rounded shape
    // becomes a round rect.
    if (!fStyle.hasPathEffect() && fShape.isRect() &&
        fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
        if (fStyle.strokeRec().getJoin() == SkPaint::kBevel_Join ||
            (fStyle.strokeRec().getJoin() == SkPaint::kMiter_Join &&
             fStyle.strokeRec().getMiter() < SK_ScalarSqrt2)) {
            // Bevel-stroked rect needs path rendering
            return;
        }

        SkScalar r = fStyle.strokeRec().getWidth() / 2;
        fShape.rect().outset(r, r);
        if (fStyle.strokeRec().getJoin() == SkPaint::kRound_Join) {
            // There's no dashing to worry about if we got here, so it's okay that this resets
            // winding parameters
            fShape.setRRect(SkRRect::MakeRectXY(fShape.rect(), r, r));
        }
        fStyle = GrStyle::SimpleFill();
        fSimplified = true;
        return;
    }

    // Otherwise, if we're a point or a line, we might be able to explicitly apply some of the
    // stroking (and even some of the dashing). Any other shape+style is too complicated to reduce.
    if ((!fShape.isPoint() && !fShape.isLine()) || fStyle.hasNonDashPathEffect() ||
        fStyle.strokeRec().isHairlineStyle()) {
        return;
    }

    // Tracks style simplifications, even if the geometry can't be further simplified.
    bool styleSimplified = false;
    if (fStyle.isDashed()) {
        // For dashing a point, if the first interval is on, we can drop the dash and just draw
        // the caps. For dashing a line, if every off interval is 0 length, its a stroke.
        bool dropDash = false;
        if (fShape.isPoint()) {
            dropDash = fStyle.dashIntervalCnt() > 0 &&
                       SkToBool(fStyle.dashIntervals()[0]);
        } else {
            dropDash = true;
            for (int i = 1; i < fStyle.dashIntervalCnt(); i += 2) {
                if (SkToBool(fStyle.dashIntervals()[i])) {
                    // An off interval has non-zero length so this won't convert to a simple line
                    dropDash = false;
                    break;
                }
            }
        }

        if (!dropDash) {
            return;
        }
        // Fall through to modifying the shape to respect the new stroke geometry
        fStyle = GrStyle(fStyle.strokeRec(), nullptr);
        // Since the reduced the line or point after dashing is dependent on the caps of the dashes,
        // we reset to be unclosed so we don't override the style based on joins later.
        fClosed = false;
        styleSimplified = true;
    }

    // At this point, we're a line or point with no path effects. Any fill portion of the style
    // is empty, so a fill-only style can be empty, and a stroke+fill becomes a stroke.
    if (fStyle.isSimpleFill()) {
        fShape.reset();
        fSimplified = true;
        return;
    } else if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
        // Stroke only
        SkStrokeRec rec = fStyle.strokeRec();
        rec.setStrokeStyle(fStyle.strokeRec().getWidth(), false);
        fStyle = GrStyle(rec, nullptr);
        styleSimplified = true;
    }

    // A point or line that was formed by a degenerate closed shape needs its style updated to
    // reflect the fact that it doesn't actually produce caps.
    if (fClosed) {
        SkPaint::Cap cap;
        if (fShape.isLine() && fStyle.strokeRec().getJoin() == SkPaint::kRound_Join) {
            // As a closed shape, the line moves from a to b and back to a, producing a 180 degree
            // turn. With round joins, this would make a semi-circle at each end, which is visually
            // identical to a round cap on the reduced line geometry.
            cap = SkPaint::kRound_Cap;
        } else {
            // If this were a closed line, the 180 degree turn either is a miter join that exceeds
            // the miter limit and becomes a bevel, or a bevel join. In either case, the bevel shape
            // of a 180 degreen corner is equivalent to a butt cap.
            //  - to match the SVG spec, the 0-length sides of an empty rectangle are skipped, so
            //    it fits this closed line description (it is not two 90 degree turns that could
            //    produce miter geometry).
            cap = SkPaint::kButt_Cap;
        }

        if (cap != fStyle.strokeRec().getCap() ||
            SkPaint::kDefault_Join != fStyle.strokeRec().getJoin()) {
            SkStrokeRec rec = fStyle.strokeRec();
            rec.setStrokeParams(cap, SkPaint::kDefault_Join, fStyle.strokeRec().getMiter());
            fStyle = GrStyle(rec, nullptr);
            styleSimplified = true;
        }
    }

    if (fShape.isPoint()) {
        // The drawn geometry is entirely based on the cap style and stroke width. A butt cap point
        // doesn't draw anything, a round cap is an oval and a square cap is a square.
        if (fStyle.strokeRec().getCap() == SkPaint::kButt_Cap) {
            fShape.reset();
        } else {
            SkScalar w = fStyle.strokeRec().getWidth() / 2.f;
            SkRect r = {fShape.point().fX, fShape.point().fY, fShape.point().fX, fShape.point().fY};
            r.outset(w, w);

            if (fStyle.strokeRec().getCap() == SkPaint::kRound_Cap) {
                fShape.setRRect(SkRRect::MakeOval(r));
            } else {
                fShape.setRect(r);
            }
        }
    } else {
        // Stroked lines reduce to rectangles or round rects when they are axis-aligned. If we
        // allowed rotation angle, this would work for any lines.
        SkRect rect;
        SkVector outset;
        if (fShape.line().fP1.fY == fShape.line().fP2.fY) {
            rect.fLeft = std::min(fShape.line().fP1.fX, fShape.line().fP2.fX);
            rect.fRight = std::max(fShape.line().fP1.fX, fShape.line().fP2.fX);
            rect.fTop = rect.fBottom = fShape.line().fP1.fY;
            outset.fY = fStyle.strokeRec().getWidth() / 2.f;
            outset.fX = SkPaint::kButt_Cap == fStyle.strokeRec().getCap() ? 0.f : outset.fY;
        } else if (fShape.line().fP1.fX == fShape.line().fP2.fX) {
            rect.fTop = std::min(fShape.line().fP1.fY, fShape.line().fP2.fY);
            rect.fBottom = std::max(fShape.line().fP1.fY, fShape.line().fP2.fY);
            rect.fLeft = rect.fRight = fShape.line().fP1.fX;
            outset.fX = fStyle.strokeRec().getWidth() / 2.f;
            outset.fY = SkPaint::kButt_Cap == fStyle.strokeRec().getCap() ? 0.f : outset.fX;
        } else {
            // Geometrically can't apply the style and turn into a fill, but might still be simpler
            // than before based solely on changes to fStyle.
            fSimplified |= styleSimplified;
            return;
        }
        rect.outset(outset.fX, outset.fY);
        if (rect.isEmpty()) {
            fShape.reset();
        } else if (fStyle.strokeRec().getCap() == SkPaint::kRound_Cap) {
            SkASSERT(outset.fX == outset.fY);
            fShape.setRRect(SkRRect::MakeRectXY(rect, outset.fX, outset.fY));
        } else {
            fShape.setRect(rect);
        }
    }
    // If we made it here, the stroke was fully applied to the new shape so we can become a fill.
    fStyle = GrStyle::SimpleFill();
    fSimplified = true;
}
