147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon/*
247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Copyright 2016 Google Inc.
347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon *
447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Use of this source code is governed by a BSD-style license that can be
547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * found in the LICENSE file.
647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon */
747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#ifndef GrShape_DEFINED
947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#define GrShape_DEFINED
1047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
1147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "GrStyle.h"
1247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkPath.h"
13ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon#include "SkPathPriv.h"
1447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkRRect.h"
1547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkTemplates.h"
1647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkTLazy.h"
1747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
1847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon/**
1947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with.
2047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * It is possible to apply the style to the GrShape to produce a new GrShape where the geometry
2147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * reflects the styling information (e.g. is stroked). It is also possible to apply just the
2247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * path effect from the style. In this case the resulting shape will include any remaining
2347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * stroking information that is to be applied after the path effect.
2447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon *
2547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Shapes can produce keys that represent only the geometry information, not the style. Note that
2647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * when styling information is applied to produce a new shape then the style has been converted
2747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * to geometric information and is included in the new shape's key. When the same style is applied
2847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes
2947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * will be the same.
3047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon *
31ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon * Currently this can only be constructed from a path, rect, or rrect though it can become a path
32ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon * applying style to the geometry. The idea is to expand this to cover most or all of the geometries
334f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * that have fast paths in the GPU backend.
3447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon */
3547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomonclass GrShape {
3647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomonpublic:
3767fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon    // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed
3867fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon    // to have to worry about this. This value is exposed for unit tests.
3967fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon    static constexpr int kMaxKeyFromDataVerbCnt = 10;
4067fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon
41728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    GrShape() { this->initType(Type::kEmpty); }
425e410b4a68d11a06c331139905171952ef535cf8bsalomon
43728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    explicit GrShape(const SkPath& path) : GrShape(path, GrStyle::SimpleFill()) {}
4472dc51c288169f38177c71081090581c5ff415b1bsalomon
45728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    explicit GrShape(const SkRRect& rrect) : GrShape(rrect, GrStyle::SimpleFill()) {}
4647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
47728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    explicit GrShape(const SkRect& rect) : GrShape(rect, GrStyle::SimpleFill()) {}
4847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
49da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon    GrShape(const SkPath& path, const GrStyle& style) : fStyle(style) {
50728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->initType(Type::kPath, &path);
511b28c1adc1e156831d5332546e942b63fd29075bbsalomon        this->attemptToSimplifyPath();
5272dc51c288169f38177c71081090581c5ff415b1bsalomon    }
5372dc51c288169f38177c71081090581c5ff415b1bsalomon
5447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    GrShape(const SkRRect& rrect, const GrStyle& style)
55728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        : fStyle(style) {
56728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->initType(Type::kRRect);
57728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fRRect = rrect;
58728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fInverted = false;
59728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, style.hasPathEffect(),
60728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                                                         &fRRectData.fDir);
611b28c1adc1e156831d5332546e942b63fd29075bbsalomon        this->attemptToSimplifyRRect();
62ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon    }
63ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon
647049396b65660907af5292d899053280430d929absalomon    GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, bool inverted,
657049396b65660907af5292d899053280430d929absalomon            const GrStyle& style)
66728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        : fStyle(style) {
67728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->initType(Type::kRRect);
68728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fRRect = rrect;
69728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fInverted = inverted;
70ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        if (style.pathEffect()) {
71728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            fRRectData.fDir = dir;
72728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            fRRectData.fStart = start;
73728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            if (fRRectData.fRRect.getType() == SkRRect::kRect_Type) {
74728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                fRRectData.fStart = (fRRectData.fStart + 1) & 0b110;
75728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            } else if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) {
76728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                fRRectData.fStart &= 0b110;
777049396b65660907af5292d899053280430d929absalomon            }
78ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        } else {
79728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectData.fDir);
80ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        }
811b28c1adc1e156831d5332546e942b63fd29075bbsalomon        this->attemptToSimplifyRRect();
825e410b4a68d11a06c331139905171952ef535cf8bsalomon    }
8347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
8447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    GrShape(const SkRect& rect, const GrStyle& style)
85728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        : fStyle(style) {
86728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->initType(Type::kRRect);
87728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fRRect = SkRRect::MakeRect(rect);
88728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fInverted = false;
89728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fStart = DefaultRectDirAndStartIndex(rect, style.hasPathEffect(),
90728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                                                        &fRRectData.fDir);
911b28c1adc1e156831d5332546e942b63fd29075bbsalomon        this->attemptToSimplifyRRect();
925e410b4a68d11a06c331139905171952ef535cf8bsalomon    }
9347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
94da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon    GrShape(const SkPath& path, const SkPaint& paint) : fStyle(paint) {
95728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->initType(Type::kPath, &path);
961b28c1adc1e156831d5332546e942b63fd29075bbsalomon        this->attemptToSimplifyPath();
9772dc51c288169f38177c71081090581c5ff415b1bsalomon    }
9872dc51c288169f38177c71081090581c5ff415b1bsalomon
9947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    GrShape(const SkRRect& rrect, const SkPaint& paint)
100728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        : fStyle(paint) {
101728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->initType(Type::kRRect);
102728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fRRect = rrect;
103728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fInverted = false;
104728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, fStyle.hasPathEffect(),
105728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                                                         &fRRectData.fDir);
1061b28c1adc1e156831d5332546e942b63fd29075bbsalomon        this->attemptToSimplifyRRect();
1075e410b4a68d11a06c331139905171952ef535cf8bsalomon    }
10847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
10947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    GrShape(const SkRect& rect, const SkPaint& paint)
110728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        : fStyle(paint) {
111728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->initType(Type::kRRect);
112728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fRRect = SkRRect::MakeRect(rect);
113728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fInverted = false;
114728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fRRectData.fStart = DefaultRectDirAndStartIndex(rect, fStyle.hasPathEffect(),
115728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                                                        &fRRectData.fDir);
1161b28c1adc1e156831d5332546e942b63fd29075bbsalomon        this->attemptToSimplifyRRect();
1175e410b4a68d11a06c331139905171952ef535cf8bsalomon    }
11847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
119a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon    static GrShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees,
120a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                           SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style);
121a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon
12247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    GrShape(const GrShape&);
12347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    GrShape& operator=(const GrShape& that);
12447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
125728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    ~GrShape() { this->changeType(Type::kEmpty); }
12647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
1274f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon    /**
1284f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     * Informs MakeFilled on how to modify that shape's fill rule when making a simple filled
1294f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     * version of the shape.
1304f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     */
1314f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon    enum class FillInversion {
1324f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon        kPreserve,
1334f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon        kFlip,
1344f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon        kForceNoninverted,
1354f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon        kForceInverted
1364f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon    };
1374f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon    /**
1384f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     * Makes a filled shape from the pre-styled original shape and optionally modifies whether
1394f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     * the fill is inverted or not. It's important to note that the original shape's geometry
1404f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     * may already have been modified if doing so was neutral with respect to its style
1414f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     * (e.g. filled paths are always closed when stored in a shape and dashed paths are always
1424f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     * made non-inverted since dashing ignores inverseness).
1434f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon     */
1444f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon    static GrShape MakeFilled(const GrShape& original, FillInversion = FillInversion::kPreserve);
1454f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon
14647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    const GrStyle& style() const { return fStyle; }
14747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
14897fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon    /**
14997fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon     * Returns a shape that has either applied the path effect or path effect and stroking
15097fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon     * information from this shape's style to its geometry. Scale is used when approximating the
15197fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon     * output geometry and typically is computed from the view matrix
15297fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon     */
153425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) const {
15497fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon        return GrShape(*this, apply, scale);
15597fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon    }
15647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
1577c73a53894927d222d4aceed96893daae8ea14f1bsalomon    /** Returns the unstyled geometry as a rrect if possible. */
1587049396b65660907af5292d899053280430d929absalomon    bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start, bool* inverted) const {
15947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon        if (Type::kRRect != fType) {
16047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon            return false;
16147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon        }
16247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon        if (rrect) {
163728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            *rrect = fRRectData.fRRect;
16447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon        }
165ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        if (dir) {
166728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            *dir = fRRectData.fDir;
167ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        }
168ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        if (start) {
169728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            *start = fRRectData.fStart;
170ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        }
1717049396b65660907af5292d899053280430d929absalomon        if (inverted) {
172728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            *inverted = fRRectData.fInverted;
1737049396b65660907af5292d899053280430d929absalomon        }
17447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon        return true;
17547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    }
17647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
177398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon    /**
178398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon     * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints.
179398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon     * An inverse filled line path is still considered a line.
180398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon     */
1810a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon    bool asLine(SkPoint pts[2], bool* inverted) const {
1820a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        if (fType != Type::kLine) {
1830a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            return false;
1840a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        }
1850a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        if (pts) {
1860a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            pts[0] = fLineData.fPts[0];
1870a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            pts[1] = fLineData.fPts[1];
1880a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        }
1890a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        if (inverted) {
1900a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            *inverted = fLineData.fInverted;
1910a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        }
1920a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        return true;
1930a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon    }
194398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon
1957c73a53894927d222d4aceed96893daae8ea14f1bsalomon    /** Returns the unstyled geometry as a path. */
19647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    void asPath(SkPath* out) const {
19747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon        switch (fType) {
19806077565b18714ff3fc0db9118e2c21f6f25243fbsalomon            case Type::kEmpty:
19906077565b18714ff3fc0db9118e2c21f6f25243fbsalomon                out->reset();
20006077565b18714ff3fc0db9118e2c21f6f25243fbsalomon                break;
201085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon            case Type::kInvertedEmpty:
202085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                out->reset();
203085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                out->setFillType(kDefaultPathInverseFillType);
204085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                break;
20547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon            case Type::kRRect:
20647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon                out->reset();
207728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                out->addRRect(fRRectData.fRRect, fRRectData.fDir, fRRectData.fStart);
20893f66bc3af522fdd2a5315407ba6d3f65c13fd1cbsalomon                // Below matches the fill type that attemptToSimplifyPath uses.
209728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                if (fRRectData.fInverted) {
210a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon                    out->setFillType(kDefaultPathInverseFillType);
21193f66bc3af522fdd2a5315407ba6d3f65c13fd1cbsalomon                } else {
212a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon                    out->setFillType(kDefaultPathFillType);
2137049396b65660907af5292d899053280430d929absalomon                }
21447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon                break;
215a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            case Type::kArc:
216a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                SkPathPriv::CreateDrawArcPath(out, fArcData.fOval, fArcData.fStartAngleDegrees,
217a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                                              fArcData.fSweepAngleDegrees, fArcData.fUseCenter,
218a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                                              fStyle.isSimpleFill());
219a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                if (fArcData.fInverted) {
220a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                    out->setFillType(kDefaultPathInverseFillType);
221a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                } else {
222a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                    out->setFillType(kDefaultPathFillType);
223a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                }
224a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                break;
2250a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            case Type::kLine:
2260a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                out->reset();
2270a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                out->moveTo(fLineData.fPts[0]);
2280a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                out->lineTo(fLineData.fPts[1]);
2290a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                if (fLineData.fInverted) {
2300a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                    out->setFillType(kDefaultPathInverseFillType);
2310a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                } else {
2320a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                    out->setFillType(kDefaultPathFillType);
2330a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                }
2340a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                break;
23547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon            case Type::kPath:
236728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                *out = this->path();
23747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon                break;
23806077565b18714ff3fc0db9118e2c21f6f25243fbsalomon        }
23906077565b18714ff3fc0db9118e2c21f6f25243fbsalomon    }
24006077565b18714ff3fc0db9118e2c21f6f25243fbsalomon
24106077565b18714ff3fc0db9118e2c21f6f25243fbsalomon    /**
2427c73a53894927d222d4aceed96893daae8ea14f1bsalomon     * Returns whether the geometry is empty. Note that applying the style could produce a
243085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon     * non-empty shape. It also may have an inverse fill.
2447c73a53894927d222d4aceed96893daae8ea14f1bsalomon     */
245085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon    bool isEmpty() const { return Type::kEmpty == fType || Type::kInvertedEmpty == fType; }
2467c73a53894927d222d4aceed96893daae8ea14f1bsalomon
2477049396b65660907af5292d899053280430d929absalomon    /**
2487049396b65660907af5292d899053280430d929absalomon     * Gets the bounds of the geometry without reflecting the shape's styling. This ignores
2497049396b65660907af5292d899053280430d929absalomon     * the inverse fill nature of the geometry.
2507049396b65660907af5292d899053280430d929absalomon     */
2510a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon    SkRect bounds() const;
2529fb420393ee1c24fc3282b7155985fa8fa7bcad4bsalomon
2537049396b65660907af5292d899053280430d929absalomon    /**
2547049396b65660907af5292d899053280430d929absalomon     * Gets the bounds of the geometry reflecting the shape's styling (ignoring inverse fill
2557049396b65660907af5292d899053280430d929absalomon     * status).
2567049396b65660907af5292d899053280430d929absalomon     */
2570a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon    SkRect styledBounds() const;
2589fb420393ee1c24fc3282b7155985fa8fa7bcad4bsalomon
2597c73a53894927d222d4aceed96893daae8ea14f1bsalomon    /**
260425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     * Is this shape known to be convex, before styling is applied. An unclosed but otherwise
261425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     * convex path is considered to be closed if they styling reflects a fill and not otherwise.
262425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     * This is because filling closes all contours in the path.
263425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     */
264425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    bool knownToBeConvex() const {
265425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        switch (fType) {
266425c27fab9d82d19b0bce7c091533d546465bbaebsalomon            case Type::kEmpty:
267425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                return true;
268085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon            case Type::kInvertedEmpty:
269085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                return true;
270425c27fab9d82d19b0bce7c091533d546465bbaebsalomon            case Type::kRRect:
271425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                return true;
272a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            case Type::kArc:
273a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                return SkPathPriv::DrawArcIsConvex(fArcData.fSweepAngleDegrees,
274a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                                                   SkToBool(fArcData.fUseCenter),
275a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                                                   fStyle.isSimpleFill());
2760a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            case Type::kLine:
2770a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                return true;
278425c27fab9d82d19b0bce7c091533d546465bbaebsalomon            case Type::kPath:
279425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                // SkPath.isConvex() really means "is this path convex were it to be closed" and
280425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                // thus doesn't give the correct answer for stroked paths, hence we also check
281425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                // whether the path is either filled or closed. Convex paths may only have one
282425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                // contour hence isLastContourClosed() is a sufficient for a convex path.
283728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                return (this->style().isSimpleFill() || this->path().isLastContourClosed()) &&
284728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                        this->path().isConvex();
285425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        }
286425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        return false;
287425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    }
288425c27fab9d82d19b0bce7c091533d546465bbaebsalomon
289425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    /** Is the pre-styled geometry inverse filled? */
290425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    bool inverseFilled() const {
291425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        bool ret = false;
292425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        switch (fType) {
293425c27fab9d82d19b0bce7c091533d546465bbaebsalomon            case Type::kEmpty:
294425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                ret = false;
295425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                break;
296085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon            case Type::kInvertedEmpty:
297085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                ret = true;
298085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                break;
299425c27fab9d82d19b0bce7c091533d546465bbaebsalomon            case Type::kRRect:
300728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                ret = fRRectData.fInverted;
301425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                break;
302a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            case Type::kArc:
303a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                ret = fArcData.fInverted;
304a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                break;
3050a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            case Type::kLine:
3060a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                ret = fLineData.fInverted;
3070a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                break;
308425c27fab9d82d19b0bce7c091533d546465bbaebsalomon            case Type::kPath:
309728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                ret = this->path().isInverseFillType();
310425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                break;
311425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        }
312425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        // Dashing ignores inverseness. We should have caught this earlier. skbug.com/5421
313425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        SkASSERT(!(ret && this->style().isDashed()));
314425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        return ret;
315425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    }
316425c27fab9d82d19b0bce7c091533d546465bbaebsalomon
317425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    /**
318425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     * Might applying the styling to the geometry produce an inverse fill. The "may" part comes in
319425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     * because an arbitrary path effect could produce an inverse filled path. In other cases this
320425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     * can be thought of as "inverseFilledAfterStyling()".
321425c27fab9d82d19b0bce7c091533d546465bbaebsalomon     */
322425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    bool mayBeInverseFilledAfterStyling() const {
323425c27fab9d82d19b0bce7c091533d546465bbaebsalomon         // An arbitrary path effect can produce an arbitrary output path, which may be inverse
324425c27fab9d82d19b0bce7c091533d546465bbaebsalomon         // filled.
325425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        if (this->style().hasNonDashPathEffect()) {
326425c27fab9d82d19b0bce7c091533d546465bbaebsalomon            return true;
327425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        }
328425c27fab9d82d19b0bce7c091533d546465bbaebsalomon        return this->inverseFilled();
329425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    }
330425c27fab9d82d19b0bce7c091533d546465bbaebsalomon
331425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    /**
3327c73a53894927d222d4aceed96893daae8ea14f1bsalomon     * Is it known that the unstyled geometry has no unclosed contours. This means that it will
3337c73a53894927d222d4aceed96893daae8ea14f1bsalomon     * not have any caps if stroked (modulo the effect of any path effect).
33406077565b18714ff3fc0db9118e2c21f6f25243fbsalomon     */
33506077565b18714ff3fc0db9118e2c21f6f25243fbsalomon    bool knownToBeClosed() const {
33606077565b18714ff3fc0db9118e2c21f6f25243fbsalomon        switch (fType) {
33747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon            case Type::kEmpty:
33806077565b18714ff3fc0db9118e2c21f6f25243fbsalomon                return true;
339085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon            case Type::kInvertedEmpty:
340085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                return true;
34106077565b18714ff3fc0db9118e2c21f6f25243fbsalomon            case Type::kRRect:
34206077565b18714ff3fc0db9118e2c21f6f25243fbsalomon                return true;
343a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            case Type::kArc:
344a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                return fArcData.fUseCenter;
3450a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            case Type::kLine:
3460a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                return false;
34706077565b18714ff3fc0db9118e2c21f6f25243fbsalomon            case Type::kPath:
348425c27fab9d82d19b0bce7c091533d546465bbaebsalomon                // SkPath doesn't keep track of the closed status of each contour.
349728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                return SkPathPriv::IsClosedSingleContour(this->path());
35047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon        }
35106077565b18714ff3fc0db9118e2c21f6f25243fbsalomon        return false;
35247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    }
35347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
35406115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon    uint32_t segmentMask() const {
35506115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon        switch (fType) {
35606115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon            case Type::kEmpty:
35706115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon                return 0;
358085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon            case Type::kInvertedEmpty:
359085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon                return 0;
36006115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon            case Type::kRRect:
361728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) {
36206115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon                    return SkPath::kConic_SegmentMask;
3632fad74a0fdc5eb3f505a052849c3cbeffa6e2d17Brian Salomon                } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type ||
3642fad74a0fdc5eb3f505a052849c3cbeffa6e2d17Brian Salomon                           fRRectData.fRRect.getType() == SkRRect::kEmpty_Type) {
36506115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon                    return SkPath::kLine_SegmentMask;
36606115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon                }
36706115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon                return SkPath::kLine_SegmentMask | SkPath::kConic_SegmentMask;
368a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            case Type::kArc:
369a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                if (fArcData.fUseCenter) {
370a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                    return SkPath::kConic_SegmentMask | SkPath::kLine_SegmentMask;
371a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                }
372a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon                return SkPath::kConic_SegmentMask;
3730a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon            case Type::kLine:
3740a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon                return SkPath::kLine_SegmentMask;
37506115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon            case Type::kPath:
376728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                return this->path().getSegmentMasks();
37706115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon        }
37806115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon        return 0;
37906115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon    }
38006115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon
38147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    /**
38247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     * Gets the size of the key for the shape represented by this GrShape (ignoring its styling).
38347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     * A negative value is returned if the shape has no key (shouldn't be cached).
38447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     */
38547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    int unstyledKeySize() const;
38647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
387425c27fab9d82d19b0bce7c091533d546465bbaebsalomon    bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; }
388425c27fab9d82d19b0bce7c091533d546465bbaebsalomon
38947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    /**
39047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough
39147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     * space allocated for the key and that unstyledKeySize() does not return a negative value
39247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     * for this shape.
39347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     */
39447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    void writeUnstyledKey(uint32_t* key) const;
39547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
396f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman    /**
397f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman     * Adds a listener to the *original* path. Typically used to invalidate cached resources when
398f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman     * a path is no longer in-use. If the shape started out as something other than a path, this
399f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman     * does nothing (but will delete the listener).
400f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman     */
401f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman    void addGenIDChangeListener(SkPathRef::GenIDChangeListener* listener) const;
402f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman
403f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman    /**
404b379dcd64eb69140f4393ac922d0774cc7d15596Brian Osman     * Helpers that are only exposed for unit tests, to determine if the shape is a path, and get
405da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon     * the generation ID of the *original* path. This is the path that will receive
406da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon     * GenIDChangeListeners added to this shape.
407f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman     */
408f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman    uint32_t testingOnly_getOriginalGenerationID() const;
409b379dcd64eb69140f4393ac922d0774cc7d15596Brian Osman    bool testingOnly_isPath() const;
410da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon    bool testingOnly_isNonVolatilePath() const;
411f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman
41247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomonprivate:
41372dc51c288169f38177c71081090581c5ff415b1bsalomon    enum class Type {
41472dc51c288169f38177c71081090581c5ff415b1bsalomon        kEmpty,
415085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon        kInvertedEmpty,
41672dc51c288169f38177c71081090581c5ff415b1bsalomon        kRRect,
417a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon        kArc,
4180a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        kLine,
41972dc51c288169f38177c71081090581c5ff415b1bsalomon        kPath,
42072dc51c288169f38177c71081090581c5ff415b1bsalomon    };
42172dc51c288169f38177c71081090581c5ff415b1bsalomon
422728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    void initType(Type type, const SkPath* path = nullptr) {
423728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fType = Type::kEmpty;
424728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        this->changeType(type, path);
425728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    }
426728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon
427728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    void changeType(Type type, const SkPath* path = nullptr) {
428728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        bool wasPath = Type::kPath == fType;
429728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fType = type;
430728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        bool isPath = Type::kPath == type;
431728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        SkASSERT(!path || isPath);
432728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        if (wasPath && !isPath) {
433728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            fPathData.fPath.~SkPath();
434728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        } else if (!wasPath && isPath) {
435728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            if (path) {
436728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                new (&fPathData.fPath) SkPath(*path);
437728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            } else {
438728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon                new (&fPathData.fPath) SkPath();
439728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            }
440728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        } else if (isPath && path) {
441728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            fPathData.fPath = *path;
442728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        }
443728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        // Whether or not we use the path's gen ID is decided in attemptToSimplifyPath.
444728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        fPathData.fGenID = 0;
445728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    }
446728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon
447728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    SkPath& path() {
448728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        SkASSERT(Type::kPath == fType);
449728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        return fPathData.fPath;
450728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    }
451728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon
452728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    const SkPath& path() const {
453728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        SkASSERT(Type::kPath == fType);
454728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        return fPathData.fPath;
455728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    }
456728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon
45797fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon    /** Constructor used by the applyStyle() function */
45897fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon    GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale);
45947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
46047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    /**
46147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     * Determines the key we should inherit from the input shape's geometry and style when
46247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     * we are applying the style to create a new shape.
46347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon     */
46497fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon    void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar scale);
46547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
4661b28c1adc1e156831d5332546e942b63fd29075bbsalomon    void attemptToSimplifyPath();
4671b28c1adc1e156831d5332546e942b63fd29075bbsalomon    void attemptToSimplifyRRect();
4680a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon    void attemptToSimplifyLine();
469a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon    void attemptToSimplifyArc();
470ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon
47172f78c37010eb2bf20be4884d4f376d122830dfdBrian Salomon    bool attemptToSimplifyStrokedLineToRRect();
47272f78c37010eb2bf20be4884d4f376d122830dfdBrian Salomon
473da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon    /** Gets the path that gen id listeners should be added to. */
474da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon    const SkPath* originalPathForListeners() const;
475da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon
476a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon    // Defaults to use when there is no distinction between even/odd and winding fills.
477a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon    static constexpr SkPath::FillType kDefaultPathFillType = SkPath::kEvenOdd_FillType;
478a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon    static constexpr SkPath::FillType kDefaultPathInverseFillType =
479a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon            SkPath::kInverseEvenOdd_FillType;
480a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon
481ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon    static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction;
482ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon    static constexpr unsigned kDefaultRRectStart = 0;
483ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon
484ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon    static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPathEffect,
485ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon                                                SkPath::Direction* dir) {
486ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        *dir = kDefaultRRectDir;
487ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        // This comes from SkPath's interface. The default for adding a SkRect is counter clockwise
488ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        // beginning at index 0 (which happens to correspond to rrect index 0 or 7).
489ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        if (!hasPathEffect) {
490ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            // It doesn't matter what start we use, just be consistent to avoid redundant keys.
491ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            return kDefaultRRectStart;
49272dc51c288169f38177c71081090581c5ff415b1bsalomon        }
493ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        // In SkPath a rect starts at index 0 by default. This is the top left corner. However,
494ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        // we store rects as rrects. RRects don't preserve the invertedness, but rather sort the
495ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        // rect edges. Thus, we may need to modify the rrect's start index to account for the sort.
496ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        bool swapX = rect.fLeft > rect.fRight;
497ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        bool swapY = rect.fTop > rect.fBottom;
498ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        if (swapX && swapY) {
499ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            // 0 becomes start index 2 and times 2 to convert from rect the rrect indices.
500ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            return 2 * 2;
501ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        } else if (swapX) {
502ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            *dir = SkPath::kCCW_Direction;
503ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            // 0 becomes start index 1 and times 2 to convert from rect the rrect indices.
504ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            return 2 * 1;
505ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        } else if (swapY) {
506ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            *dir = SkPath::kCCW_Direction;
507ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            // 0 becomes start index 3 and times 2 to convert from rect the rrect indices.
508ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            return 2 * 3;
50972dc51c288169f38177c71081090581c5ff415b1bsalomon        }
510ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        return 0;
511ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon    }
512ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon
513ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon    static unsigned DefaultRRectDirAndStartIndex(const SkRRect& rrect, bool hasPathEffect,
514ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon                                                 SkPath::Direction* dir) {
515ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        // This comes from SkPath's interface. The default for adding a SkRRect to a path is
516ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        // clockwise beginning at starting index 6.
517ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        static constexpr unsigned kPathRRectStartIdx = 6;
518ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        *dir = kDefaultRRectDir;
519ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        if (!hasPathEffect) {
520ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            // It doesn't matter what start we use, just be consistent to avoid redundant keys.
521ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon            return kDefaultRRectStart;
52272dc51c288169f38177c71081090581c5ff415b1bsalomon        }
523ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon        return kPathRRectStartIdx;
52472dc51c288169f38177c71081090581c5ff415b1bsalomon    }
52547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon
526728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    union {
527728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        struct {
528a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            SkRRect fRRect;
529a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            SkPath::Direction fDir;
530a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            unsigned fStart;
531a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            bool fInverted;
532728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        } fRRectData;
533728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        struct {
534a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            SkRect fOval;
535a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            SkScalar fStartAngleDegrees;
536a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            SkScalar fSweepAngleDegrees;
537a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            int16_t fUseCenter;
538a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            int16_t fInverted;
539a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon        } fArcData;
540a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon        struct {
541a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            SkPath fPath;
542728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon            // Gen ID of the original path (fPath may be modified)
543a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            int32_t fGenID;
544728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon        } fPathData;
5450a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        struct {
546a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            SkPoint fPts[2];
547a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon            bool fInverted;
5480a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon        } fLineData;
549728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon    };
550a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon    GrStyle fStyle;
551a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon    SkTLazy<SkPath> fInheritedPathForListeners;
55247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon    SkAutoSTArray<8, uint32_t>  fInheritedKey;
553a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon    Type fType;
55447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon};
55547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#endif
556