• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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