SkCornerPathEffect.cpp revision 277c3f87656c44e0a651ed0dd56efa16c0ab07b4
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 "SkCornerPathEffect.h"
11#include "SkPath.h"
12#include "SkPoint.h"
13#include "SkFlattenableBuffers.h"
14
15SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
16SkCornerPathEffect::~SkCornerPathEffect() {}
17
18static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
19                        SkPoint* step) {
20    SkScalar dist = SkPoint::Distance(a, b);
21
22    step->set(b.fX - a.fX, b.fY - a.fY);
23
24    if (dist <= radius * 2) {
25        step->scale(SK_ScalarHalf);
26        return false;
27    } else {
28        step->scale(SkScalarDiv(radius, dist));
29        return true;
30    }
31}
32
33bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
34                                    SkStrokeRec*, const SkRect*) const {
35    if (0 == fRadius) {
36        return false;
37    }
38
39    SkPath::Iter    iter(src, false);
40    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
41    SkPoint         pts[4];
42
43    bool        closed;
44    SkPoint     moveTo, lastCorner;
45    SkVector    firstStep, step;
46    bool        prevIsValid = true;
47
48    // to avoid warnings
49    moveTo.set(0, 0);
50    firstStep.set(0, 0);
51    lastCorner.set(0, 0);
52
53    for (;;) {
54        switch (verb = iter.next(pts, false)) {
55            case SkPath::kMove_Verb:
56                    // close out the previous (open) contour
57                if (SkPath::kLine_Verb == prevVerb) {
58                    dst->lineTo(lastCorner);
59                }
60                closed = iter.isClosedContour();
61                if (closed) {
62                    moveTo = pts[0];
63                    prevIsValid = false;
64                } else {
65                    dst->moveTo(pts[0]);
66                    prevIsValid = true;
67                }
68                break;
69            case SkPath::kLine_Verb: {
70                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
71                // prev corner
72                if (!prevIsValid) {
73                    dst->moveTo(moveTo + step);
74                    prevIsValid = true;
75                } else {
76                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
77                                pts[0].fY + step.fY);
78                }
79                if (drawSegment) {
80                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
81                }
82                lastCorner = pts[1];
83                prevIsValid = true;
84                break;
85            }
86            case SkPath::kQuad_Verb:
87                // TBD - just replicate the curve for now
88                if (!prevIsValid) {
89                    dst->moveTo(pts[0]);
90                    prevIsValid = true;
91                }
92                dst->quadTo(pts[1], pts[2]);
93                lastCorner = pts[2];
94                firstStep.set(0, 0);
95                break;
96            case SkPath::kCubic_Verb:
97                if (!prevIsValid) {
98                    dst->moveTo(pts[0]);
99                    prevIsValid = true;
100                }
101                // TBD - just replicate the curve for now
102                dst->cubicTo(pts[1], pts[2], pts[3]);
103                lastCorner = pts[3];
104                firstStep.set(0, 0);
105                break;
106            case SkPath::kClose_Verb:
107                if (firstStep.fX || firstStep.fY) {
108                    dst->quadTo(lastCorner.fX, lastCorner.fY,
109                                lastCorner.fX + firstStep.fX,
110                                lastCorner.fY + firstStep.fY);
111                    }
112                dst->close();
113                break;
114            case SkPath::kConic_Verb:
115                SkASSERT(0);
116                break;
117            case SkPath::kDone_Verb:
118                goto DONE;
119        }
120
121        if (SkPath::kMove_Verb == prevVerb) {
122            firstStep = step;
123        }
124        prevVerb = verb;
125    }
126DONE:
127    return true;
128}
129
130void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
131    this->INHERITED::flatten(buffer);
132    buffer.writeScalar(fRadius);
133}
134
135SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
136    fRadius = buffer.readScalar();
137}
138