1 /*
2  * Copyright 2014 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 GrStrokeInfo_DEFINED
9 #define GrStrokeInfo_DEFINED
10 
11 #include "SkStrokeRec.h"
12 #include "SkPathEffect.h"
13 
14 /*
15  * GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec
16  * which holds information on fill style, width, miter, cap, and join. It also holds information
17  * about the dash like intervals, count, and phase.
18  */
19 class GrStrokeInfo {
20 public:
GrStrokeInfo(SkStrokeRec::InitStyle style)21     GrStrokeInfo(SkStrokeRec::InitStyle style) :
22         fStroke(style), fDashType(SkPathEffect::kNone_DashType) {}
23 
24     GrStrokeInfo(const GrStrokeInfo& src, bool includeDash = true) : fStroke(src.fStroke) {
25         if (includeDash && src.isDashed()) {
26             fDashType = src.fDashType;
27             fDashPhase = src.fDashPhase;
28             fIntervals.reset(src.getDashCount());
29             memcpy(fIntervals.get(), src.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
30         } else {
31             fDashType = SkPathEffect::kNone_DashType;
32         }
33     }
34 
GrStrokeInfo(const SkPaint & paint,SkPaint::Style styleOverride)35     GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride) :
36         fStroke(paint, styleOverride), fDashType(SkPathEffect::kNone_DashType) {
37         this->init(paint);
38     }
39 
GrStrokeInfo(const SkPaint & paint)40     explicit GrStrokeInfo(const SkPaint& paint) :
41         fStroke(paint), fDashType(SkPathEffect::kNone_DashType) {
42         this->init(paint);
43     }
44 
45     GrStrokeInfo& operator=(const GrStrokeInfo& other) {
46         if (other.isDashed()) {
47             fDashType = other.fDashType;
48             fDashPhase = other.fDashPhase;
49             fIntervals.reset(other.getDashCount());
50             memcpy(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
51         } else {
52             this->removeDash();
53         }
54         fStroke = other.fStroke;
55         return *this;
56     }
57 
getStrokeRec()58     const SkStrokeRec& getStrokeRec() const { return fStroke; }
59 
getStrokeRecPtr()60     SkStrokeRec* getStrokeRecPtr() { return &fStroke; }
61 
setFillStyle()62     void setFillStyle() { fStroke.setFillStyle(); }
63 
64     /*
65      * This functions takes in a patheffect and updates the dashing information if the path effect
66      * is a Dash type. Returns true if the path effect is a dashed effect and we are stroking,
67      * otherwise it returns false.
68      */
setDashInfo(const SkPathEffect * pe)69     bool setDashInfo(const SkPathEffect* pe) {
70         if (pe && !fStroke.isFillStyle()) {
71             SkPathEffect::DashInfo dashInfo;
72             fDashType = pe->asADash(&dashInfo);
73             if (SkPathEffect::kDash_DashType == fDashType) {
74                 fIntervals.reset(dashInfo.fCount);
75                 dashInfo.fIntervals = fIntervals.get();
76                 pe->asADash(&dashInfo);
77                 fDashPhase = dashInfo.fPhase;
78                 return true;
79             }
80         }
81         return false;
82     }
83 
84     /*
85      * Like the above, but sets with an explicit SkPathEffect::DashInfo
86      */
setDashInfo(const SkPathEffect::DashInfo & info)87     bool setDashInfo(const SkPathEffect::DashInfo& info) {
88         if (!fStroke.isFillStyle()) {
89             SkASSERT(!fStroke.isFillStyle());
90             fDashType = SkPathEffect::kDash_DashType;
91             fDashPhase = info.fPhase;
92             fIntervals.reset(info.fCount);
93             for (int i = 0; i < fIntervals.count(); i++) {
94                 fIntervals[i] = info.fIntervals[i];
95             }
96             return true;
97         }
98         return false;
99     }
100 
isDashed()101     bool isDashed() const {
102         return (!fStroke.isFillStyle() && SkPathEffect::kDash_DashType == fDashType);
103     }
104 
isFillStyle()105     bool isFillStyle() const { return fStroke.isFillStyle(); }
106 
getDashCount()107     int32_t getDashCount() const {
108         SkASSERT(this->isDashed());
109         return fIntervals.count();
110     }
111 
getDashPhase()112     SkScalar getDashPhase() const {
113         SkASSERT(this->isDashed());
114         return fDashPhase;
115     }
116 
getDashIntervals()117     const SkScalar* getDashIntervals() const {
118         SkASSERT(this->isDashed());
119         return fIntervals.get();
120     }
121 
removeDash()122     void removeDash() {
123         fDashType = SkPathEffect::kNone_DashType;
124     }
125 
126     /** Applies the dash to a path, if the stroke info has dashing.
127      * @return true if the dashing was applied (dst and dstStrokeInfo will be modified).
128      *         false if the stroke info did not have dashing. The dst and dstStrokeInfo
129      *               will be unmodified. The stroking in the SkStrokeRec might still
130      *               be applicable.
131      */
132     bool applyDash(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const;
133 
134 private:
135 
init(const SkPaint & paint)136     void init(const SkPaint& paint) {
137         const SkPathEffect* pe = paint.getPathEffect();
138         this->setDashInfo(pe);
139     }
140 
141     SkStrokeRec            fStroke;
142     SkPathEffect::DashType fDashType;
143     SkScalar               fDashPhase;
144     SkAutoSTArray<2, SkScalar> fIntervals;
145 };
146 
147 #endif
148