GrShape.h revision 72dc51c288169f38177c71081090581c5ff415b1
1/* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#ifndef GrShape_DEFINED 9#define GrShape_DEFINED 10 11#include "GrStyle.h" 12#include "SkPath.h" 13#include "SkRRect.h" 14#include "SkTemplates.h" 15#include "SkTLazy.h" 16 17/** 18 * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with. 19 * It is possible to apply the style to the GrShape to produce a new GrShape where the geometry 20 * reflects the styling information (e.g. is stroked). It is also possible to apply just the 21 * path effect from the style. In this case the resulting shape will include any remaining 22 * stroking information that is to be applied after the path effect. 23 * 24 * Shapes can produce keys that represent only the geometry information, not the style. Note that 25 * when styling information is applied to produce a new shape then the style has been converted 26 * to geometric information and is included in the new shape's key. When the same style is applied 27 * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes 28 * will be the same. 29 * 30 * Currently this can only be constructed from a rrect, though it can become a path by applying 31 * style to the geometry. The idea is to expand this to cover most or all of the geometries that 32 * have SkCanvas::draw APIs. 33 */ 34class GrShape { 35public: 36 GrShape(const SkPath& path) 37 : fType(Type::kPath) 38 , fPath(&path) { 39 this->attemptToReduceFromPath(); 40 } 41 42 GrShape() : fType(Type::kEmpty) {} 43 44 explicit GrShape(const SkRRect& rrect) : fType(Type::kRRect), fRRect(rrect) {} 45 explicit GrShape(const SkRect& rect) : fType(Type::kRRect), fRRect(SkRRect::MakeRect(rect)) {} 46 47 GrShape(const SkPath& path, const GrStyle& style) 48 : fType(Type::kPath) 49 , fPath(&path) 50 , fStyle(style) { 51 this->attemptToReduceFromPath(); 52 } 53 54 GrShape(const SkRRect& rrect, const GrStyle& style) 55 : fType(Type::kRRect) 56 , fRRect(rrect) 57 , fStyle(style) {} 58 59 GrShape(const SkRect& rect, const GrStyle& style) 60 : fType(Type::kRRect) 61 , fRRect(SkRRect::MakeRect(rect)) 62 , fStyle(style) {} 63 64 GrShape(const SkPath& path, const SkPaint& paint) 65 : fType(Type::kPath) 66 , fPath(&path) 67 , fStyle(paint) { 68 this->attemptToReduceFromPath(); 69 } 70 71 GrShape(const SkRRect& rrect, const SkPaint& paint) 72 : fType(Type::kRRect) 73 , fRRect(rrect) 74 , fStyle(paint) {} 75 76 GrShape(const SkRect& rect, const SkPaint& paint) 77 : fType(Type::kRRect) 78 , fRRect(SkRRect::MakeRect(rect)) 79 , fStyle(paint) {} 80 81 GrShape(const GrShape&); 82 GrShape& operator=(const GrShape& that); 83 84 ~GrShape() { 85 if (Type::kPath == fType) { 86 fPath.reset(); 87 } 88 } 89 90 const GrStyle& style() const { return fStyle; } 91 92 /** 93 * Returns a GrShape where the shape's geometry fully reflects the original shape's GrStyle. 94 * The GrStyle of the returned shape will either be fill or hairline. 95 */ 96 GrShape applyFullStyle() { return GrShape(*this, false); } 97 98 /** 99 * Similar to above but applies only the path effect. Path effects take the original geometry 100 * and fill/stroking information and compute a new geometry and residual fill/stroking 101 * information to be applied. The path effect's output geometry and stroking will be captured 102 * in the returned GrShape. 103 */ 104 GrShape applyPathEffect() { return GrShape(*this, true); } 105 106 bool asRRect(SkRRect* rrect) const { 107 if (Type::kRRect != fType) { 108 return false; 109 } 110 if (rrect) { 111 *rrect = fRRect; 112 } 113 return true; 114 } 115 116 void asPath(SkPath* out) const { 117 switch (fType) { 118 case Type::kRRect: 119 out->reset(); 120 out->addRRect(fRRect); 121 break; 122 case Type::kPath: 123 *out = *fPath.get(); 124 break; 125 case Type::kEmpty: 126 out->reset(); 127 break; 128 } 129 } 130 131 /** 132 * Gets the size of the key for the shape represented by this GrShape (ignoring its styling). 133 * A negative value is returned if the shape has no key (shouldn't be cached). 134 */ 135 int unstyledKeySize() const; 136 137 /** 138 * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough 139 * space allocated for the key and that unstyledKeySize() does not return a negative value 140 * for this shape. 141 */ 142 void writeUnstyledKey(uint32_t* key) const; 143 144private: 145 enum class Type { 146 kEmpty, 147 kRRect, 148 kPath, 149 }; 150 151 /** 152 * Computes the key length for a GrStyle. The return will be negative if it cannot be turned 153 * into a key. 154 */ 155 static int StyleKeySize(const GrStyle& , bool stopAfterPE); 156 157 /** 158 * Writes a unique key for the style into the provided buffer. This function assumes the buffer 159 * has room for at least StyleKeySize() values. It assumes that StyleKeySize() returns a 160 * positive value for the style and stopAfterPE param. This is written so that the key for just 161 * dash application followed by the key for the remaining SkStrokeRec is the same as the 162 * key for applying dashing and SkStrokeRec all at once. 163 */ 164 static void StyleKey(uint32_t*, const GrStyle&, bool stopAfterPE); 165 166 /** Constructor used by Apply* functions */ 167 GrShape(const GrShape& parentShape, bool stopAfterPE); 168 169 /** 170 * Determines the key we should inherit from the input shape's geometry and style when 171 * we are applying the style to create a new shape. 172 */ 173 void setInheritedKey(const GrShape& parentShape, bool stopAfterPE); 174 175 void attemptToReduceFromPath() { 176 SkASSERT(Type::kPath == fType); 177 fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, fStyle.pathEffect(), 178 fStyle.strokeRec()); 179 if (Type::kPath != fType) { 180 fPath.reset(); 181 fInheritedKey.reset(0); 182 } 183 } 184 185 static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, 186 const SkPathEffect* pe, const SkStrokeRec& strokeRec) { 187 if (path.isEmpty()) { 188 return Type::kEmpty; 189 } 190 if (path.isRRect(rrect)) { 191 return Type::kRRect; 192 } 193 SkRect rect; 194 if (path.isOval(&rect)) { 195 rrect->setOval(rect); 196 return Type::kRRect; 197 } 198 bool closed; 199 if (path.isRect(&rect, &closed, nullptr)) { 200 if (closed || (!pe && strokeRec.isFillStyle())) { 201 rrect->setRect(rect); 202 return Type::kRRect; 203 } 204 } 205 return Type::kPath; 206 } 207 208 Type fType; 209 SkRRect fRRect; 210 SkTLazy<SkPath> fPath; 211 GrStyle fStyle; 212 SkAutoSTArray<8, uint32_t> fInheritedKey; 213}; 214#endif 215