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 "SkStrokeRec.h"
9 #include "SkPaintDefaults.h"
10 
11 // must be < 0, since ==0 means hairline, and >0 means normal stroke
12 #define kStrokeRec_FillStyleWidth     (-SK_Scalar1)
13 
SkStrokeRec(InitStyle s)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 
SkStrokeRec(const SkStrokeRec & src)23 SkStrokeRec::SkStrokeRec(const SkStrokeRec& src) {
24     memcpy(this, &src, sizeof(src));
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 #include "SkStroke.h"
102 
103 #if !defined SK_LEGACY_STROKE_CURVES && defined SK_DEBUG
104     // enables tweaking these values at runtime from SampleApp
105     bool gDebugStrokerErrorSet = false;
106     SkScalar gDebugStrokerError;
107 #endif
108 
applyToPath(SkPath * dst,const SkPath & src) const109 bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const {
110     if (fWidth <= 0) {  // hairline or fill
111         return false;
112     }
113 
114     SkStroke stroker;
115     stroker.setCap(fCap);
116     stroker.setJoin(fJoin);
117     stroker.setMiterLimit(fMiterLimit);
118     stroker.setWidth(fWidth);
119     stroker.setDoFill(fStrokeAndFill);
120 #if !defined SK_LEGACY_STROKE_CURVES && defined SK_DEBUG
121     stroker.setResScale(gDebugStrokerErrorSet ? gDebugStrokerError : fResScale);
122 #else
123     stroker.setResScale(fResScale);
124 #endif
125     stroker.strokePath(src, dst);
126     return true;
127 }
128 
applyToPaint(SkPaint * paint) const129 void SkStrokeRec::applyToPaint(SkPaint* paint) const {
130     if (fWidth < 0) {  // fill
131         paint->setStyle(SkPaint::kFill_Style);
132         return;
133     }
134 
135     paint->setStyle(fStrokeAndFill ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
136     paint->setStrokeWidth(fWidth);
137     paint->setStrokeMiter(fMiterLimit);
138     paint->setStrokeCap(fCap);
139     paint->setStrokeJoin(fJoin);
140 }
141