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
SkCornerPathEffect(SkScalar radius)16 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
~SkCornerPathEffect()17 SkCornerPathEffect::~SkCornerPathEffect() {}
18
ComputeStep(const SkPoint & a,const SkPoint & b,SkScalar radius,SkPoint * step)19 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
20 SkPoint* step) {
21 SkScalar dist = SkPoint::Distance(a, b);
22
23 *step = b - a;
24 if (dist <= radius * 2) {
25 *step *= SK_ScalarHalf;
26 return false;
27 } else {
28 *step *= radius / dist;
29 return true;
30 }
31 }
32
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *) const33 bool 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 step.set(0, 0);
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::kConic_Verb:
98 // TBD - just replicate the curve for now
99 if (!prevIsValid) {
100 dst->moveTo(pts[0]);
101 prevIsValid = true;
102 }
103 dst->conicTo(pts[1], pts[2], iter.conicWeight());
104 lastCorner = pts[2];
105 firstStep.set(0, 0);
106 break;
107 case SkPath::kCubic_Verb:
108 if (!prevIsValid) {
109 dst->moveTo(pts[0]);
110 prevIsValid = true;
111 }
112 // TBD - just replicate the curve for now
113 dst->cubicTo(pts[1], pts[2], pts[3]);
114 lastCorner = pts[3];
115 firstStep.set(0, 0);
116 break;
117 case SkPath::kClose_Verb:
118 if (firstStep.fX || firstStep.fY) {
119 dst->quadTo(lastCorner.fX, lastCorner.fY,
120 lastCorner.fX + firstStep.fX,
121 lastCorner.fY + firstStep.fY);
122 }
123 dst->close();
124 prevIsValid = false;
125 break;
126 case SkPath::kDone_Verb:
127 if (prevIsValid) {
128 dst->lineTo(lastCorner);
129 }
130 goto DONE;
131 }
132
133 if (SkPath::kMove_Verb == prevVerb) {
134 firstStep = step;
135 }
136 prevVerb = verb;
137 }
138 DONE:
139 return true;
140 }
141
CreateProc(SkReadBuffer & buffer)142 SkFlattenable* SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
143 return SkCornerPathEffect::Create(buffer.readScalar());
144 }
145
flatten(SkWriteBuffer & buffer) const146 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
147 buffer.writeScalar(fRadius);
148 }
149
150 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const151 void SkCornerPathEffect::toString(SkString* str) const {
152 str->appendf("SkCornerPathEffect: (");
153 str->appendf("radius: %.2f", fRadius);
154 str->appendf(")");
155 }
156 #endif
157