1 /*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9 #include "SkCornerPathEffect.h"
10 #include "SkPath.h"
11 #include "SkPoint.h"
12 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.h"
14
SkCornerPathEffect(SkScalar radius)15 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
~SkCornerPathEffect()16 SkCornerPathEffect::~SkCornerPathEffect() {}
17
ComputeStep(const SkPoint & a,const SkPoint & b,SkScalar radius,SkPoint * step)18 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
19 SkPoint* step) {
20 SkScalar dist = SkPoint::Distance(a, b);
21
22 *step = b - a;
23 if (dist <= radius * 2) {
24 *step *= SK_ScalarHalf;
25 return false;
26 } else {
27 *step *= radius / dist;
28 return true;
29 }
30 }
31
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *) const32 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
33 SkStrokeRec*, const SkRect*) const {
34 if (0 == fRadius) {
35 return false;
36 }
37
38 SkPath::Iter iter(src, false);
39 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1;
40 SkPoint pts[4];
41
42 bool closed;
43 SkPoint moveTo, lastCorner;
44 SkVector firstStep, step;
45 bool prevIsValid = true;
46
47 // to avoid warnings
48 step.set(0, 0);
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::kConic_Verb:
97 // TBD - just replicate the curve for now
98 if (!prevIsValid) {
99 dst->moveTo(pts[0]);
100 prevIsValid = true;
101 }
102 dst->conicTo(pts[1], pts[2], iter.conicWeight());
103 lastCorner = pts[2];
104 firstStep.set(0, 0);
105 break;
106 case SkPath::kCubic_Verb:
107 if (!prevIsValid) {
108 dst->moveTo(pts[0]);
109 prevIsValid = true;
110 }
111 // TBD - just replicate the curve for now
112 dst->cubicTo(pts[1], pts[2], pts[3]);
113 lastCorner = pts[3];
114 firstStep.set(0, 0);
115 break;
116 case SkPath::kClose_Verb:
117 if (firstStep.fX || firstStep.fY) {
118 dst->quadTo(lastCorner.fX, lastCorner.fY,
119 lastCorner.fX + firstStep.fX,
120 lastCorner.fY + firstStep.fY);
121 }
122 dst->close();
123 prevIsValid = false;
124 break;
125 case SkPath::kDone_Verb:
126 if (prevIsValid) {
127 dst->lineTo(lastCorner);
128 }
129 goto DONE;
130 }
131
132 if (SkPath::kMove_Verb == prevVerb) {
133 firstStep = step;
134 }
135 prevVerb = verb;
136 }
137 DONE:
138 return true;
139 }
140
CreateProc(SkReadBuffer & buffer)141 sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
142 return SkCornerPathEffect::Make(buffer.readScalar());
143 }
144
flatten(SkWriteBuffer & buffer) const145 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
146 buffer.writeScalar(fRadius);
147 }
148
149 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const150 void SkCornerPathEffect::toString(SkString* str) const {
151 str->appendf("SkCornerPathEffect: (");
152 str->appendf("radius: %.2f", fRadius);
153 str->appendf(")");
154 }
155 #endif
156