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 "SkFlattenableBuffers.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->set(b.fX - a.fX, b.fY - a.fY);
23
24 if (dist <= radius * 2) {
25 step->scale(SK_ScalarHalf);
26 return false;
27 } else {
28 step->scale(SkScalarDiv(radius, dist));
29 return true;
30 }
31 }
32
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *) const33 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
34 SkStrokeRec*, const SkRect*) const {
35 if (0 == fRadius) {
36 return false;
37 }
38
39 SkPath::Iter iter(src, false);
40 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1;
41 SkPoint pts[4];
42
43 bool closed;
44 SkPoint moveTo, lastCorner;
45 SkVector firstStep, step;
46 bool prevIsValid = true;
47
48 // to avoid warnings
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::kCubic_Verb:
97 if (!prevIsValid) {
98 dst->moveTo(pts[0]);
99 prevIsValid = true;
100 }
101 // TBD - just replicate the curve for now
102 dst->cubicTo(pts[1], pts[2], pts[3]);
103 lastCorner = pts[3];
104 firstStep.set(0, 0);
105 break;
106 case SkPath::kClose_Verb:
107 if (firstStep.fX || firstStep.fY) {
108 dst->quadTo(lastCorner.fX, lastCorner.fY,
109 lastCorner.fX + firstStep.fX,
110 lastCorner.fY + firstStep.fY);
111 }
112 dst->close();
113 break;
114 case SkPath::kDone_Verb:
115 goto DONE;
116 }
117
118 if (SkPath::kMove_Verb == prevVerb) {
119 firstStep = step;
120 }
121 prevVerb = verb;
122 }
123 DONE:
124 return true;
125 }
126
flatten(SkFlattenableWriteBuffer & buffer) const127 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
128 this->INHERITED::flatten(buffer);
129 buffer.writeScalar(fRadius);
130 }
131
SkCornerPathEffect(SkFlattenableReadBuffer & buffer)132 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
133 fRadius = buffer.readScalar();
134 }
135