1 /* libs/graphics/effects/SkCornerPathEffect.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkCornerPathEffect.h"
19 #include "SkPath.h"
20 #include "SkPoint.h"
21 #include "SkBuffer.h"
22
SkCornerPathEffect(SkScalar radius)23 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius)
24 {
25 }
26
~SkCornerPathEffect()27 SkCornerPathEffect::~SkCornerPathEffect()
28 {
29 }
30
ComputeStep(const SkPoint & a,const SkPoint & b,SkScalar radius,SkPoint * step)31 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, SkPoint* step)
32 {
33 SkScalar dist = SkPoint::Distance(a, b);
34
35 step->set(b.fX - a.fX, b.fY - a.fY);
36
37 if (dist <= radius * 2) {
38 step->scale(SK_ScalarHalf);
39 return false;
40 }
41 else {
42 step->scale(SkScalarDiv(radius, dist));
43 return true;
44 }
45 }
46
filterPath(SkPath * dst,const SkPath & src,SkScalar * width)47 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
48 {
49 if (fRadius == 0)
50 return false;
51
52 SkPath::Iter iter(src, false);
53 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1;
54 SkPoint pts[4];
55
56 bool closed;
57 SkPoint moveTo, lastCorner;
58 SkVector firstStep, step;
59 bool prevIsValid = true;
60
61 // to avoid warnings
62 moveTo.set(0, 0);
63 firstStep.set(0, 0);
64 lastCorner.set(0, 0);
65
66 for (;;) {
67 switch (verb = iter.next(pts)) {
68 case SkPath::kMove_Verb:
69 // close out the previous (open) contour
70 if (SkPath::kLine_Verb == prevVerb) {
71 dst->lineTo(lastCorner);
72 }
73 closed = iter.isClosedContour();
74 if (closed) {
75 moveTo = pts[0];
76 prevIsValid = false;
77 }
78 else {
79 dst->moveTo(pts[0]);
80 prevIsValid = true;
81 }
82 break;
83 case SkPath::kLine_Verb:
84 {
85 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
86 // prev corner
87 if (!prevIsValid) {
88 dst->moveTo(moveTo + step);
89 prevIsValid = true;
90 }
91 else {
92 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY);
93 }
94 if (drawSegment) {
95 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
96 }
97 lastCorner = pts[1];
98 prevIsValid = true;
99 }
100 break;
101 case SkPath::kQuad_Verb:
102 // TBD - just replicate the curve for now
103 if (!prevIsValid)
104 {
105 dst->moveTo(pts[0]);
106 prevIsValid = true;
107 }
108 dst->quadTo(pts[1], pts[2]);
109 lastCorner = pts[2];
110 firstStep.set(0, 0);
111 break;
112 case SkPath::kCubic_Verb:
113 if (!prevIsValid)
114 {
115 dst->moveTo(pts[0]);
116 prevIsValid = true;
117 }
118 // TBD - just replicate the curve for now
119 dst->cubicTo(pts[1], pts[2], pts[3]);
120 lastCorner = pts[3];
121 firstStep.set(0, 0);
122 break;
123 case SkPath::kClose_Verb:
124 if (firstStep.fX || firstStep.fY)
125 dst->quadTo(lastCorner.fX, lastCorner.fY,
126 lastCorner.fX + firstStep.fX,
127 lastCorner.fY + firstStep.fY);
128 dst->close();
129 break;
130 case SkPath::kDone_Verb:
131 goto DONE;
132 }
133
134 if (SkPath::kMove_Verb == prevVerb)
135 firstStep = step;
136 prevVerb = verb;
137 }
138 DONE:
139 return true;
140 }
141
getFactory()142 SkFlattenable::Factory SkCornerPathEffect::getFactory()
143 {
144 return CreateProc;
145 }
146
flatten(SkFlattenableWriteBuffer & buffer)147 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
148 {
149 buffer.writeScalar(fRadius);
150 }
151
CreateProc(SkFlattenableReadBuffer & buffer)152 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer)
153 {
154 return SkNEW_ARGS(SkCornerPathEffect, (buffer));
155 }
156
SkCornerPathEffect(SkFlattenableReadBuffer & buffer)157 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer)
158 {
159 fRadius = buffer.readScalar();
160 }
161
162