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      * Returns a C++11-iterable object that traverses a path's verbs in order. e.g:
110      *
111      *   for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {
112      *       ...
113      *   }
114      */
115     struct Verbs {
116     public:
VerbsVerbs117         Verbs(const SkPath& path) : fPathRef(path.fPathRef.get()) {}
118         struct Iter {
119             void operator++() { --fVerb; } // verbs are laid out backwards in memory.
120             bool operator!=(const Iter& b) { return fVerb != b.fVerb; }
121             SkPath::Verb operator*() { return static_cast<SkPath::Verb>(*fVerb); }
122             const uint8_t* fVerb;
123         };
beginVerbs124         Iter begin() { return Iter{fPathRef->verbs() - 1}; }
endVerbs125         Iter end() { return Iter{fPathRef->verbs() - fPathRef->countVerbs() - 1}; }
126     private:
127         Verbs(const Verbs&) = delete;
128         Verbs& operator=(const Verbs&) = delete;
129         SkPathRef* fPathRef;
130     };
131 
132     /**
133      * Returns a pointer to the verb data. Note that the verbs are stored backwards in memory and
134      * thus the returned pointer is the last verb.
135      */
VerbData(const SkPath & path)136     static const uint8_t* VerbData(const SkPath& path) {
137         return path.fPathRef->verbsMemBegin();
138     }
139 
140     /** Returns a raw pointer to the path points */
PointData(const SkPath & path)141     static const SkPoint* PointData(const SkPath& path) {
142         return path.fPathRef->points();
143     }
144 
145     /** Returns the number of conic weights in the path */
ConicWeightCnt(const SkPath & path)146     static int ConicWeightCnt(const SkPath& path) {
147         return path.fPathRef->countWeights();
148     }
149 
150     /** Returns a raw pointer to the path conic weights. */
ConicWeightData(const SkPath & path)151     static const SkScalar* ConicWeightData(const SkPath& path) {
152         return path.fPathRef->conicWeights();
153     }
154 
155     /** Returns true if the underlying SkPathRef has one single owner. */
TestingOnly_unique(const SkPath & path)156     static bool TestingOnly_unique(const SkPath& path) {
157         return path.fPathRef->unique();
158     }
159 
160 };
161 
162 #endif
163