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