egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 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 | |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 11 | #include "SkPathEffect.h" |
bungeman | f3c15b7 | 2015-08-19 11:56:48 -0700 | [diff] [blame] | 12 | #include "SkStrokeRec.h" |
| 13 | #include "SkTemplates.h" |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 14 | |
kkinnunen | 50b58e6 | 2015-05-18 23:02:07 -0700 | [diff] [blame] | 15 | class GrUniqueKey; |
| 16 | |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 17 | /* |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 18 | * GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec |
| 19 | * which holds information on fill style, width, miter, cap, and join. It also holds information |
| 20 | * about the dash like intervals, count, and phase. |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 21 | */ |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 22 | class GrStrokeInfo : public SkStrokeRec { |
| 23 | public: |
bsalomon | c55271f | 2015-11-09 11:55:57 -0800 | [diff] [blame] | 24 | static const GrStrokeInfo& FillInfo() { |
| 25 | static const GrStrokeInfo gFill(kFill_InitStyle); |
| 26 | return gFill; |
| 27 | } |
| 28 | |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 29 | GrStrokeInfo(SkStrokeRec::InitStyle style) |
| 30 | : INHERITED(style) |
| 31 | , fDashType(SkPathEffect::kNone_DashType) { |
| 32 | } |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 33 | |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 34 | GrStrokeInfo(const GrStrokeInfo& src, bool includeDash = true) |
| 35 | : INHERITED(src) { |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 36 | if (includeDash && src.isDashed()) { |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 37 | fDashType = src.fDashType; |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 38 | fDashPhase = src.fDashPhase; |
| 39 | fIntervals.reset(src.getDashCount()); |
| 40 | memcpy(fIntervals.get(), src.fIntervals.get(), fIntervals.count() * sizeof(SkScalar)); |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 41 | } else { |
| 42 | fDashType = SkPathEffect::kNone_DashType; |
| 43 | } |
| 44 | } |
| 45 | |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 46 | GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride) |
| 47 | : INHERITED(paint, styleOverride) |
| 48 | , fDashType(SkPathEffect::kNone_DashType) { |
egdaniel | e61c411 | 2014-06-12 10:24:21 -0700 | [diff] [blame] | 49 | this->init(paint); |
| 50 | } |
| 51 | |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 52 | explicit GrStrokeInfo(const SkPaint& paint) |
| 53 | : INHERITED(paint) |
| 54 | , fDashType(SkPathEffect::kNone_DashType) { |
egdaniel | e61c411 | 2014-06-12 10:24:21 -0700 | [diff] [blame] | 55 | this->init(paint); |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 56 | } |
| 57 | |
kkinnunen | 1899651 | 2015-04-26 23:18:49 -0700 | [diff] [blame] | 58 | GrStrokeInfo& operator=(const GrStrokeInfo& other) { |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 59 | if (other.isDashed()) { |
| 60 | fDashType = other.fDashType; |
| 61 | fDashPhase = other.fDashPhase; |
| 62 | fIntervals.reset(other.getDashCount()); |
| 63 | memcpy(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar)); |
| 64 | } else { |
| 65 | this->removeDash(); |
| 66 | } |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 67 | this->INHERITED::operator=(other); |
kkinnunen | 1899651 | 2015-04-26 23:18:49 -0700 | [diff] [blame] | 68 | return *this; |
| 69 | } |
| 70 | |
kkinnunen | 50b58e6 | 2015-05-18 23:02:07 -0700 | [diff] [blame] | 71 | bool hasEqualEffect(const GrStrokeInfo& other) const { |
| 72 | if (this->isDashed() != other.isDashed()) { |
| 73 | return false; |
| 74 | } |
| 75 | if (this->isDashed()) { |
| 76 | if (fDashPhase != other.fDashPhase || |
| 77 | fIntervals.count() != other.fIntervals.count() || |
| 78 | memcmp(fIntervals.get(), other.fIntervals.get(), |
| 79 | fIntervals.count() * sizeof(SkScalar)) != 0) { |
| 80 | return false; |
| 81 | } |
| 82 | } |
| 83 | return this->INHERITED::hasEqualEffect(other); |
| 84 | } |
| 85 | |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 86 | /* |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 87 | * This functions takes in a patheffect and updates the dashing information if the path effect |
| 88 | * is a Dash type. Returns true if the path effect is a dashed effect and we are stroking, |
| 89 | * otherwise it returns false. |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 90 | */ |
| 91 | bool setDashInfo(const SkPathEffect* pe) { |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 92 | if (pe && !this->isFillStyle()) { |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 93 | SkPathEffect::DashInfo dashInfo; |
| 94 | fDashType = pe->asADash(&dashInfo); |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 95 | if (SkPathEffect::kDash_DashType == fDashType) { |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 96 | fIntervals.reset(dashInfo.fCount); |
| 97 | dashInfo.fIntervals = fIntervals.get(); |
| 98 | pe->asADash(&dashInfo); |
| 99 | fDashPhase = dashInfo.fPhase; |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 100 | return true; |
| 101 | } |
| 102 | } |
| 103 | return false; |
| 104 | } |
| 105 | |
joshualitt | fa2008f | 2015-04-29 11:32:05 -0700 | [diff] [blame] | 106 | /* |
| 107 | * Like the above, but sets with an explicit SkPathEffect::DashInfo |
| 108 | */ |
| 109 | bool setDashInfo(const SkPathEffect::DashInfo& info) { |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 110 | if (!this->isFillStyle()) { |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 111 | fDashType = SkPathEffect::kDash_DashType; |
| 112 | fDashPhase = info.fPhase; |
joshualitt | fa2008f | 2015-04-29 11:32:05 -0700 | [diff] [blame] | 113 | fIntervals.reset(info.fCount); |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 114 | for (int i = 0; i < fIntervals.count(); i++) { |
joshualitt | fa2008f | 2015-04-29 11:32:05 -0700 | [diff] [blame] | 115 | fIntervals[i] = info.fIntervals[i]; |
| 116 | } |
joshualitt | fa2008f | 2015-04-29 11:32:05 -0700 | [diff] [blame] | 117 | return true; |
| 118 | } |
| 119 | return false; |
| 120 | } |
| 121 | |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 122 | bool isDashed() const { |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 123 | return (!this->isFillStyle() && SkPathEffect::kDash_DashType == fDashType); |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 124 | } |
| 125 | |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 126 | int32_t getDashCount() const { |
| 127 | SkASSERT(this->isDashed()); |
| 128 | return fIntervals.count(); |
| 129 | } |
| 130 | |
| 131 | SkScalar getDashPhase() const { |
| 132 | SkASSERT(this->isDashed()); |
| 133 | return fDashPhase; |
| 134 | } |
| 135 | |
| 136 | const SkScalar* getDashIntervals() const { |
| 137 | SkASSERT(this->isDashed()); |
| 138 | return fIntervals.get(); |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | void removeDash() { |
| 142 | fDashType = SkPathEffect::kNone_DashType; |
| 143 | } |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 144 | |
kkinnunen | 1899651 | 2015-04-26 23:18:49 -0700 | [diff] [blame] | 145 | /** Applies the dash to a path, if the stroke info has dashing. |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 146 | * @return true if the dashing was applied (dst and dstStrokeInfo will be modified). |
kkinnunen | 1899651 | 2015-04-26 23:18:49 -0700 | [diff] [blame] | 147 | * false if the stroke info did not have dashing. The dst and dstStrokeInfo |
| 148 | * will be unmodified. The stroking in the SkStrokeRec might still |
| 149 | * be applicable. |
| 150 | */ |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 151 | bool applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const; |
kkinnunen | 1899651 | 2015-04-26 23:18:49 -0700 | [diff] [blame] | 152 | |
kkinnunen | 50b58e6 | 2015-05-18 23:02:07 -0700 | [diff] [blame] | 153 | /** |
| 154 | * Computes the length of the data that will be written by asUniqueKeyFragment() function. |
| 155 | */ |
| 156 | int computeUniqueKeyFragmentData32Cnt() const { |
| 157 | const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t); |
| 158 | // SkStrokeRec data: 32 bits for style+join+cap and 2 scalars for miter and width. |
| 159 | int strokeKeyData32Cnt = 1 + 2 * kSkScalarData32Cnt; |
| 160 | |
| 161 | if (this->isDashed()) { |
| 162 | // One scalar for dash phase and one for each dash value. |
| 163 | strokeKeyData32Cnt += (1 + this->getDashCount()) * kSkScalarData32Cnt; |
| 164 | } |
| 165 | return strokeKeyData32Cnt; |
| 166 | } |
| 167 | |
| 168 | /** |
| 169 | * Writes the object contents as uint32_t data, to be used with GrUniqueKey. |
| 170 | * Note: the data written does not encode the length, so care must be taken to ensure |
| 171 | * that the full unique key data is encoded properly. For example, GrStrokeInfo |
| 172 | * fragment can be placed last in the sequence, at fixed index. |
| 173 | */ |
| 174 | void asUniqueKeyFragment(uint32_t*) const; |
| 175 | |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 176 | private: |
kkinnunen | 50b58e6 | 2015-05-18 23:02:07 -0700 | [diff] [blame] | 177 | // Prevent accidental usage, should use GrStrokeInfo::hasEqualEffect. |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 178 | bool hasEqualEffect(const SkStrokeRec& other) const; |
egdaniel | e61c411 | 2014-06-12 10:24:21 -0700 | [diff] [blame] | 179 | |
| 180 | void init(const SkPaint& paint) { |
| 181 | const SkPathEffect* pe = paint.getPathEffect(); |
| 182 | this->setDashInfo(pe); |
| 183 | } |
| 184 | |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 185 | SkPathEffect::DashType fDashType; |
kkinnunen | 261694c | 2015-05-05 08:00:10 -0700 | [diff] [blame] | 186 | SkScalar fDashPhase; |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 187 | SkAutoSTArray<2, SkScalar> fIntervals; |
kkinnunen | d156d36 | 2015-05-18 22:23:54 -0700 | [diff] [blame] | 188 | typedef SkStrokeRec INHERITED; |
egdaniel | d58a0ba | 2014-06-11 10:30:05 -0700 | [diff] [blame] | 189 | }; |
| 190 | |
| 191 | #endif |