SkPathEffect.cpp revision 687c57c7d5a17549f63e0b15208db18b220e2a91
1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkPathEffect.h"
11#include "SkPath.h"
12#include "SkFlattenableBuffers.h"
13#include "SkPaintDefaults.h"
14
15// must be < 0, since ==0 means hairline, and >0 means normal stroke
16#define kStrokeRec_FillStyleWidth     (-SK_Scalar1)
17
18SkStrokeRec::SkStrokeRec(InitStyle s) {
19    fWidth          = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0;
20    fMiterLimit     = SkPaintDefaults_MiterLimit;
21    fCap            = SkPaint::kDefault_Cap;
22    fJoin           = SkPaint::kDefault_Join;
23    fStrokeAndFill  = false;
24}
25
26SkStrokeRec::SkStrokeRec(const SkStrokeRec& src) {
27    memcpy(this, &src, sizeof(src));
28}
29
30SkStrokeRec::SkStrokeRec(const SkPaint& paint) {
31    switch (paint.getStyle()) {
32        case SkPaint::kFill_Style:
33            fWidth = kStrokeRec_FillStyleWidth;
34            fStrokeAndFill = false;
35            break;
36        case SkPaint::kStroke_Style:
37            fWidth = paint.getStrokeWidth();
38            fStrokeAndFill = false;
39            break;
40        case SkPaint::kStrokeAndFill_Style:
41            if (0 == paint.getStrokeWidth()) {
42                // hairline+fill == fill
43                fWidth = kStrokeRec_FillStyleWidth;
44                fStrokeAndFill = false;
45            } else {
46                fWidth = paint.getStrokeWidth();
47                fStrokeAndFill = true;
48            }
49            break;
50        default:
51            SkASSERT(!"unknown paint style");
52            // fall back on just fill
53            fWidth = kStrokeRec_FillStyleWidth;
54            fStrokeAndFill = false;
55            break;
56    }
57
58    // copy these from the paint, regardless of our "style"
59    fMiterLimit = paint.getStrokeMiter();
60    fCap        = paint.getStrokeCap();
61    fJoin       = paint.getStrokeJoin();
62}
63
64SkStrokeRec::Style SkStrokeRec::getStyle() const {
65    if (fWidth < 0) {
66        return kFill_Style;
67    } else if (0 == fWidth) {
68        return kHairline_Style;
69    } else {
70        return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style;
71    }
72}
73
74void SkStrokeRec::setFillStyle() {
75    fWidth = kStrokeRec_FillStyleWidth;
76    fStrokeAndFill = false;
77}
78
79void SkStrokeRec::setHairlineStyle() {
80    fWidth = 0;
81    fStrokeAndFill = false;
82}
83
84void SkStrokeRec::setStrokeStyle(SkScalar width, bool strokeAndFill) {
85    if (strokeAndFill && (0 == width)) {
86        // hairline+fill == fill
87        this->setFillStyle();
88    } else {
89        fWidth = width;
90        fStrokeAndFill = strokeAndFill;
91    }
92}
93
94#include "SkStroke.h"
95
96bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const {
97    if (fWidth <= 0) {  // hairline or fill
98        return false;
99    }
100
101    SkStroke stroker;
102    stroker.setCap(fCap);
103    stroker.setJoin(fJoin);
104    stroker.setMiterLimit(fMiterLimit);
105    stroker.setWidth(fWidth);
106    stroker.setDoFill(fStrokeAndFill);
107    stroker.strokePath(src, dst);
108    return true;
109}
110
111///////////////////////////////////////////////////////////////////////////////
112
113SK_DEFINE_INST_COUNT(SkPathEffect)
114
115void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) {
116    *dst = src;
117}
118
119bool SkPathEffect::asPoints(PointData* results, const SkPath& src,
120                            const SkStrokeRec&, const SkMatrix&) const {
121    return false;
122}
123
124///////////////////////////////////////////////////////////////////////////////
125
126SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
127        : fPE0(pe0), fPE1(pe1) {
128    SkASSERT(pe0);
129    SkASSERT(pe1);
130    fPE0->ref();
131    fPE1->ref();
132}
133
134SkPairPathEffect::~SkPairPathEffect() {
135    SkSafeUnref(fPE0);
136    SkSafeUnref(fPE1);
137}
138
139/*
140    Format: [oe0-factory][pe1-factory][pe0-size][pe0-data][pe1-data]
141*/
142void SkPairPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
143    this->INHERITED::flatten(buffer);
144    buffer.writeFlattenable(fPE0);
145    buffer.writeFlattenable(fPE1);
146}
147
148SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) {
149    fPE0 = buffer.readFlattenableT<SkPathEffect>();
150    fPE1 = buffer.readFlattenableT<SkPathEffect>();
151    // either of these may fail, so we have to check for nulls later on
152}
153
154///////////////////////////////////////////////////////////////////////////////
155
156bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src,
157                                     SkStrokeRec* rec) {
158    // we may have failed to unflatten these, so we have to check
159    if (!fPE0 || !fPE1) {
160        return false;
161    }
162
163    SkPath          tmp;
164    const SkPath*   ptr = &src;
165
166    if (fPE1->filterPath(&tmp, src, rec)) {
167        ptr = &tmp;
168    }
169    return fPE0->filterPath(dst, *ptr, rec);
170}
171
172///////////////////////////////////////////////////////////////////////////////
173
174bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src,
175                                 SkStrokeRec* rec) {
176    // use bit-or so that we always call both, even if the first one succeeds
177    return fPE0->filterPath(dst, src, rec) | fPE1->filterPath(dst, src, rec);
178}
179