1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 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 SkPathPriv_DEFINED 9cb93a386Sopenharmony_ci#define SkPathPriv_DEFINED 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h" 12cb93a386Sopenharmony_ci#include "include/private/SkIDChangeListener.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_cistatic_assert(0 == static_cast<int>(SkPathFillType::kWinding), "fill_type_mismatch"); 15cb93a386Sopenharmony_cistatic_assert(1 == static_cast<int>(SkPathFillType::kEvenOdd), "fill_type_mismatch"); 16cb93a386Sopenharmony_cistatic_assert(2 == static_cast<int>(SkPathFillType::kInverseWinding), "fill_type_mismatch"); 17cb93a386Sopenharmony_cistatic_assert(3 == static_cast<int>(SkPathFillType::kInverseEvenOdd), "fill_type_mismatch"); 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ciclass SK_API SkPathPriv { 20cb93a386Sopenharmony_cipublic: 21cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 22cb93a386Sopenharmony_ci static const int kPathRefGenIDBitCnt = 30; // leave room for the fill type (skbug.com/1762) 23cb93a386Sopenharmony_ci#else 24cb93a386Sopenharmony_ci static const int kPathRefGenIDBitCnt = 32; 25cb93a386Sopenharmony_ci#endif 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci // skbug.com/9906: Not a perfect solution for W plane clipping, but 1/16384 is a 28cb93a386Sopenharmony_ci // reasonable limit (roughly 5e-5) 29cb93a386Sopenharmony_ci inline static constexpr SkScalar kW0PlaneDistance = 1.f / (1 << 14); 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci static SkPathFirstDirection AsFirstDirection(SkPathDirection dir) { 32cb93a386Sopenharmony_ci // since we agree numerically for the values in Direction, we can just cast. 33cb93a386Sopenharmony_ci return (SkPathFirstDirection)dir; 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci /** 37cb93a386Sopenharmony_ci * Return the opposite of the specified direction. kUnknown is its own 38cb93a386Sopenharmony_ci * opposite. 39cb93a386Sopenharmony_ci */ 40cb93a386Sopenharmony_ci static SkPathFirstDirection OppositeFirstDirection(SkPathFirstDirection dir) { 41cb93a386Sopenharmony_ci static const SkPathFirstDirection gOppositeDir[] = { 42cb93a386Sopenharmony_ci SkPathFirstDirection::kCCW, SkPathFirstDirection::kCW, SkPathFirstDirection::kUnknown, 43cb93a386Sopenharmony_ci }; 44cb93a386Sopenharmony_ci return gOppositeDir[(unsigned)dir]; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci /** 48cb93a386Sopenharmony_ci * Tries to compute the direction of the outer-most non-degenerate 49cb93a386Sopenharmony_ci * contour. If it can be computed, return that direction. If it cannot be determined, 50cb93a386Sopenharmony_ci * or the contour is known to be convex, return kUnknown. If the direction was determined, 51cb93a386Sopenharmony_ci * it is cached to make subsequent calls return quickly. 52cb93a386Sopenharmony_ci */ 53cb93a386Sopenharmony_ci static SkPathFirstDirection ComputeFirstDirection(const SkPath&); 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci static bool IsClosedSingleContour(const SkPath& path) { 56cb93a386Sopenharmony_ci int verbCount = path.countVerbs(); 57cb93a386Sopenharmony_ci if (verbCount == 0) 58cb93a386Sopenharmony_ci return false; 59cb93a386Sopenharmony_ci int moveCount = 0; 60cb93a386Sopenharmony_ci auto verbs = path.fPathRef->verbsBegin(); 61cb93a386Sopenharmony_ci for (int i = 0; i < verbCount; i++) { 62cb93a386Sopenharmony_ci switch (verbs[i]) { 63cb93a386Sopenharmony_ci case SkPath::Verb::kMove_Verb: 64cb93a386Sopenharmony_ci moveCount += 1; 65cb93a386Sopenharmony_ci if (moveCount > 1) { 66cb93a386Sopenharmony_ci return false; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci break; 69cb93a386Sopenharmony_ci case SkPath::Verb::kClose_Verb: 70cb93a386Sopenharmony_ci if (i == verbCount - 1) { 71cb93a386Sopenharmony_ci return true; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci return false; 74cb93a386Sopenharmony_ci default: break; 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci return false; 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci // In some scenarios (e.g. fill or convexity checking all but the last leading move to are 81cb93a386Sopenharmony_ci // irrelevant to behavior). SkPath::injectMoveToIfNeeded should ensure that this is always at 82cb93a386Sopenharmony_ci // least 1. 83cb93a386Sopenharmony_ci static int LeadingMoveToCount(const SkPath& path) { 84cb93a386Sopenharmony_ci int verbCount = path.countVerbs(); 85cb93a386Sopenharmony_ci auto verbs = path.fPathRef->verbsBegin(); 86cb93a386Sopenharmony_ci for (int i = 0; i < verbCount; i++) { 87cb93a386Sopenharmony_ci if (verbs[i] != SkPath::Verb::kMove_Verb) { 88cb93a386Sopenharmony_ci return i; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci return verbCount; // path is all move verbs 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci static void AddGenIDChangeListener(const SkPath& path, sk_sp<SkIDChangeListener> listener) { 95cb93a386Sopenharmony_ci path.fPathRef->addGenIDChangeListener(std::move(listener)); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci /** 99cb93a386Sopenharmony_ci * This returns true for a rect that has a move followed by 3 or 4 lines and a close. If 100cb93a386Sopenharmony_ci * 'isSimpleFill' is true, an uncloseed rect will also be accepted as long as it starts and 101cb93a386Sopenharmony_ci * ends at the same corner. This does not permit degenerate line or point rectangles. 102cb93a386Sopenharmony_ci */ 103cb93a386Sopenharmony_ci static bool IsSimpleRect(const SkPath& path, bool isSimpleFill, SkRect* rect, 104cb93a386Sopenharmony_ci SkPathDirection* direction, unsigned* start); 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci /** 107cb93a386Sopenharmony_ci * Creates a path from arc params using the semantics of SkCanvas::drawArc. This function 108cb93a386Sopenharmony_ci * assumes empty ovals and zero sweeps have already been filtered out. 109cb93a386Sopenharmony_ci */ 110cb93a386Sopenharmony_ci static void CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle, 111cb93a386Sopenharmony_ci SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci /** 114cb93a386Sopenharmony_ci * Determines whether an arc produced by CreateDrawArcPath will be convex. Assumes a non-empty 115cb93a386Sopenharmony_ci * oval. 116cb93a386Sopenharmony_ci */ 117cb93a386Sopenharmony_ci static bool DrawArcIsConvex(SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect); 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci static void ShrinkToFit(SkPath* path) { 120cb93a386Sopenharmony_ci path->shrinkToFit(); 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci /** 124cb93a386Sopenharmony_ci * Returns a C++11-iterable object that traverses a path's verbs in order. e.g: 125cb93a386Sopenharmony_ci * 126cb93a386Sopenharmony_ci * for (SkPath::Verb verb : SkPathPriv::Verbs(path)) { 127cb93a386Sopenharmony_ci * ... 128cb93a386Sopenharmony_ci * } 129cb93a386Sopenharmony_ci */ 130cb93a386Sopenharmony_ci struct Verbs { 131cb93a386Sopenharmony_ci public: 132cb93a386Sopenharmony_ci Verbs(const SkPath& path) : fPathRef(path.fPathRef.get()) {} 133cb93a386Sopenharmony_ci struct Iter { 134cb93a386Sopenharmony_ci void operator++() { fVerb++; } 135cb93a386Sopenharmony_ci bool operator!=(const Iter& b) { return fVerb != b.fVerb; } 136cb93a386Sopenharmony_ci SkPath::Verb operator*() { return static_cast<SkPath::Verb>(*fVerb); } 137cb93a386Sopenharmony_ci const uint8_t* fVerb; 138cb93a386Sopenharmony_ci }; 139cb93a386Sopenharmony_ci Iter begin() { return Iter{fPathRef->verbsBegin()}; } 140cb93a386Sopenharmony_ci Iter end() { return Iter{fPathRef->verbsEnd()}; } 141cb93a386Sopenharmony_ci private: 142cb93a386Sopenharmony_ci Verbs(const Verbs&) = delete; 143cb93a386Sopenharmony_ci Verbs& operator=(const Verbs&) = delete; 144cb93a386Sopenharmony_ci SkPathRef* fPathRef; 145cb93a386Sopenharmony_ci }; 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci /** 148cb93a386Sopenharmony_ci * Iterates through a raw range of path verbs, points, and conics. All values are returned 149cb93a386Sopenharmony_ci * unaltered. 150cb93a386Sopenharmony_ci * 151cb93a386Sopenharmony_ci * NOTE: This class's definition will be moved into SkPathPriv once RangeIter is removed. 152cb93a386Sopenharmony_ci */ 153cb93a386Sopenharmony_ci using RangeIter = SkPath::RangeIter; 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci /** 156cb93a386Sopenharmony_ci * Iterable object for traversing verbs, points, and conic weights in a path: 157cb93a386Sopenharmony_ci * 158cb93a386Sopenharmony_ci * for (auto [verb, pts, weights] : SkPathPriv::Iterate(skPath)) { 159cb93a386Sopenharmony_ci * ... 160cb93a386Sopenharmony_ci * } 161cb93a386Sopenharmony_ci */ 162cb93a386Sopenharmony_ci struct Iterate { 163cb93a386Sopenharmony_ci public: 164cb93a386Sopenharmony_ci Iterate(const SkPath& path) 165cb93a386Sopenharmony_ci : Iterate(path.fPathRef->verbsBegin(), 166cb93a386Sopenharmony_ci // Don't allow iteration through non-finite points. 167cb93a386Sopenharmony_ci (!path.isFinite()) ? path.fPathRef->verbsBegin() 168cb93a386Sopenharmony_ci : path.fPathRef->verbsEnd(), 169cb93a386Sopenharmony_ci path.fPathRef->points(), path.fPathRef->conicWeights()) { 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci Iterate(const uint8_t* verbsBegin, const uint8_t* verbsEnd, const SkPoint* points, 172cb93a386Sopenharmony_ci const SkScalar* weights) 173cb93a386Sopenharmony_ci : fVerbsBegin(verbsBegin), fVerbsEnd(verbsEnd), fPoints(points), fWeights(weights) { 174cb93a386Sopenharmony_ci } 175cb93a386Sopenharmony_ci SkPath::RangeIter begin() { return {fVerbsBegin, fPoints, fWeights}; } 176cb93a386Sopenharmony_ci SkPath::RangeIter end() { return {fVerbsEnd, nullptr, nullptr}; } 177cb93a386Sopenharmony_ci private: 178cb93a386Sopenharmony_ci const uint8_t* fVerbsBegin; 179cb93a386Sopenharmony_ci const uint8_t* fVerbsEnd; 180cb93a386Sopenharmony_ci const SkPoint* fPoints; 181cb93a386Sopenharmony_ci const SkScalar* fWeights; 182cb93a386Sopenharmony_ci }; 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci /** 185cb93a386Sopenharmony_ci * Returns a pointer to the verb data. 186cb93a386Sopenharmony_ci */ 187cb93a386Sopenharmony_ci static const uint8_t* VerbData(const SkPath& path) { 188cb93a386Sopenharmony_ci return path.fPathRef->verbsBegin(); 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci /** Returns a raw pointer to the path points */ 192cb93a386Sopenharmony_ci static const SkPoint* PointData(const SkPath& path) { 193cb93a386Sopenharmony_ci return path.fPathRef->points(); 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci /** Returns the number of conic weights in the path */ 197cb93a386Sopenharmony_ci static int ConicWeightCnt(const SkPath& path) { 198cb93a386Sopenharmony_ci return path.fPathRef->countWeights(); 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci /** Returns a raw pointer to the path conic weights. */ 202cb93a386Sopenharmony_ci static const SkScalar* ConicWeightData(const SkPath& path) { 203cb93a386Sopenharmony_ci return path.fPathRef->conicWeights(); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci /** Returns true if the underlying SkPathRef has one single owner. */ 207cb93a386Sopenharmony_ci static bool TestingOnly_unique(const SkPath& path) { 208cb93a386Sopenharmony_ci return path.fPathRef->unique(); 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci 211cb93a386Sopenharmony_ci // Won't be needed once we can make path's immutable (with their bounds always computed) 212cb93a386Sopenharmony_ci static bool HasComputedBounds(const SkPath& path) { 213cb93a386Sopenharmony_ci return path.hasComputedBounds(); 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci /** Returns true if constructed by addCircle(), addOval(); and in some cases, 217cb93a386Sopenharmony_ci addRoundRect(), addRRect(). SkPath constructed with conicTo() or rConicTo() will not 218cb93a386Sopenharmony_ci return true though SkPath draws oval. 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci rect receives bounds of oval. 221cb93a386Sopenharmony_ci dir receives SkPathDirection of oval: kCW_Direction if clockwise, kCCW_Direction if 222cb93a386Sopenharmony_ci counterclockwise. 223cb93a386Sopenharmony_ci start receives start of oval: 0 for top, 1 for right, 2 for bottom, 3 for left. 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci rect, dir, and start are unmodified if oval is not found. 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci Triggers performance optimizations on some GPU surface implementations. 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci @param rect storage for bounding SkRect of oval; may be nullptr 230cb93a386Sopenharmony_ci @param dir storage for SkPathDirection; may be nullptr 231cb93a386Sopenharmony_ci @param start storage for start of oval; may be nullptr 232cb93a386Sopenharmony_ci @return true if SkPath was constructed by method that reduces to oval 233cb93a386Sopenharmony_ci */ 234cb93a386Sopenharmony_ci static bool IsOval(const SkPath& path, SkRect* rect, SkPathDirection* dir, unsigned* start) { 235cb93a386Sopenharmony_ci bool isCCW = false; 236cb93a386Sopenharmony_ci bool result = path.fPathRef->isOval(rect, &isCCW, start); 237cb93a386Sopenharmony_ci if (dir && result) { 238cb93a386Sopenharmony_ci *dir = isCCW ? SkPathDirection::kCCW : SkPathDirection::kCW; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci return result; 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci /** Returns true if constructed by addRoundRect(), addRRect(); and if construction 244cb93a386Sopenharmony_ci is not empty, not SkRect, and not oval. SkPath constructed with other calls 245cb93a386Sopenharmony_ci will not return true though SkPath draws SkRRect. 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ci rrect receives bounds of SkRRect. 248cb93a386Sopenharmony_ci dir receives SkPathDirection of oval: kCW_Direction if clockwise, kCCW_Direction if 249cb93a386Sopenharmony_ci counterclockwise. 250cb93a386Sopenharmony_ci start receives start of SkRRect: 0 for top, 1 for right, 2 for bottom, 3 for left. 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci rrect, dir, and start are unmodified if SkRRect is not found. 253cb93a386Sopenharmony_ci 254cb93a386Sopenharmony_ci Triggers performance optimizations on some GPU surface implementations. 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci @param rrect storage for bounding SkRect of SkRRect; may be nullptr 257cb93a386Sopenharmony_ci @param dir storage for SkPathDirection; may be nullptr 258cb93a386Sopenharmony_ci @param start storage for start of SkRRect; may be nullptr 259cb93a386Sopenharmony_ci @return true if SkPath contains only SkRRect 260cb93a386Sopenharmony_ci */ 261cb93a386Sopenharmony_ci static bool IsRRect(const SkPath& path, SkRRect* rrect, SkPathDirection* dir, 262cb93a386Sopenharmony_ci unsigned* start) { 263cb93a386Sopenharmony_ci bool isCCW = false; 264cb93a386Sopenharmony_ci bool result = path.fPathRef->isRRect(rrect, &isCCW, start); 265cb93a386Sopenharmony_ci if (dir && result) { 266cb93a386Sopenharmony_ci *dir = isCCW ? SkPathDirection::kCCW : SkPathDirection::kCW; 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci return result; 269cb93a386Sopenharmony_ci } 270cb93a386Sopenharmony_ci 271cb93a386Sopenharmony_ci /** 272cb93a386Sopenharmony_ci * Sometimes in the drawing pipeline, we have to perform math on path coordinates, even after 273cb93a386Sopenharmony_ci * the path is in device-coordinates. Tessellation and clipping are two examples. Usually this 274cb93a386Sopenharmony_ci * is pretty modest, but it can involve subtracting/adding coordinates, or multiplying by 275cb93a386Sopenharmony_ci * small constants (e.g. 2,3,4). To try to preflight issues where these optionations could turn 276cb93a386Sopenharmony_ci * finite path values into infinities (or NaNs), we allow the upper drawing code to reject 277cb93a386Sopenharmony_ci * the path if its bounds (in device coordinates) is too close to max float. 278cb93a386Sopenharmony_ci */ 279cb93a386Sopenharmony_ci static bool TooBigForMath(const SkRect& bounds) { 280cb93a386Sopenharmony_ci // This value is just a guess. smaller is safer, but we don't want to reject largish paths 281cb93a386Sopenharmony_ci // that we don't have to. 282cb93a386Sopenharmony_ci constexpr SkScalar scale_down_to_allow_for_small_multiplies = 0.25f; 283cb93a386Sopenharmony_ci constexpr SkScalar max = SK_ScalarMax * scale_down_to_allow_for_small_multiplies; 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci // use ! expression so we return true if bounds contains NaN 286cb93a386Sopenharmony_ci return !(bounds.fLeft >= -max && bounds.fTop >= -max && 287cb93a386Sopenharmony_ci bounds.fRight <= max && bounds.fBottom <= max); 288cb93a386Sopenharmony_ci } 289cb93a386Sopenharmony_ci static bool TooBigForMath(const SkPath& path) { 290cb93a386Sopenharmony_ci return TooBigForMath(path.getBounds()); 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci // Returns number of valid points for each SkPath::Iter verb 294cb93a386Sopenharmony_ci static int PtsInIter(unsigned verb) { 295cb93a386Sopenharmony_ci static const uint8_t gPtsInVerb[] = { 296cb93a386Sopenharmony_ci 1, // kMove pts[0] 297cb93a386Sopenharmony_ci 2, // kLine pts[0..1] 298cb93a386Sopenharmony_ci 3, // kQuad pts[0..2] 299cb93a386Sopenharmony_ci 3, // kConic pts[0..2] 300cb93a386Sopenharmony_ci 4, // kCubic pts[0..3] 301cb93a386Sopenharmony_ci 0, // kClose 302cb93a386Sopenharmony_ci 0 // kDone 303cb93a386Sopenharmony_ci }; 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb)); 306cb93a386Sopenharmony_ci return gPtsInVerb[verb]; 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci // Returns number of valid points for each verb, not including the "starter" 310cb93a386Sopenharmony_ci // point that the Iterator adds for line/quad/conic/cubic 311cb93a386Sopenharmony_ci static int PtsInVerb(unsigned verb) { 312cb93a386Sopenharmony_ci static const uint8_t gPtsInVerb[] = { 313cb93a386Sopenharmony_ci 1, // kMove pts[0] 314cb93a386Sopenharmony_ci 1, // kLine pts[0..1] 315cb93a386Sopenharmony_ci 2, // kQuad pts[0..2] 316cb93a386Sopenharmony_ci 2, // kConic pts[0..2] 317cb93a386Sopenharmony_ci 3, // kCubic pts[0..3] 318cb93a386Sopenharmony_ci 0, // kClose 319cb93a386Sopenharmony_ci 0 // kDone 320cb93a386Sopenharmony_ci }; 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb)); 323cb93a386Sopenharmony_ci return gPtsInVerb[verb]; 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci 326cb93a386Sopenharmony_ci static bool IsAxisAligned(const SkPath& path); 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci static bool AllPointsEq(const SkPoint pts[], int count) { 329cb93a386Sopenharmony_ci for (int i = 1; i < count; ++i) { 330cb93a386Sopenharmony_ci if (pts[0] != pts[i]) { 331cb93a386Sopenharmony_ci return false; 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci return true; 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci static int LastMoveToIndex(const SkPath& path) { return path.fLastMoveToIndex; } 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_ci static bool IsRectContour(const SkPath&, bool allowPartial, int* currVerb, 340cb93a386Sopenharmony_ci const SkPoint** ptsPtr, bool* isClosed, SkPathDirection* direction, 341cb93a386Sopenharmony_ci SkRect* rect); 342cb93a386Sopenharmony_ci 343cb93a386Sopenharmony_ci /** Returns true if SkPath is equivalent to nested SkRect pair when filled. 344cb93a386Sopenharmony_ci If false, rect and dirs are unchanged. 345cb93a386Sopenharmony_ci If true, rect and dirs are written to if not nullptr: 346cb93a386Sopenharmony_ci setting rect[0] to outer SkRect, and rect[1] to inner SkRect; 347cb93a386Sopenharmony_ci setting dirs[0] to SkPathDirection of outer SkRect, and dirs[1] to SkPathDirection of 348cb93a386Sopenharmony_ci inner SkRect. 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci @param rect storage for SkRect pair; may be nullptr 351cb93a386Sopenharmony_ci @param dirs storage for SkPathDirection pair; may be nullptr 352cb93a386Sopenharmony_ci @return true if SkPath contains nested SkRect pair 353cb93a386Sopenharmony_ci */ 354cb93a386Sopenharmony_ci static bool IsNestedFillRects(const SkPath&, SkRect rect[2], 355cb93a386Sopenharmony_ci SkPathDirection dirs[2] = nullptr); 356cb93a386Sopenharmony_ci 357cb93a386Sopenharmony_ci static bool IsInverseFillType(SkPathFillType fill) { 358cb93a386Sopenharmony_ci return (static_cast<int>(fill) & 2) != 0; 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci /** Returns equivalent SkPath::FillType representing SkPath fill inside its bounds. 362cb93a386Sopenharmony_ci . 363cb93a386Sopenharmony_ci 364cb93a386Sopenharmony_ci @param fill one of: kWinding_FillType, kEvenOdd_FillType, 365cb93a386Sopenharmony_ci kInverseWinding_FillType, kInverseEvenOdd_FillType 366cb93a386Sopenharmony_ci @return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted 367cb93a386Sopenharmony_ci */ 368cb93a386Sopenharmony_ci static SkPathFillType ConvertToNonInverseFillType(SkPathFillType fill) { 369cb93a386Sopenharmony_ci return (SkPathFillType)(static_cast<int>(fill) & 1); 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci 372cb93a386Sopenharmony_ci /** 373cb93a386Sopenharmony_ci * If needed (to not blow-up under a perspective matrix), clip the path, returning the 374cb93a386Sopenharmony_ci * answer in "result", and return true. 375cb93a386Sopenharmony_ci * 376cb93a386Sopenharmony_ci * Note result might be empty (if the path was completely clipped out). 377cb93a386Sopenharmony_ci * 378cb93a386Sopenharmony_ci * If no clipping is needed, returns false and "result" is left unchanged. 379cb93a386Sopenharmony_ci */ 380cb93a386Sopenharmony_ci static bool PerspectiveClip(const SkPath& src, const SkMatrix&, SkPath* result); 381cb93a386Sopenharmony_ci 382cb93a386Sopenharmony_ci /** 383cb93a386Sopenharmony_ci * Gets the number of GenIDChangeListeners. If another thread has access to this path then 384cb93a386Sopenharmony_ci * this may be stale before return and only indicates that the count was the return value 385cb93a386Sopenharmony_ci * at some point during the execution of the function. 386cb93a386Sopenharmony_ci */ 387cb93a386Sopenharmony_ci static int GenIDChangeListenersCount(const SkPath&); 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_ci static void UpdatePathPoint(SkPath* path, int index, const SkPoint& pt) { 390cb93a386Sopenharmony_ci SkASSERT(index < path->countPoints()); 391cb93a386Sopenharmony_ci SkPathRef::Editor ed(&path->fPathRef); 392cb93a386Sopenharmony_ci ed.writablePoints()[index] = pt; 393cb93a386Sopenharmony_ci path->dirtyAfterEdit(); 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci 396cb93a386Sopenharmony_ci static SkPathConvexity GetConvexity(const SkPath& path) { 397cb93a386Sopenharmony_ci return path.getConvexity(); 398cb93a386Sopenharmony_ci } 399cb93a386Sopenharmony_ci static SkPathConvexity GetConvexityOrUnknown(const SkPath& path) { 400cb93a386Sopenharmony_ci return path.getConvexityOrUnknown(); 401cb93a386Sopenharmony_ci } 402cb93a386Sopenharmony_ci static void SetConvexity(const SkPath& path, SkPathConvexity c) { 403cb93a386Sopenharmony_ci path.setConvexity(c); 404cb93a386Sopenharmony_ci } 405cb93a386Sopenharmony_ci static void SetConvexity(SkPathBuilder* builder, SkPathConvexity c) { 406cb93a386Sopenharmony_ci builder->privateSetConvexity(c); 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci static void ForceComputeConvexity(const SkPath& path) { 409cb93a386Sopenharmony_ci path.setConvexity(SkPathConvexity::kUnknown); 410cb93a386Sopenharmony_ci (void)path.isConvex(); 411cb93a386Sopenharmony_ci } 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci static void ReverseAddPath(SkPathBuilder* builder, const SkPath& reverseMe) { 414cb93a386Sopenharmony_ci builder->privateReverseAddPath(reverseMe); 415cb93a386Sopenharmony_ci } 416cb93a386Sopenharmony_ci}; 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ci// Lightweight variant of SkPath::Iter that only returns segments (e.g. lines/conics). 419cb93a386Sopenharmony_ci// Does not return kMove or kClose. 420cb93a386Sopenharmony_ci// Always "auto-closes" each contour. 421cb93a386Sopenharmony_ci// Roughly the same as SkPath::Iter(path, true), but does not return moves or closes 422cb93a386Sopenharmony_ci// 423cb93a386Sopenharmony_ciclass SkPathEdgeIter { 424cb93a386Sopenharmony_ci const uint8_t* fVerbs; 425cb93a386Sopenharmony_ci const uint8_t* fVerbsStop; 426cb93a386Sopenharmony_ci const SkPoint* fPts; 427cb93a386Sopenharmony_ci const SkPoint* fMoveToPtr; 428cb93a386Sopenharmony_ci const SkScalar* fConicWeights; 429cb93a386Sopenharmony_ci SkPoint fScratch[2]; // for auto-close lines 430cb93a386Sopenharmony_ci bool fNeedsCloseLine; 431cb93a386Sopenharmony_ci bool fNextIsNewContour; 432cb93a386Sopenharmony_ci SkDEBUGCODE(bool fIsConic); 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci enum { 435cb93a386Sopenharmony_ci kIllegalEdgeValue = 99 436cb93a386Sopenharmony_ci }; 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_cipublic: 439cb93a386Sopenharmony_ci SkPathEdgeIter(const SkPath& path); 440cb93a386Sopenharmony_ci 441cb93a386Sopenharmony_ci SkScalar conicWeight() const { 442cb93a386Sopenharmony_ci SkASSERT(fIsConic); 443cb93a386Sopenharmony_ci return *fConicWeights; 444cb93a386Sopenharmony_ci } 445cb93a386Sopenharmony_ci 446cb93a386Sopenharmony_ci enum class Edge { 447cb93a386Sopenharmony_ci kLine = SkPath::kLine_Verb, 448cb93a386Sopenharmony_ci kQuad = SkPath::kQuad_Verb, 449cb93a386Sopenharmony_ci kConic = SkPath::kConic_Verb, 450cb93a386Sopenharmony_ci kCubic = SkPath::kCubic_Verb, 451cb93a386Sopenharmony_ci }; 452cb93a386Sopenharmony_ci 453cb93a386Sopenharmony_ci static SkPath::Verb EdgeToVerb(Edge e) { 454cb93a386Sopenharmony_ci return SkPath::Verb(e); 455cb93a386Sopenharmony_ci } 456cb93a386Sopenharmony_ci 457cb93a386Sopenharmony_ci struct Result { 458cb93a386Sopenharmony_ci const SkPoint* fPts; // points for the segment, or null if done 459cb93a386Sopenharmony_ci Edge fEdge; 460cb93a386Sopenharmony_ci bool fIsNewContour; 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci // Returns true when it holds an Edge, false when the path is done. 463cb93a386Sopenharmony_ci operator bool() { return fPts != nullptr; } 464cb93a386Sopenharmony_ci }; 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_ci Result next() { 467cb93a386Sopenharmony_ci auto closeline = [&]() { 468cb93a386Sopenharmony_ci fScratch[0] = fPts[-1]; 469cb93a386Sopenharmony_ci fScratch[1] = *fMoveToPtr; 470cb93a386Sopenharmony_ci fNeedsCloseLine = false; 471cb93a386Sopenharmony_ci fNextIsNewContour = true; 472cb93a386Sopenharmony_ci return Result{ fScratch, Edge::kLine, false }; 473cb93a386Sopenharmony_ci }; 474cb93a386Sopenharmony_ci 475cb93a386Sopenharmony_ci for (;;) { 476cb93a386Sopenharmony_ci SkASSERT(fVerbs <= fVerbsStop); 477cb93a386Sopenharmony_ci if (fVerbs == fVerbsStop) { 478cb93a386Sopenharmony_ci return fNeedsCloseLine 479cb93a386Sopenharmony_ci ? closeline() 480cb93a386Sopenharmony_ci : Result{ nullptr, Edge(kIllegalEdgeValue), false }; 481cb93a386Sopenharmony_ci } 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci SkDEBUGCODE(fIsConic = false;) 484cb93a386Sopenharmony_ci 485cb93a386Sopenharmony_ci const auto v = *fVerbs++; 486cb93a386Sopenharmony_ci switch (v) { 487cb93a386Sopenharmony_ci case SkPath::kMove_Verb: { 488cb93a386Sopenharmony_ci if (fNeedsCloseLine) { 489cb93a386Sopenharmony_ci auto res = closeline(); 490cb93a386Sopenharmony_ci fMoveToPtr = fPts++; 491cb93a386Sopenharmony_ci return res; 492cb93a386Sopenharmony_ci } 493cb93a386Sopenharmony_ci fMoveToPtr = fPts++; 494cb93a386Sopenharmony_ci fNextIsNewContour = true; 495cb93a386Sopenharmony_ci } break; 496cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 497cb93a386Sopenharmony_ci if (fNeedsCloseLine) return closeline(); 498cb93a386Sopenharmony_ci break; 499cb93a386Sopenharmony_ci default: { 500cb93a386Sopenharmony_ci // Actual edge. 501cb93a386Sopenharmony_ci const int pts_count = (v+2) / 2, 502cb93a386Sopenharmony_ci cws_count = (v & (v-1)) / 2; 503cb93a386Sopenharmony_ci SkASSERT(pts_count == SkPathPriv::PtsInIter(v) - 1); 504cb93a386Sopenharmony_ci 505cb93a386Sopenharmony_ci fNeedsCloseLine = true; 506cb93a386Sopenharmony_ci fPts += pts_count; 507cb93a386Sopenharmony_ci fConicWeights += cws_count; 508cb93a386Sopenharmony_ci 509cb93a386Sopenharmony_ci SkDEBUGCODE(fIsConic = (v == SkPath::kConic_Verb);) 510cb93a386Sopenharmony_ci SkASSERT(fIsConic == (cws_count > 0)); 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci bool isNewContour = fNextIsNewContour; 513cb93a386Sopenharmony_ci fNextIsNewContour = false; 514cb93a386Sopenharmony_ci return { &fPts[-(pts_count + 1)], Edge(v), isNewContour }; 515cb93a386Sopenharmony_ci } 516cb93a386Sopenharmony_ci } 517cb93a386Sopenharmony_ci } 518cb93a386Sopenharmony_ci } 519cb93a386Sopenharmony_ci}; 520cb93a386Sopenharmony_ci 521cb93a386Sopenharmony_ci#endif 522