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 "SkBuffer.h"
14
SkCornerPathEffect(SkScalar radius)15 SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius)
16 {
17 }
18
~SkCornerPathEffect()19 SkCornerPathEffect::~SkCornerPathEffect()
20 {
21 }
22
ComputeStep(const SkPoint & a,const SkPoint & b,SkScalar radius,SkPoint * step)23 static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
24 SkPoint* step) {
25 SkScalar dist = SkPoint::Distance(a, b);
26
27 step->set(b.fX - a.fX, b.fY - a.fY);
28
29 if (dist <= radius * 2) {
30 step->scale(SK_ScalarHalf);
31 return false;
32 } else {
33 step->scale(SkScalarDiv(radius, dist));
34 return true;
35 }
36 }
37
filterPath(SkPath * dst,const SkPath & src,SkScalar * width)38 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
39 SkScalar* width) {
40 if (fRadius == 0) {
41 return false;
42 }
43
44 SkPath::Iter iter(src, false);
45 SkPath::Verb verb, prevVerb = (SkPath::Verb)-1;
46 SkPoint pts[4];
47
48 bool closed;
49 SkPoint moveTo, lastCorner;
50 SkVector firstStep, step;
51 bool prevIsValid = true;
52
53 // to avoid warnings
54 moveTo.set(0, 0);
55 firstStep.set(0, 0);
56 lastCorner.set(0, 0);
57
58 for (;;) {
59 switch (verb = iter.next(pts)) {
60 case SkPath::kMove_Verb:
61 // close out the previous (open) contour
62 if (SkPath::kLine_Verb == prevVerb) {
63 dst->lineTo(lastCorner);
64 }
65 closed = iter.isClosedContour();
66 if (closed) {
67 moveTo = pts[0];
68 prevIsValid = false;
69 } else {
70 dst->moveTo(pts[0]);
71 prevIsValid = true;
72 }
73 break;
74 case SkPath::kLine_Verb: {
75 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
76 // prev corner
77 if (!prevIsValid) {
78 dst->moveTo(moveTo + step);
79 prevIsValid = true;
80 } else {
81 dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
82 pts[0].fY + step.fY);
83 }
84 if (drawSegment) {
85 dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
86 }
87 lastCorner = pts[1];
88 prevIsValid = true;
89 break;
90 }
91 case SkPath::kQuad_Verb:
92 // TBD - just replicate the curve for now
93 if (!prevIsValid) {
94 dst->moveTo(pts[0]);
95 prevIsValid = true;
96 }
97 dst->quadTo(pts[1], pts[2]);
98 lastCorner = pts[2];
99 firstStep.set(0, 0);
100 break;
101 case SkPath::kCubic_Verb:
102 if (!prevIsValid) {
103 dst->moveTo(pts[0]);
104 prevIsValid = true;
105 }
106 // TBD - just replicate the curve for now
107 dst->cubicTo(pts[1], pts[2], pts[3]);
108 lastCorner = pts[3];
109 firstStep.set(0, 0);
110 break;
111 case SkPath::kClose_Verb:
112 if (firstStep.fX || firstStep.fY) {
113 dst->quadTo(lastCorner.fX, lastCorner.fY,
114 lastCorner.fX + firstStep.fX,
115 lastCorner.fY + firstStep.fY);
116 }
117 dst->close();
118 break;
119 case SkPath::kDone_Verb:
120 goto DONE;
121 }
122
123 if (SkPath::kMove_Verb == prevVerb) {
124 firstStep = step;
125 }
126 prevVerb = verb;
127 }
128 DONE:
129 return true;
130 }
131
getFactory()132 SkFlattenable::Factory SkCornerPathEffect::getFactory() {
133 return CreateProc;
134 }
135
flatten(SkFlattenableWriteBuffer & buffer)136 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
137 buffer.writeScalar(fRadius);
138 }
139
CreateProc(SkFlattenableReadBuffer & buffer)140 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
141 return SkNEW_ARGS(SkCornerPathEffect, (buffer));
142 }
143
SkCornerPathEffect(SkFlattenableReadBuffer & buffer)144 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
145 fRadius = buffer.readScalar();
146 }
147
148 SK_DEFINE_FLATTENABLE_REGISTRAR(SkCornerPathEffect)
149
150