• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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