SkPathEffect.cpp revision fd4be26c4202ae91f0f7cf2c03e44b5169d885eb
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 "SkBuffer.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            fWidth = paint.getStrokeWidth();
42            fStrokeAndFill = true;
43            break;
44        default:
45            SkASSERT(!"unknown paint style");
46            // fall back on just fill
47            fWidth = kStrokeRec_FillStyleWidth;
48            fStrokeAndFill = false;
49            break;
50    }
51
52    // copy these from the paint, regardless of our "style"
53    fMiterLimit = paint.getStrokeMiter();
54    fCap        = paint.getStrokeCap();
55    fJoin       = paint.getStrokeJoin();
56}
57
58SkStrokeRec::Style SkStrokeRec::getStyle() const {
59    if (fWidth < 0) {
60        return kFill_Style;
61    } else if (0 == fWidth) {
62        return kHairline_Style;
63    } else {
64        return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style;
65    }
66}
67
68void SkStrokeRec::setFillStyle() {
69    fWidth = kStrokeRec_FillStyleWidth;
70}
71
72#include "SkStroke.h"
73
74bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const {
75    if (fWidth <= 0) {  // hairline or fill
76        return false;
77    }
78
79    SkStroke stroker;
80    stroker.setCap(fCap);
81    stroker.setJoin(fJoin);
82    stroker.setMiterLimit(fMiterLimit);
83    stroker.setWidth(fWidth);
84    stroker.setDoFill(fStrokeAndFill);
85    stroker.strokePath(src, dst);
86    return true;
87}
88
89///////////////////////////////////////////////////////////////////////////////
90
91void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) {
92    *dst = src;
93}
94
95///////////////////////////////////////////////////////////////////////////////
96
97SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
98        : fPE0(pe0), fPE1(pe1) {
99    SkASSERT(pe0);
100    SkASSERT(pe1);
101    fPE0->ref();
102    fPE1->ref();
103}
104
105SkPairPathEffect::~SkPairPathEffect() {
106    SkSafeUnref(fPE0);
107    SkSafeUnref(fPE1);
108}
109
110/*
111    Format: [oe0-factory][pe1-factory][pe0-size][pe0-data][pe1-data]
112*/
113void SkPairPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
114    this->INHERITED::flatten(buffer);
115    buffer.writeFlattenable(fPE0);
116    buffer.writeFlattenable(fPE1);
117}
118
119SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) {
120    fPE0 = (SkPathEffect*)buffer.readFlattenable();
121    fPE1 = (SkPathEffect*)buffer.readFlattenable();
122    // either of these may fail, so we have to check for nulls later on
123}
124
125///////////////////////////////////////////////////////////////////////////////
126
127bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src,
128                                     SkStrokeRec* rec) {
129    // we may have failed to unflatten these, so we have to check
130    if (!fPE0 || !fPE1) {
131        return false;
132    }
133
134    SkPath          tmp;
135    const SkPath*   ptr = &src;
136
137    if (fPE1->filterPath(&tmp, src, rec)) {
138        ptr = &tmp;
139    }
140    return fPE0->filterPath(dst, *ptr, rec);
141}
142
143///////////////////////////////////////////////////////////////////////////////
144
145bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src,
146                                 SkStrokeRec* rec) {
147    // use bit-or so that we always call both, even if the first one succeeds
148    return fPE0->filterPath(dst, src, rec) | fPE1->filterPath(dst, src, rec);
149}
150
151///////////////////////////////////////////////////////////////////////////////
152
153SK_DEFINE_FLATTENABLE_REGISTRAR(SkComposePathEffect)
154SK_DEFINE_FLATTENABLE_REGISTRAR(SkSumPathEffect)
155
156