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 */
19class GrStrokeInfo {
20public:
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
35    GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride) :
36        fStroke(paint, styleOverride), fDashType(SkPathEffect::kNone_DashType) {
37        this->init(paint);
38    }
39
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
58    const SkStrokeRec& getStrokeRec() const { return fStroke; }
59
60    SkStrokeRec* getStrokeRecPtr() { return &fStroke; }
61
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     */
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     */
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
101    bool isDashed() const {
102        return (!fStroke.isFillStyle() && SkPathEffect::kDash_DashType == fDashType);
103    }
104
105    bool isFillStyle() const { return fStroke.isFillStyle(); }
106
107    int32_t getDashCount() const {
108        SkASSERT(this->isDashed());
109        return fIntervals.count();
110    }
111
112    SkScalar getDashPhase() const {
113        SkASSERT(this->isDashed());
114        return fDashPhase;
115    }
116
117    const SkScalar* getDashIntervals() const {
118        SkASSERT(this->isDashed());
119        return fIntervals.get();
120    }
121
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
134private:
135
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