1 /* 2 * Copyright 2015 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 SkPathPriv_DEFINED 9 #define SkPathPriv_DEFINED 10 11 #include "SkPath.h" 12 13 class SkPathPriv { 14 public: 15 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 16 static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762) 17 #else 18 static const int kPathRefGenIDBitCnt = 32; 19 #endif 20 21 enum FirstDirection { 22 kCW_FirstDirection, // == SkPath::kCW_Direction 23 kCCW_FirstDirection, // == SkPath::kCCW_Direction 24 kUnknown_FirstDirection, 25 }; 26 AsFirstDirection(SkPath::Direction dir)27 static FirstDirection AsFirstDirection(SkPath::Direction dir) { 28 // since we agree numerically for the values in Direction, we can just cast. 29 return (FirstDirection)dir; 30 } 31 32 /** 33 * Return the opposite of the specified direction. kUnknown is its own 34 * opposite. 35 */ OppositeFirstDirection(FirstDirection dir)36 static FirstDirection OppositeFirstDirection(FirstDirection dir) { 37 static const FirstDirection gOppositeDir[] = { 38 kCCW_FirstDirection, kCW_FirstDirection, kUnknown_FirstDirection, 39 }; 40 return gOppositeDir[dir]; 41 } 42 43 /** 44 * Tries to quickly compute the direction of the first non-degenerate 45 * contour. If it can be computed, return true and set dir to that 46 * direction. If it cannot be (quickly) determined, return false and ignore 47 * the dir parameter. If the direction was determined, it is cached to make 48 * subsequent calls return quickly. 49 */ 50 static bool CheapComputeFirstDirection(const SkPath&, FirstDirection* dir); 51 52 /** 53 * Returns true if the path's direction can be computed via 54 * cheapComputDirection() and if that computed direction matches the 55 * specified direction. If dir is kUnknown, returns true if the direction 56 * cannot be computed. 57 */ CheapIsFirstDirection(const SkPath & path,FirstDirection dir)58 static bool CheapIsFirstDirection(const SkPath& path, FirstDirection dir) { 59 FirstDirection computedDir = kUnknown_FirstDirection; 60 (void)CheapComputeFirstDirection(path, &computedDir); 61 return computedDir == dir; 62 } 63 IsClosedSingleContour(const SkPath & path)64 static bool IsClosedSingleContour(const SkPath& path) { 65 int verbCount = path.countVerbs(); 66 if (verbCount == 0) 67 return false; 68 int moveCount = 0; 69 auto verbs = path.fPathRef->verbs(); 70 for (int i = 0; i < verbCount; i++) { 71 switch (verbs[~i]) { // verbs are stored backwards; we use [~i] to get the i'th verb 72 case SkPath::Verb::kMove_Verb: 73 moveCount += 1; 74 if (moveCount > 1) { 75 return false; 76 } 77 break; 78 case SkPath::Verb::kClose_Verb: 79 if (i == verbCount - 1) { 80 return true; 81 } 82 return false; 83 default: break; 84 } 85 } 86 return false; 87 } 88 AddGenIDChangeListener(const SkPath & path,SkPathRef::GenIDChangeListener * listener)89 static void AddGenIDChangeListener(const SkPath& path, SkPathRef::GenIDChangeListener* listener) { 90 path.fPathRef->addGenIDChangeListener(listener); 91 } 92 93 /** 94 * This returns true for a rect that begins and ends at the same corner and has either a move 95 * followed by four lines or a move followed by 3 lines and a close. None of the parameters are 96 * optional. This does not permit degenerate line or point rectangles. 97 */ 98 static bool IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction, 99 unsigned* start); 100 101 /** 102 * Creates a path from arc params using the semantics of SkCanvas::drawArc. This function 103 * assumes empty ovals and zero sweeps have already been filtered out. 104 */ 105 static void CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle, 106 SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect); 107 108 /** 109 * Determines whether an arc produced by CreateDrawArcPath will be convex. Assumes a non-empty 110 * oval. 111 */ 112 static bool DrawArcIsConvex(SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect); 113 114 /** 115 * Returns a C++11-iterable object that traverses a path's verbs in order. e.g: 116 * 117 * for (SkPath::Verb verb : SkPathPriv::Verbs(path)) { 118 * ... 119 * } 120 */ 121 struct Verbs { 122 public: VerbsVerbs123 Verbs(const SkPath& path) : fPathRef(path.fPathRef.get()) {} 124 struct Iter { 125 void operator++() { --fVerb; } // verbs are laid out backwards in memory. 126 bool operator!=(const Iter& b) { return fVerb != b.fVerb; } 127 SkPath::Verb operator*() { return static_cast<SkPath::Verb>(*fVerb); } 128 const uint8_t* fVerb; 129 }; beginVerbs130 Iter begin() { return Iter{fPathRef->verbs() - 1}; } endVerbs131 Iter end() { return Iter{fPathRef->verbs() - fPathRef->countVerbs() - 1}; } 132 private: 133 Verbs(const Verbs&) = delete; 134 Verbs& operator=(const Verbs&) = delete; 135 SkPathRef* fPathRef; 136 }; 137 138 /** 139 * Returns a pointer to the verb data. Note that the verbs are stored backwards in memory and 140 * thus the returned pointer is the last verb. 141 */ VerbData(const SkPath & path)142 static const uint8_t* VerbData(const SkPath& path) { 143 return path.fPathRef->verbsMemBegin(); 144 } 145 146 /** Returns a raw pointer to the path points */ PointData(const SkPath & path)147 static const SkPoint* PointData(const SkPath& path) { 148 return path.fPathRef->points(); 149 } 150 151 /** Returns the number of conic weights in the path */ ConicWeightCnt(const SkPath & path)152 static int ConicWeightCnt(const SkPath& path) { 153 return path.fPathRef->countWeights(); 154 } 155 156 /** Returns a raw pointer to the path conic weights. */ ConicWeightData(const SkPath & path)157 static const SkScalar* ConicWeightData(const SkPath& path) { 158 return path.fPathRef->conicWeights(); 159 } 160 161 /** Returns true if the underlying SkPathRef has one single owner. */ TestingOnly_unique(const SkPath & path)162 static bool TestingOnly_unique(const SkPath& path) { 163 return path.fPathRef->unique(); 164 } 165 166 /** Returns true if constructed by addCircle(), addOval(); and in some cases, 167 addRoundRect(), addRRect(). SkPath constructed with conicTo() or rConicTo() will not 168 return true though SkPath draws oval. 169 170 rect receives bounds of oval. 171 dir receives SkPath::Direction of oval: kCW_Direction if clockwise, kCCW_Direction if 172 counterclockwise. 173 start receives start of oval: 0 for top, 1 for right, 2 for bottom, 3 for left. 174 175 rect, dir, and start are unmodified if oval is not found. 176 177 Triggers performance optimizations on some GPU surface implementations. 178 179 @param rect storage for bounding SkRect of oval; may be nullptr 180 @param dir storage for SkPath::Direction; may be nullptr 181 @param start storage for start of oval; may be nullptr 182 @return true if SkPath was constructed by method that reduces to oval 183 */ IsOval(const SkPath & path,SkRect * rect,SkPath::Direction * dir,unsigned * start)184 static bool IsOval(const SkPath& path, SkRect* rect, SkPath::Direction* dir, unsigned* start) { 185 bool isCCW = false; 186 bool result = path.fPathRef->isOval(rect, &isCCW, start); 187 if (dir && result) { 188 *dir = isCCW ? SkPath::kCCW_Direction : SkPath::kCW_Direction; 189 } 190 return result; 191 } 192 193 /** Returns true if constructed by addRoundRect(), addRRect(); and if construction 194 is not empty, not SkRect, and not oval. SkPath constructed with other calls 195 will not return true though SkPath draws SkRRect. 196 197 rrect receives bounds of SkRRect. 198 dir receives SkPath::Direction of oval: kCW_Direction if clockwise, kCCW_Direction if 199 counterclockwise. 200 start receives start of SkRRect: 0 for top, 1 for right, 2 for bottom, 3 for left. 201 202 rrect, dir, and start are unmodified if SkRRect is not found. 203 204 Triggers performance optimizations on some GPU surface implementations. 205 206 @param rrect storage for bounding SkRect of SkRRect; may be nullptr 207 @param dir storage for SkPath::Direction; may be nullptr 208 @param start storage for start of SkRRect; may be nullptr 209 @return true if SkPath contains only SkRRect 210 */ IsRRect(const SkPath & path,SkRRect * rrect,SkPath::Direction * dir,unsigned * start)211 static bool IsRRect(const SkPath& path, SkRRect* rrect, SkPath::Direction* dir, 212 unsigned* start) { 213 bool isCCW = false; 214 bool result = path.fPathRef->isRRect(rrect, &isCCW, start); 215 if (dir && result) { 216 *dir = isCCW ? SkPath::kCCW_Direction : SkPath::kCW_Direction; 217 } 218 return result; 219 } 220 }; 221 222 #endif 223