|
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 |
|
16 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {} |
|
17 SkCornerPathEffect::~SkCornerPathEffect() {} |
|
18 |
|
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->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 |
|
34 bool 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 } |
|
127 DONE: |
|
128 return true; |
|
129 } |
|
130 |
|
131 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const { |
|
132 this->INHERITED::flatten(buffer); |
|
133 buffer.writeScalar(fRadius); |
|
134 } |
|
135 |
|
136 SkCornerPathEffect::SkCornerPathEffect(SkReadBuffer& buffer) { |
|
137 fRadius = buffer.readScalar(); |
|
138 } |