• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 
9 #include "SkCornerPathEffect.h"
10 #include "SkPath.h"
11 #include "SkPoint.h"
12 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.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 = b - a;
23     if (dist <= radius * 2) {
24         *step *= SK_ScalarHalf;
25         return false;
26     } else {
27         *step *= radius / dist;
28         return true;
29     }
30 }
31 
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *) const32 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
33                                     SkStrokeRec*, const SkRect*) const {
34     if (0 == fRadius) {
35         return false;
36     }
37 
38     SkPath::Iter    iter(src, false);
39     SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
40     SkPoint         pts[4];
41 
42     bool        closed;
43     SkPoint     moveTo, lastCorner;
44     SkVector    firstStep, step;
45     bool        prevIsValid = true;
46 
47     // to avoid warnings
48     step.set(0, 0);
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::kConic_Verb:
97                 // TBD - just replicate the curve for now
98                 if (!prevIsValid) {
99                     dst->moveTo(pts[0]);
100                     prevIsValid = true;
101                 }
102                 dst->conicTo(pts[1], pts[2], iter.conicWeight());
103                 lastCorner = pts[2];
104                 firstStep.set(0, 0);
105                 break;
106             case SkPath::kCubic_Verb:
107                 if (!prevIsValid) {
108                     dst->moveTo(pts[0]);
109                     prevIsValid = true;
110                 }
111                 // TBD - just replicate the curve for now
112                 dst->cubicTo(pts[1], pts[2], pts[3]);
113                 lastCorner = pts[3];
114                 firstStep.set(0, 0);
115                 break;
116             case SkPath::kClose_Verb:
117                 if (firstStep.fX || firstStep.fY) {
118                     dst->quadTo(lastCorner.fX, lastCorner.fY,
119                                 lastCorner.fX + firstStep.fX,
120                                 lastCorner.fY + firstStep.fY);
121                     }
122                 dst->close();
123                 prevIsValid = false;
124                 break;
125             case SkPath::kDone_Verb:
126                 if (prevIsValid) {
127                     dst->lineTo(lastCorner);
128                 }
129                 goto DONE;
130         }
131 
132         if (SkPath::kMove_Verb == prevVerb) {
133             firstStep = step;
134         }
135         prevVerb = verb;
136     }
137 DONE:
138     return true;
139 }
140 
CreateProc(SkReadBuffer & buffer)141 sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
142     return SkCornerPathEffect::Make(buffer.readScalar());
143 }
144 
flatten(SkWriteBuffer & buffer) const145 void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
146     buffer.writeScalar(fRadius);
147 }
148 
149 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const150 void SkCornerPathEffect::toString(SkString* str) const {
151     str->appendf("SkCornerPathEffect: (");
152     str->appendf("radius: %.2f", fRadius);
153     str->appendf(")");
154 }
155 #endif
156