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,
32 SkPoint* step) {
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 } else {
41 step->scale(SkScalarDiv(radius, dist));
42 return true;
43 }
44 }
45
filterPath(SkPath * dst,const SkPath & src,SkScalar * width)46 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
47 SkScalar* width) {
48 if (fRadius == 0) {
49 return false;
50 }
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 } else {
78 dst->moveTo(pts[0]);
79 prevIsValid = true;
80 }
81 break;
82 case SkPath::kLine_Verb: {
83 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
84 // prev corner
85 if (!prevIsValid) {
86 dst->moveTo(moveTo + step);
87 prevIsValid = true;
88 } else {
89 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
90 pts[0].fY + step.fY);
91 }
92 if (drawSegment) {
93 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
94 }
95 lastCorner = pts[1];
96 prevIsValid = true;
97 break;
98 }
99 case SkPath::kQuad_Verb:
100 // TBD - just replicate the curve for now
101 if (!prevIsValid) {
102 dst->moveTo(pts[0]);
103 prevIsValid = true;
104 }
105 dst->quadTo(pts[1], pts[2]);
106 lastCorner = pts[2];
107 firstStep.set(0, 0);
108 break;
109 case SkPath::kCubic_Verb:
110 if (!prevIsValid) {
111 dst->moveTo(pts[0]);
112 prevIsValid = true;
113 }
114 // TBD - just replicate the curve for now
115 dst->cubicTo(pts[1], pts[2], pts[3]);
116 lastCorner = pts[3];
117 firstStep.set(0, 0);
118 break;
119 case SkPath::kClose_Verb:
120 if (firstStep.fX || firstStep.fY) {
121 dst->quadTo(lastCorner.fX, lastCorner.fY,
122 lastCorner.fX + firstStep.fX,
123 lastCorner.fY + firstStep.fY);
124 }
125 dst->close();
126 break;
127 case SkPath::kDone_Verb:
128 goto DONE;
129 }
130
131 if (SkPath::kMove_Verb == prevVerb) {
132 firstStep = step;
133 }
134 prevVerb = verb;
135 }
136 DONE:
137 return true;
138 }
139
getFactory()140 SkFlattenable::Factory SkCornerPathEffect::getFactory() {
141 return CreateProc;
142 }
143
flatten(SkFlattenableWriteBuffer & buffer)144 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
145 buffer.writeScalar(fRadius);
146 }
147
CreateProc(SkFlattenableReadBuffer & buffer)148 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
149 return SkNEW_ARGS(SkCornerPathEffect, (buffer));
150 }
151
SkCornerPathEffect(SkFlattenableReadBuffer & buffer)152 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
153 fRadius = buffer.readScalar();
154 }
155
156