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