aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrStyle.h
blob: 2ca037a463dacdde006a4ff12020ec0cb3f8ac14 (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
/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrStyle_DEFINED
#define GrStyle_DEFINED

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

/**
 * Represents the various ways that a GrShape can be styled. It has fill/stroking information
 * as well as an optional path effect. If the path effect represents dashing, the dashing
 * information is extracted from the path effect and stored explicitly.
 *
 * This will replace GrStrokeInfo as GrShape is deployed.
 */
class GrStyle {
public:
    /**
     * A style object that represents a fill with no path effect.
     * TODO: constexpr with C++14
     */
    static const GrStyle& SimpleFill() {
        static const GrStyle kFill(SkStrokeRec::kFill_InitStyle);
        return kFill;
        }

    /**
     * A style object that represents a hairline stroke with no path effect.
     * TODO: constexpr with C++14
     */
    static const GrStyle& SimpleHairline() {
        static const GrStyle kHairline(SkStrokeRec::kHairline_InitStyle);
        return kHairline;
    }

    enum class Apply {
        kPathEffectOnly,
        kPathEffectAndStrokeRec
    };

    /**
     * Optional flags for computing keys that may remove unnecessary variation in the key due to
     * style settings that don't affect particular classes of geometry.
     */
    enum KeyFlags {
        // The shape being styled has no open contours.
        kClosed_KeyFlag = 0x1
    };

    /**
     * Computes the key length for a GrStyle. The return will be negative if it cannot be turned
     * into a key. This occurs when there is a path effect that is not a dash. The key can
     * either reflect just the path effect (if one) or the path effect and the strokerec. Note
     * that a simple fill has a zero sized key.
     */
    static int KeySize(const GrStyle& , Apply, uint32_t flags = 0);

    /**
     * Writes a unique key for the style into the provided buffer. This function assumes the buffer
     * has room for at least KeySize() values. It assumes that KeySize() returns a non-negative
     * value for the combination of GrStyle, Apply and flags params. This is written so that the key
     * for just dash application followed by the key for the remaining SkStrokeRec is the same as
     * the key for applying dashing and SkStrokeRec all at once.
     */
    static void WriteKey(uint32_t*, const GrStyle&, Apply, uint32_t flags = 0);

    GrStyle() : GrStyle(SkStrokeRec::kFill_InitStyle) {}

    explicit GrStyle(SkStrokeRec::InitStyle initStyle) : fStrokeRec(initStyle) {}

    GrStyle(const SkStrokeRec& strokeRec, SkPathEffect* pe) : fStrokeRec(strokeRec) {
        this->initPathEffect(pe);
    }

    GrStyle(const GrStyle& that) : fStrokeRec(SkStrokeRec::kFill_InitStyle) { *this = that; }

    explicit GrStyle(const SkPaint& paint) : fStrokeRec(paint) {
        this->initPathEffect(paint.getPathEffect());
    }

    GrStyle& operator=(const GrStyle& that) {
        fPathEffect = that.fPathEffect;
        fDashInfo = that.fDashInfo;
        fStrokeRec = that.fStrokeRec;
        return *this;
    }

    void resetToInitStyle(SkStrokeRec::InitStyle fillOrHairline) {
        fDashInfo.reset();
        fPathEffect.reset(nullptr);
        if (SkStrokeRec::kFill_InitStyle == fillOrHairline) {
            fStrokeRec.setFillStyle();
        } else {
            fStrokeRec.setHairlineStyle();
        }
    }

    /** Is this style a fill with no path effect? */
    bool isSimpleFill() const { return fStrokeRec.isFillStyle() && !fPathEffect; }

    /** Is this style a hairline with no path effect? */
    bool isSimpleHairline() const { return fStrokeRec.isHairlineStyle() && !fPathEffect; }

    SkPathEffect* pathEffect() const { return fPathEffect.get(); }

    bool hasNonDashPathEffect() const { return fPathEffect.get() && !this->isDashed(); }

    bool isDashed() const { return SkPathEffect::kDash_DashType == fDashInfo.fType; }
    SkScalar dashPhase() const {
        SkASSERT(this->isDashed());
        return fDashInfo.fPhase;
    }
    int dashIntervalCnt() const {
        SkASSERT(this->isDashed());
        return fDashInfo.fIntervals.count();
    }
    const SkScalar* dashIntervals() const {
        SkASSERT(this->isDashed());
        return fDashInfo.fIntervals.get();
    }

    const SkStrokeRec& strokeRec() const { return fStrokeRec; }

    /** Hairline or fill styles without path effects make no alterations to a geometry. */
    bool applies() const {
        return this->pathEffect() || (!fStrokeRec.isFillStyle() && !fStrokeRec.isHairlineStyle());
    }

    /**
     * Applies just the path effect and returns remaining stroke information. This will fail if
     * there is no path effect. dst may or may not have been overwritten on failure.
     */
    bool SK_WARN_UNUSED_RESULT applyPathEffectToPath(SkPath* dst, SkStrokeRec* remainingStoke,
                                                     const SkPath& src) const;

    /** If this succeeds then the result path should be filled or hairlined as indicated by the
        returned SkStrokeRec::InitStyle value. Will fail if there is no path effect and the
        strokerec doesn't change the geometry. When this fails the outputs may or may not have
        been overwritten.
      */
    bool SK_WARN_UNUSED_RESULT applyToPath(SkPath* dst, SkStrokeRec::InitStyle* fillOrHairline,
                                           const SkPath& src) const;

    /** Given bounds of a path compute the bounds of path with the style applied. */
    void adjustBounds(SkRect* dst, const SkRect& src) const {
        if (this->pathEffect()) {
            this->pathEffect()->computeFastBounds(dst, src);
        } else {
            SkScalar radius = fStrokeRec.getInflationRadius();
            *dst = src.makeOutset(radius, radius);
        }
    }

private:
    void initPathEffect(SkPathEffect* pe);

    struct DashInfo {
        DashInfo() : fType(SkPathEffect::kNone_DashType) {}
        DashInfo& operator=(const DashInfo& that) {
            fType = that.fType;
            fPhase = that.fPhase;
            fIntervals.reset(that.fIntervals.count());
            sk_careful_memcpy(fIntervals.get(), that.fIntervals.get(),
                              sizeof(SkScalar) * that.fIntervals.count());
            return *this;
        }
        void reset() {
            fType = SkPathEffect::kNone_DashType;
            fIntervals.reset(0);
        }
        SkPathEffect::DashType      fType;
        SkScalar                    fPhase;
        SkAutoSTArray<4, SkScalar>  fIntervals;
    };

    SkStrokeRec         fStrokeRec;
    sk_sp<SkPathEffect> fPathEffect;
    DashInfo            fDashInfo;
};

#endif