1 | /* |
2 | * Copyright 2012 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 | #include "include/core/SkStrokeRec.h" |
9 | #include "src/core/SkPaintDefaults.h" |
10 | |
11 | // must be < 0, since ==0 means hairline, and >0 means normal stroke |
12 | #define kStrokeRec_FillStyleWidth (-SK_Scalar1) |
13 | |
14 | SkStrokeRec::SkStrokeRec(InitStyle s) { |
15 | fResScale = 1; |
16 | fWidth = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0; |
17 | fMiterLimit = SkPaintDefaults_MiterLimit; |
18 | fCap = SkPaint::kDefault_Cap; |
19 | fJoin = SkPaint::kDefault_Join; |
20 | fStrokeAndFill = false; |
21 | } |
22 | |
23 | SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkScalar resScale) { |
24 | this->init(paint, paint.getStyle(), resScale); |
25 | } |
26 | |
27 | SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride, SkScalar resScale) { |
28 | this->init(paint, styleOverride, resScale); |
29 | } |
30 | |
31 | void SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style, SkScalar resScale) { |
32 | fResScale = resScale; |
33 | |
34 | switch (style) { |
35 | case SkPaint::kFill_Style: |
36 | fWidth = kStrokeRec_FillStyleWidth; |
37 | fStrokeAndFill = false; |
38 | break; |
39 | case SkPaint::kStroke_Style: |
40 | fWidth = paint.getStrokeWidth(); |
41 | fStrokeAndFill = false; |
42 | break; |
43 | case SkPaint::kStrokeAndFill_Style: |
44 | if (0 == paint.getStrokeWidth()) { |
45 | // hairline+fill == fill |
46 | fWidth = kStrokeRec_FillStyleWidth; |
47 | fStrokeAndFill = false; |
48 | } else { |
49 | fWidth = paint.getStrokeWidth(); |
50 | fStrokeAndFill = true; |
51 | } |
52 | break; |
53 | default: |
54 | SkDEBUGFAIL("unknown paint style" ); |
55 | // fall back on just fill |
56 | fWidth = kStrokeRec_FillStyleWidth; |
57 | fStrokeAndFill = false; |
58 | break; |
59 | } |
60 | |
61 | // copy these from the paint, regardless of our "style" |
62 | fMiterLimit = paint.getStrokeMiter(); |
63 | fCap = paint.getStrokeCap(); |
64 | fJoin = paint.getStrokeJoin(); |
65 | } |
66 | |
67 | SkStrokeRec::Style SkStrokeRec::getStyle() const { |
68 | if (fWidth < 0) { |
69 | return kFill_Style; |
70 | } else if (0 == fWidth) { |
71 | return kHairline_Style; |
72 | } else { |
73 | return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style; |
74 | } |
75 | } |
76 | |
77 | void SkStrokeRec::setFillStyle() { |
78 | fWidth = kStrokeRec_FillStyleWidth; |
79 | fStrokeAndFill = false; |
80 | } |
81 | |
82 | void SkStrokeRec::setHairlineStyle() { |
83 | fWidth = 0; |
84 | fStrokeAndFill = false; |
85 | } |
86 | |
87 | void SkStrokeRec::setStrokeStyle(SkScalar width, bool strokeAndFill) { |
88 | if (strokeAndFill && (0 == width)) { |
89 | // hairline+fill == fill |
90 | this->setFillStyle(); |
91 | } else { |
92 | fWidth = width; |
93 | fStrokeAndFill = strokeAndFill; |
94 | } |
95 | } |
96 | |
97 | #include "src/core/SkStroke.h" |
98 | |
99 | #ifdef SK_DEBUG |
100 | // enables tweaking these values at runtime from Viewer |
101 | bool gDebugStrokerErrorSet = false; |
102 | SkScalar gDebugStrokerError; |
103 | #endif |
104 | |
105 | bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const { |
106 | if (fWidth <= 0) { // hairline or fill |
107 | return false; |
108 | } |
109 | |
110 | SkStroke stroker; |
111 | stroker.setCap((SkPaint::Cap)fCap); |
112 | stroker.setJoin((SkPaint::Join)fJoin); |
113 | stroker.setMiterLimit(fMiterLimit); |
114 | stroker.setWidth(fWidth); |
115 | stroker.setDoFill(fStrokeAndFill); |
116 | #ifdef SK_DEBUG |
117 | stroker.setResScale(gDebugStrokerErrorSet ? gDebugStrokerError : fResScale); |
118 | #else |
119 | stroker.setResScale(fResScale); |
120 | #endif |
121 | stroker.strokePath(src, dst); |
122 | return true; |
123 | } |
124 | |
125 | void SkStrokeRec::applyToPaint(SkPaint* paint) const { |
126 | if (fWidth < 0) { // fill |
127 | paint->setStyle(SkPaint::kFill_Style); |
128 | return; |
129 | } |
130 | |
131 | paint->setStyle(fStrokeAndFill ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style); |
132 | paint->setStrokeWidth(fWidth); |
133 | paint->setStrokeMiter(fMiterLimit); |
134 | paint->setStrokeCap((SkPaint::Cap)fCap); |
135 | paint->setStrokeJoin((SkPaint::Join)fJoin); |
136 | } |
137 | |
138 | SkScalar SkStrokeRec::getInflationRadius() const { |
139 | return GetInflationRadius((SkPaint::Join)fJoin, fMiterLimit, (SkPaint::Cap)fCap, fWidth); |
140 | } |
141 | |
142 | SkScalar SkStrokeRec::GetInflationRadius(const SkPaint& paint, SkPaint::Style style) { |
143 | SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth(); |
144 | return GetInflationRadius(paint.getStrokeJoin(), paint.getStrokeMiter(), paint.getStrokeCap(), |
145 | width); |
146 | |
147 | } |
148 | |
149 | SkScalar SkStrokeRec::GetInflationRadius(SkPaint::Join join, SkScalar miterLimit, SkPaint::Cap cap, |
150 | SkScalar strokeWidth) { |
151 | if (strokeWidth < 0) { // fill |
152 | return 0; |
153 | } else if (0 == strokeWidth) { |
154 | // FIXME: We need a "matrixScale" parameter here in order to properly handle hairlines. |
155 | // Their with is determined in device space, unlike other strokes. |
156 | // http://skbug.com/8157 |
157 | return SK_Scalar1; |
158 | } |
159 | |
160 | // since we're stroked, outset the rect by the radius (and join type, caps) |
161 | SkScalar multiplier = SK_Scalar1; |
162 | if (SkPaint::kMiter_Join == join) { |
163 | multiplier = std::max(multiplier, miterLimit); |
164 | } |
165 | if (SkPaint::kSquare_Cap == cap) { |
166 | multiplier = std::max(multiplier, SK_ScalarSqrt2); |
167 | } |
168 | return strokeWidth/2 * multiplier; |
169 | } |
170 | |
171 | |