aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrStrokeInfo.h
blob: 9cf7d8302f1388b0490e906945c3a2ea24909769 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrStrokeInfo_DEFINED
#define GrStrokeInfo_DEFINED

#include "SkPathEffect.h"
#include "SkStrokeRec.h"
#include "SkTemplates.h"

class GrUniqueKey;

/*
 * GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec
 * which holds information on fill style, width, miter, cap, and join. It also holds information
 * about the dash like intervals, count, and phase.
 */
class GrStrokeInfo : public SkStrokeRec {
public:
    static const GrStrokeInfo& FillInfo() {
        static const GrStrokeInfo gFill(kFill_InitStyle);
        return gFill;
    }

    GrStrokeInfo(SkStrokeRec::InitStyle style)
        : INHERITED(style)
        , fDashType(SkPathEffect::kNone_DashType) {
    }

    GrStrokeInfo(const GrStrokeInfo& src, bool includeDash = true)
        : INHERITED(src) {
        if (includeDash && src.isDashed()) {
            fDashType = src.fDashType;
            fDashPhase = src.fDashPhase;
            fIntervals.reset(src.getDashCount());
            memcpy(fIntervals.get(), src.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
        } else {
            fDashType = SkPathEffect::kNone_DashType;
        }
    }

    GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride)
        : INHERITED(paint, styleOverride)
        , fDashType(SkPathEffect::kNone_DashType) {
        this->init(paint);
    }

    explicit GrStrokeInfo(const SkPaint& paint)
        : INHERITED(paint)
        , fDashType(SkPathEffect::kNone_DashType) {
        this->init(paint);
    }

    GrStrokeInfo& operator=(const GrStrokeInfo& other) {
        if (other.isDashed()) {
            fDashType = other.fDashType;
            fDashPhase = other.fDashPhase;
            fIntervals.reset(other.getDashCount());
            memcpy(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar));
        } else {
            this->removeDash();
        }
        this->INHERITED::operator=(other);
        return *this;
    }

    bool hasEqualEffect(const GrStrokeInfo& other) const {
        if (this->isDashed() != other.isDashed()) {
            return false;
        }
        if (this->isDashed()) {
            if (fDashPhase != other.fDashPhase ||
                fIntervals.count() != other.fIntervals.count() ||
                memcmp(fIntervals.get(), other.fIntervals.get(),
                       fIntervals.count() * sizeof(SkScalar)) != 0) {
                return false;
            }
        }
        return this->INHERITED::hasEqualEffect(other);
    }

    /*
     * This functions takes in a patheffect and updates the dashing information if the path effect
     * is a Dash type. Returns true if the path effect is a dashed effect and we are stroking,
     * otherwise it returns false.
     */
    bool setDashInfo(const SkPathEffect* pe) {
        if (pe && !this->isFillStyle()) {
            SkPathEffect::DashInfo dashInfo;
            fDashType = pe->asADash(&dashInfo);
            if (SkPathEffect::kDash_DashType == fDashType) {
                fIntervals.reset(dashInfo.fCount);
                dashInfo.fIntervals = fIntervals.get();
                pe->asADash(&dashInfo);
                fDashPhase = dashInfo.fPhase;
                return true;
            }
        }
        return false;
    }

    /*
     * Like the above, but sets with an explicit SkPathEffect::DashInfo
     */
    bool setDashInfo(const SkPathEffect::DashInfo& info) {
        if (!this->isFillStyle()) {
            fDashType = SkPathEffect::kDash_DashType;
            fDashPhase = info.fPhase;
            fIntervals.reset(info.fCount);
            for (int i = 0; i < fIntervals.count(); i++) {
                fIntervals[i] = info.fIntervals[i];
            }
            return true;
        }
        return false;
    }

    bool isDashed() const {
        return (!this->isFillStyle() && SkPathEffect::kDash_DashType == fDashType);
    }

    int32_t getDashCount() const {
        SkASSERT(this->isDashed());
        return fIntervals.count();
    }

    SkScalar getDashPhase() const {
        SkASSERT(this->isDashed());
        return fDashPhase;
    }

    const SkScalar* getDashIntervals() const {
        SkASSERT(this->isDashed());
        return fIntervals.get();
    }

    void removeDash() {
        fDashType = SkPathEffect::kNone_DashType;
    }

    /** Applies the dash to a path, if the stroke info has dashing.
     * @return true if the dashing was applied (dst and dstStrokeInfo will be modified).
     *         false if the stroke info did not have dashing. The dst and dstStrokeInfo
     *               will be unmodified. The stroking in the SkStrokeRec might still
     *               be applicable.
     */
    bool applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const;

    /**
     * Computes the length of the data that will be written by asUniqueKeyFragment() function.
     */
    int computeUniqueKeyFragmentData32Cnt() const {
        const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t);
        // SkStrokeRec data: 32 bits for style+join+cap and 2 scalars for miter and width.
        int strokeKeyData32Cnt = 1 + 2 * kSkScalarData32Cnt;

        if (this->isDashed()) {
            // One scalar for dash phase and one for each dash value.
            strokeKeyData32Cnt += (1 + this->getDashCount()) * kSkScalarData32Cnt;
        }
        return strokeKeyData32Cnt;
    }

    /**
     * Writes the object contents as uint32_t data, to be used with GrUniqueKey.
     * Note: the data written does not encode the length, so care must be taken to ensure
     * that the full unique key data is encoded properly. For example, GrStrokeInfo
     * fragment can be placed last in the sequence, at fixed index.
     */
    void asUniqueKeyFragment(uint32_t*) const;

private:
    // Prevent accidental usage, should use GrStrokeInfo::hasEqualEffect.
    bool hasEqualEffect(const SkStrokeRec& other) const;

    void init(const SkPaint& paint) {
        const SkPathEffect* pe = paint.getPathEffect();
        this->setDashInfo(pe);
    }

    SkPathEffect::DashType fDashType;
    SkScalar               fDashPhase;
    SkAutoSTArray<2, SkScalar> fIntervals;
    typedef SkStrokeRec INHERITED;
};

#endif