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