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
14SkStrokeRec::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
23SkStrokeRec::SkStrokeRec(const SkStrokeRec& src) {
24    memcpy(this, &src, sizeof(src));
25}
26
27SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkScalar resScale) {
28    this->init(paint, paint.getStyle(), resScale);
29}
30
31SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride, SkScalar resScale) {
32    this->init(paint, styleOverride, resScale);
33}
34
35void 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
71SkStrokeRec::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
81void SkStrokeRec::setFillStyle() {
82    fWidth = kStrokeRec_FillStyleWidth;
83    fStrokeAndFill = false;
84}
85
86void SkStrokeRec::setHairlineStyle() {
87    fWidth = 0;
88    fStrokeAndFill = false;
89}
90
91void 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
109bool 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
129void 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