1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef GrStyledShape_DEFINED
9cb93a386Sopenharmony_ci#define GrStyledShape_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
12cb93a386Sopenharmony_ci#include "include/core/SkRRect.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
14cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
15cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h"
17cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrShape.h"
18cb93a386Sopenharmony_ci#include <new>
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ciclass SkIDChangeListener;
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci/**
23cb93a386Sopenharmony_ci * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with.
24cb93a386Sopenharmony_ci * It is possible to apply the style to the GrStyledShape to produce a new GrStyledShape where the
25cb93a386Sopenharmony_ci * geometry reflects the styling information (e.g. is stroked). It is also possible to apply just
26cb93a386Sopenharmony_ci * the path effect from the style. In this case the resulting shape will include any remaining
27cb93a386Sopenharmony_ci * stroking information that is to be applied after the path effect.
28cb93a386Sopenharmony_ci *
29cb93a386Sopenharmony_ci * Shapes can produce keys that represent only the geometry information, not the style. Note that
30cb93a386Sopenharmony_ci * when styling information is applied to produce a new shape then the style has been converted
31cb93a386Sopenharmony_ci * to geometric information and is included in the new shape's key. When the same style is applied
32cb93a386Sopenharmony_ci * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes
33cb93a386Sopenharmony_ci * will be the same.
34cb93a386Sopenharmony_ci *
35cb93a386Sopenharmony_ci * Currently this can only be constructed from a path, rect, or rrect though it can become a path
36cb93a386Sopenharmony_ci * applying style to the geometry. The idea is to expand this to cover most or all of the geometries
37cb93a386Sopenharmony_ci * that have fast paths in the GPU backend.
38cb93a386Sopenharmony_ci */
39cb93a386Sopenharmony_ciclass GrStyledShape {
40cb93a386Sopenharmony_cipublic:
41cb93a386Sopenharmony_ci    // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed
42cb93a386Sopenharmony_ci    // to have to worry about this. This value is exposed for unit tests.
43cb93a386Sopenharmony_ci    inline static constexpr int kMaxKeyFromDataVerbCnt = 10;
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci    GrStyledShape() {}
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    enum class DoSimplify : bool { kNo = false, kYes };
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci    explicit GrStyledShape(const SkPath& path, DoSimplify doSimplify = DoSimplify::kYes)
50cb93a386Sopenharmony_ci            : GrStyledShape(path, GrStyle::SimpleFill(), doSimplify) {}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    explicit GrStyledShape(const SkRRect& rrect, DoSimplify doSimplify = DoSimplify::kYes)
53cb93a386Sopenharmony_ci            : GrStyledShape(rrect, GrStyle::SimpleFill(), doSimplify) {}
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    explicit GrStyledShape(const SkRect& rect, DoSimplify doSimplify = DoSimplify::kYes)
56cb93a386Sopenharmony_ci            : GrStyledShape(rect, GrStyle::SimpleFill(), doSimplify) {}
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    GrStyledShape(const SkPath& path, const SkPaint& paint,
59cb93a386Sopenharmony_ci                  DoSimplify doSimplify = DoSimplify::kYes)
60cb93a386Sopenharmony_ci            : GrStyledShape(path, GrStyle(paint), doSimplify) {}
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci    GrStyledShape(const SkRRect& rrect, const SkPaint& paint,
63cb93a386Sopenharmony_ci                  DoSimplify doSimplify = DoSimplify::kYes)
64cb93a386Sopenharmony_ci            : GrStyledShape(rrect, GrStyle(paint), doSimplify) {}
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    GrStyledShape(const SkRect& rect, const SkPaint& paint,
67cb93a386Sopenharmony_ci                  DoSimplify doSimplify = DoSimplify::kYes)
68cb93a386Sopenharmony_ci            : GrStyledShape(rect, GrStyle(paint), doSimplify) {}
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    GrStyledShape(const SkPath& path, const GrStyle& style,
71cb93a386Sopenharmony_ci                  DoSimplify doSimplify = DoSimplify::kYes)
72cb93a386Sopenharmony_ci            : fShape(path), fStyle(style) {
73cb93a386Sopenharmony_ci        if (doSimplify == DoSimplify::kYes) {
74cb93a386Sopenharmony_ci            this->simplify();
75cb93a386Sopenharmony_ci        }
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    GrStyledShape(const SkRRect& rrect, const GrStyle& style,
79cb93a386Sopenharmony_ci                  DoSimplify doSimplify = DoSimplify::kYes)
80cb93a386Sopenharmony_ci            : fShape(rrect), fStyle(style) {
81cb93a386Sopenharmony_ci        if (doSimplify == DoSimplify::kYes) {
82cb93a386Sopenharmony_ci            this->simplify();
83cb93a386Sopenharmony_ci        }
84cb93a386Sopenharmony_ci    }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    GrStyledShape(const SkRRect& rrect, SkPathDirection dir, unsigned start, bool inverted,
87cb93a386Sopenharmony_ci                  const GrStyle& style, DoSimplify doSimplify = DoSimplify::kYes)
88cb93a386Sopenharmony_ci            : fShape(rrect)
89cb93a386Sopenharmony_ci            , fStyle(style) {
90cb93a386Sopenharmony_ci        fShape.setPathWindingParams(dir, start);
91cb93a386Sopenharmony_ci        fShape.setInverted(inverted);
92cb93a386Sopenharmony_ci        if (doSimplify == DoSimplify::kYes) {
93cb93a386Sopenharmony_ci            this->simplify();
94cb93a386Sopenharmony_ci        }
95cb93a386Sopenharmony_ci    }
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci    GrStyledShape(const SkRect& rect, const GrStyle& style,
98cb93a386Sopenharmony_ci                  DoSimplify doSimplify = DoSimplify::kYes)
99cb93a386Sopenharmony_ci            : fShape(rect), fStyle(style) {
100cb93a386Sopenharmony_ci        if (doSimplify == DoSimplify::kYes) {
101cb93a386Sopenharmony_ci            this->simplify();
102cb93a386Sopenharmony_ci        }
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci    GrStyledShape(const GrStyledShape&);
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci    static GrStyledShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees,
108cb93a386Sopenharmony_ci                                 SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style,
109cb93a386Sopenharmony_ci                                 DoSimplify = DoSimplify::kYes);
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci    GrStyledShape& operator=(const GrStyledShape& that);
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    /**
114cb93a386Sopenharmony_ci     * Informs MakeFilled on how to modify that shape's fill rule when making a simple filled
115cb93a386Sopenharmony_ci     * version of the shape.
116cb93a386Sopenharmony_ci     */
117cb93a386Sopenharmony_ci    enum class FillInversion {
118cb93a386Sopenharmony_ci        kPreserve,
119cb93a386Sopenharmony_ci        kFlip,
120cb93a386Sopenharmony_ci        kForceNoninverted,
121cb93a386Sopenharmony_ci        kForceInverted
122cb93a386Sopenharmony_ci    };
123cb93a386Sopenharmony_ci    /**
124cb93a386Sopenharmony_ci     * Makes a filled shape from the pre-styled original shape and optionally modifies whether
125cb93a386Sopenharmony_ci     * the fill is inverted or not. It's important to note that the original shape's geometry
126cb93a386Sopenharmony_ci     * may already have been modified if doing so was neutral with respect to its style
127cb93a386Sopenharmony_ci     * (e.g. filled paths are always closed when stored in a shape and dashed paths are always
128cb93a386Sopenharmony_ci     * made non-inverted since dashing ignores inverseness).
129cb93a386Sopenharmony_ci     */
130cb93a386Sopenharmony_ci    static GrStyledShape MakeFilled(const GrStyledShape& original,
131cb93a386Sopenharmony_ci                                    FillInversion = FillInversion::kPreserve);
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    const GrStyle& style() const { return fStyle; }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    // True if the shape and/or style were modified into a simpler, equivalent pairing
136cb93a386Sopenharmony_ci    bool simplified() const { return fSimplified; }
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci    /**
139cb93a386Sopenharmony_ci     * Returns a shape that has either applied the path effect or path effect and stroking
140cb93a386Sopenharmony_ci     * information from this shape's style to its geometry. Scale is used when approximating the
141cb93a386Sopenharmony_ci     * output geometry and typically is computed from the view matrix
142cb93a386Sopenharmony_ci     */
143cb93a386Sopenharmony_ci    GrStyledShape applyStyle(GrStyle::Apply apply, SkScalar scale) const {
144cb93a386Sopenharmony_ci        return GrStyledShape(*this, apply, scale);
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci    bool isRect() const {
148cb93a386Sopenharmony_ci        // Should have simplified a rrect to a rect if possible already.
149cb93a386Sopenharmony_ci        SkASSERT(!fShape.isRRect() || !fShape.rrect().isRect());
150cb93a386Sopenharmony_ci        return fShape.isRect();
151cb93a386Sopenharmony_ci    }
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci    /** Returns the unstyled geometry as a rrect if possible. */
154cb93a386Sopenharmony_ci    bool asRRect(SkRRect* rrect, SkPathDirection* dir, unsigned* start, bool* inverted) const;
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    /**
157cb93a386Sopenharmony_ci     * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints.
158cb93a386Sopenharmony_ci     * An inverse filled line path is still considered a line.
159cb93a386Sopenharmony_ci     */
160cb93a386Sopenharmony_ci    bool asLine(SkPoint pts[2], bool* inverted) const;
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci    // Can this shape be drawn as a pair of filled nested rectangles?
163cb93a386Sopenharmony_ci    bool asNestedRects(SkRect rects[2]) const;
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_ci    /** Returns the unstyled geometry as a path. */
166cb93a386Sopenharmony_ci    void asPath(SkPath* out) const {
167cb93a386Sopenharmony_ci        fShape.asPath(out, fStyle.isSimpleFill());
168cb93a386Sopenharmony_ci    }
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci    /**
171cb93a386Sopenharmony_ci     * Returns whether the geometry is empty. Note that applying the style could produce a
172cb93a386Sopenharmony_ci     * non-empty shape. It also may have an inverse fill.
173cb93a386Sopenharmony_ci     */
174cb93a386Sopenharmony_ci    bool isEmpty() const { return fShape.isEmpty(); }
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci    /**
177cb93a386Sopenharmony_ci     * Gets the bounds of the geometry without reflecting the shape's styling. This ignores
178cb93a386Sopenharmony_ci     * the inverse fill nature of the geometry.
179cb93a386Sopenharmony_ci     */
180cb93a386Sopenharmony_ci    SkRect bounds() const { return fShape.bounds(); }
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    /**
183cb93a386Sopenharmony_ci     * Gets the bounds of the geometry reflecting the shape's styling (ignoring inverse fill
184cb93a386Sopenharmony_ci     * status).
185cb93a386Sopenharmony_ci     */
186cb93a386Sopenharmony_ci    SkRect styledBounds() const;
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci    /**
189cb93a386Sopenharmony_ci     * Is this shape known to be convex, before styling is applied. An unclosed but otherwise
190cb93a386Sopenharmony_ci     * convex path is considered to be closed if they styling reflects a fill and not otherwise.
191cb93a386Sopenharmony_ci     * This is because filling closes all contours in the path.
192cb93a386Sopenharmony_ci     */
193cb93a386Sopenharmony_ci    bool knownToBeConvex() const {
194cb93a386Sopenharmony_ci        return fShape.convex(fStyle.isSimpleFill());
195cb93a386Sopenharmony_ci    }
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ci    /**
198cb93a386Sopenharmony_ci     * Does the shape have a known winding direction. Some degenerate convex shapes may not have
199cb93a386Sopenharmony_ci     * a computable direction, but this is not always a requirement for path renderers so it is
200cb93a386Sopenharmony_ci     * kept separate from knownToBeConvex().
201cb93a386Sopenharmony_ci     */
202cb93a386Sopenharmony_ci    bool knownDirection() const {
203cb93a386Sopenharmony_ci        // Assuming this is called after knownToBeConvex(), this should just be relying on
204cb93a386Sopenharmony_ci        // cached convexity and direction and will be cheap.
205cb93a386Sopenharmony_ci        return !fShape.isPath() ||
206cb93a386Sopenharmony_ci               SkPathPriv::ComputeFirstDirection(fShape.path()) != SkPathFirstDirection::kUnknown;
207cb93a386Sopenharmony_ci    }
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ci    /** Is the pre-styled geometry inverse filled? */
210cb93a386Sopenharmony_ci    bool inverseFilled() const {
211cb93a386Sopenharmony_ci        // Since the path tracks inverted-fillness itself, it should match what was recorded.
212cb93a386Sopenharmony_ci        SkASSERT(!fShape.isPath() || fShape.inverted() == fShape.path().isInverseFillType());
213cb93a386Sopenharmony_ci        // Dashing ignores inverseness. We should have caught this earlier. skbug.com/5421
214cb93a386Sopenharmony_ci        SkASSERT(!(fShape.inverted() && this->style().isDashed()));
215cb93a386Sopenharmony_ci        return fShape.inverted();
216cb93a386Sopenharmony_ci    }
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    /**
219cb93a386Sopenharmony_ci     * Might applying the styling to the geometry produce an inverse fill. The "may" part comes in
220cb93a386Sopenharmony_ci     * because an arbitrary path effect could produce an inverse filled path. In other cases this
221cb93a386Sopenharmony_ci     * can be thought of as "inverseFilledAfterStyling()".
222cb93a386Sopenharmony_ci     */
223cb93a386Sopenharmony_ci    bool mayBeInverseFilledAfterStyling() const {
224cb93a386Sopenharmony_ci         // An arbitrary path effect can produce an arbitrary output path, which may be inverse
225cb93a386Sopenharmony_ci         // filled.
226cb93a386Sopenharmony_ci        if (this->style().hasNonDashPathEffect()) {
227cb93a386Sopenharmony_ci            return true;
228cb93a386Sopenharmony_ci        }
229cb93a386Sopenharmony_ci        return this->inverseFilled();
230cb93a386Sopenharmony_ci    }
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci    /**
233cb93a386Sopenharmony_ci     * Is it known that the unstyled geometry has no unclosed contours. This means that it will
234cb93a386Sopenharmony_ci     * not have any caps if stroked (modulo the effect of any path effect).
235cb93a386Sopenharmony_ci     */
236cb93a386Sopenharmony_ci    bool knownToBeClosed() const {
237cb93a386Sopenharmony_ci        // This refers to the base shape and does not depend on invertedness.
238cb93a386Sopenharmony_ci        return fShape.closed();
239cb93a386Sopenharmony_ci    }
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci    uint32_t segmentMask() const {
242cb93a386Sopenharmony_ci        // This refers to the base shape and does not depend on invertedness.
243cb93a386Sopenharmony_ci        return fShape.segmentMask();
244cb93a386Sopenharmony_ci    }
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_ci    /**
247cb93a386Sopenharmony_ci     * Gets the size of the key for the shape represented by this GrStyledShape (ignoring its
248cb93a386Sopenharmony_ci     * styling). A negative value is returned if the shape has no key (shouldn't be cached).
249cb93a386Sopenharmony_ci     */
250cb93a386Sopenharmony_ci    int unstyledKeySize() const;
251cb93a386Sopenharmony_ci
252cb93a386Sopenharmony_ci    bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; }
253cb93a386Sopenharmony_ci
254cb93a386Sopenharmony_ci    /**
255cb93a386Sopenharmony_ci     * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough
256cb93a386Sopenharmony_ci     * space allocated for the key and that unstyledKeySize() does not return a negative value
257cb93a386Sopenharmony_ci     * for this shape.
258cb93a386Sopenharmony_ci     */
259cb93a386Sopenharmony_ci    void writeUnstyledKey(uint32_t* key) const;
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ci    /**
262cb93a386Sopenharmony_ci     * Adds a listener to the *original* path. Typically used to invalidate cached resources when
263cb93a386Sopenharmony_ci     * a path is no longer in-use. If the shape started out as something other than a path, this
264cb93a386Sopenharmony_ci     * does nothing.
265cb93a386Sopenharmony_ci     */
266cb93a386Sopenharmony_ci    void addGenIDChangeListener(sk_sp<SkIDChangeListener>) const;
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci    /**
269cb93a386Sopenharmony_ci     * Helpers that are only exposed for unit tests, to determine if the shape is a path, and get
270cb93a386Sopenharmony_ci     * the generation ID of the *original* path. This is the path that will receive
271cb93a386Sopenharmony_ci     * GenIDChangeListeners added to this shape.
272cb93a386Sopenharmony_ci     */
273cb93a386Sopenharmony_ci    uint32_t testingOnly_getOriginalGenerationID() const;
274cb93a386Sopenharmony_ci    bool testingOnly_isPath() const;
275cb93a386Sopenharmony_ci    bool testingOnly_isNonVolatilePath() const;
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci    /**
278cb93a386Sopenharmony_ci     * Similar to GrShape::simplify but also takes into account style and stroking, possibly
279cb93a386Sopenharmony_ci     * applying the style explicitly to produce a new analytic shape with a simpler style.
280cb93a386Sopenharmony_ci     * Unless "doSimplify" is kNo, this method gets called automatically during construction.
281cb93a386Sopenharmony_ci     */
282cb93a386Sopenharmony_ci    void simplify();
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ciprivate:
285cb93a386Sopenharmony_ci    /** Constructor used by the applyStyle() function */
286cb93a386Sopenharmony_ci    GrStyledShape(const GrStyledShape& parentShape, GrStyle::Apply, SkScalar scale);
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_ci    /**
289cb93a386Sopenharmony_ci     * Determines the key we should inherit from the input shape's geometry and style when
290cb93a386Sopenharmony_ci     * we are applying the style to create a new shape.
291cb93a386Sopenharmony_ci     */
292cb93a386Sopenharmony_ci    void setInheritedKey(const GrStyledShape& parentShape, GrStyle::Apply, SkScalar scale);
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci    /**
295cb93a386Sopenharmony_ci     * As part of the simplification process, some shapes can have stroking trivially evaluated
296cb93a386Sopenharmony_ci     * and form a new geometry with just a fill.
297cb93a386Sopenharmony_ci     */
298cb93a386Sopenharmony_ci    void simplifyStroke();
299cb93a386Sopenharmony_ci
300cb93a386Sopenharmony_ci    /** Gets the path that gen id listeners should be added to. */
301cb93a386Sopenharmony_ci    const SkPath* originalPathForListeners() const;
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci    GrShape fShape;
304cb93a386Sopenharmony_ci    GrStyle fStyle;
305cb93a386Sopenharmony_ci    // Gen ID of the original path (path may be modified or simplified away).
306cb93a386Sopenharmony_ci    int32_t fGenID      = 0;
307cb93a386Sopenharmony_ci    bool    fClosed     = false;
308cb93a386Sopenharmony_ci    bool    fSimplified = false;
309cb93a386Sopenharmony_ci
310cb93a386Sopenharmony_ci    SkTLazy<SkPath>            fInheritedPathForListeners;
311cb93a386Sopenharmony_ci    SkAutoSTArray<8, uint32_t> fInheritedKey;
312cb93a386Sopenharmony_ci};
313cb93a386Sopenharmony_ci#endif
314