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->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
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *) const34 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
flatten(SkWriteBuffer & buffer) const131 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
132 this->INHERITED::flatten(buffer);
133 buffer.writeScalar(fRadius);
134 }
135
SkCornerPathEffect(SkReadBuffer & buffer)136 SkCornerPathEffect::SkCornerPathEffect(SkReadBuffer& buffer) {
137 fRadius = buffer.readScalar();
138 }
139