SkPathEffect.cpp revision e4f10a70807166484e5a6303a5cd0034e5e87aba
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
14void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) {
15    *dst = src;
16}
17
18///////////////////////////////////////////////////////////////////////////////
19
20SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
21        : fPE0(pe0), fPE1(pe1) {
22    SkASSERT(pe0);
23    SkASSERT(pe1);
24    fPE0->ref();
25    fPE1->ref();
26}
27
28SkPairPathEffect::~SkPairPathEffect() {
29    SkSafeUnref(fPE0);
30    SkSafeUnref(fPE1);
31}
32
33/*
34    Format: [oe0-factory][pe1-factory][pe0-size][pe0-data][pe1-data]
35*/
36void SkPairPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
37    this->INHERITED::flatten(buffer);
38    buffer.writeFlattenable(fPE0);
39    buffer.writeFlattenable(fPE1);
40}
41
42SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) {
43    fPE0 = (SkPathEffect*)buffer.readFlattenable();
44    fPE1 = (SkPathEffect*)buffer.readFlattenable();
45    // either of these may fail, so we have to check for nulls later on
46}
47
48///////////////////////////////////////////////////////////////////////////////
49
50bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src,
51                                     SkScalar* width) {
52    // we may have failed to unflatten these, so we have to check
53    if (!fPE0 || !fPE1) {
54        return false;
55    }
56
57    SkPath          tmp;
58    const SkPath*   ptr = &src;
59
60    if (fPE1->filterPath(&tmp, src, width)) {
61        ptr = &tmp;
62    }
63    return fPE0->filterPath(dst, *ptr, width);
64}
65
66///////////////////////////////////////////////////////////////////////////////
67
68bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src,
69                                 SkScalar* width) {
70    // use bit-or so that we always call both, even if the first one succeeds
71    return  fPE0->filterPath(dst, src, width) | fPE1->filterPath(dst, src, width);
72}
73
74///////////////////////////////////////////////////////////////////////////////
75
76#include "SkStroke.h"
77
78/** \class SkStrokePathEffect
79
80 SkStrokePathEffect simulates stroking inside a patheffect, allowing the
81 caller to have explicit control of when to stroke a path. Typically this is
82 used if the caller wants to stroke before another patheffect is applied
83 (using SkComposePathEffect or SkSumPathEffect).
84 */
85class SkStrokePathEffect : public SkPathEffect {
86public:
87    SkStrokePathEffect(const SkPaint&);
88    SkStrokePathEffect(SkScalar width, SkPaint::Style, SkPaint::Join,
89                       SkPaint::Cap, SkScalar miterLimit = -1);
90
91    // overrides
92    virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
93
94    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkStrokePathEffect)
95
96protected:
97    SkStrokePathEffect(SkFlattenableReadBuffer&);
98    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
99
100private:
101    SkScalar    fWidth, fMiter;
102    uint8_t     fStyle, fJoin, fCap;
103
104    typedef SkPathEffect INHERITED;
105
106    // illegal
107    SkStrokePathEffect(const SkStrokePathEffect&);
108    SkStrokePathEffect& operator=(const SkStrokePathEffect&);
109};
110
111SkStrokePathEffect::SkStrokePathEffect(const SkPaint& paint)
112    : fWidth(paint.getStrokeWidth()), fMiter(paint.getStrokeMiter()),
113      fStyle(SkToU8(paint.getStyle())), fJoin(SkToU8(paint.getStrokeJoin())),
114      fCap(SkToU8(paint.getStrokeCap())) {
115}
116
117SkStrokePathEffect::SkStrokePathEffect(SkScalar width, SkPaint::Style style,
118                           SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
119        : fWidth(width), fMiter(miter), fStyle(SkToU8(style)),
120          fJoin(SkToU8(join)), fCap(SkToU8(cap)) {
121    if (miter < 0) {  // signal they want the default
122        fMiter = SkIntToScalar(4);
123    }
124}
125
126bool SkStrokePathEffect::filterPath(SkPath* dst, const SkPath& src,
127                                    SkScalar* width) {
128    if (fWidth < 0 || fStyle == SkPaint::kFill_Style) {
129        return false;
130    }
131
132    if (fStyle == SkPaint::kStroke_Style && fWidth == 0) {  // hairline
133        *width = 0;
134        return true;
135    }
136
137    SkStroke    stroke;
138
139    stroke.setWidth(fWidth);
140    stroke.setMiterLimit(fMiter);
141    stroke.setJoin((SkPaint::Join)fJoin);
142    stroke.setCap((SkPaint::Cap)fCap);
143    stroke.setDoFill(fStyle == SkPaint::kStrokeAndFill_Style);
144
145    stroke.strokePath(src, dst);
146    return true;
147}
148
149void SkStrokePathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
150    this->INHERITED::flatten(buffer);
151    buffer.writeScalar(fWidth);
152    buffer.writeScalar(fMiter);
153    buffer.write8(fStyle);
154    buffer.write8(fJoin);
155    buffer.write8(fCap);
156}
157
158SkStrokePathEffect::SkStrokePathEffect(SkFlattenableReadBuffer& buffer) {
159    fWidth = buffer.readScalar();
160    fMiter = buffer.readScalar();
161    fStyle = buffer.readU8();
162    fJoin = buffer.readU8();
163    fCap = buffer.readU8();
164}
165
166///////////////////////////////////////////////////////////////////////////////
167
168SK_DEFINE_FLATTENABLE_REGISTRAR(SkComposePathEffect)
169//SK_DEFINE_FLATTENABLE_REGISTRAR(SkStrokePathEffect)
170SK_DEFINE_FLATTENABLE_REGISTRAR(SkSumPathEffect)
171
172