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