• 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, SkPoint* step)
32 {
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     }
41     else {
42         step->scale(SkScalarDiv(radius, dist));
43         return true;
44     }
45 }
46 
filterPath(SkPath * dst,const SkPath & src,SkScalar * width)47 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
48 {
49     if (fRadius == 0)
50         return false;
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             }
78             else {
79                 dst->moveTo(pts[0]);
80                 prevIsValid = true;
81             }
82             break;
83         case SkPath::kLine_Verb:
84             {
85                 bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
86                 // prev corner
87                 if (!prevIsValid) {
88                     dst->moveTo(moveTo + step);
89                     prevIsValid = true;
90                 }
91                 else {
92                     dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY);
93                 }
94                 if (drawSegment) {
95                     dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
96                 }
97                 lastCorner = pts[1];
98                 prevIsValid = true;
99             }
100             break;
101         case SkPath::kQuad_Verb:
102             // TBD - just replicate the curve for now
103             if (!prevIsValid)
104             {
105                 dst->moveTo(pts[0]);
106                 prevIsValid = true;
107             }
108             dst->quadTo(pts[1], pts[2]);
109             lastCorner = pts[2];
110             firstStep.set(0, 0);
111             break;
112         case SkPath::kCubic_Verb:
113             if (!prevIsValid)
114             {
115                 dst->moveTo(pts[0]);
116                 prevIsValid = true;
117             }
118             // TBD - just replicate the curve for now
119             dst->cubicTo(pts[1], pts[2], pts[3]);
120             lastCorner = pts[3];
121             firstStep.set(0, 0);
122             break;
123         case SkPath::kClose_Verb:
124             if (firstStep.fX || firstStep.fY)
125                 dst->quadTo(lastCorner.fX, lastCorner.fY,
126                             lastCorner.fX + firstStep.fX,
127                             lastCorner.fY + firstStep.fY);
128             dst->close();
129             break;
130         case SkPath::kDone_Verb:
131             goto DONE;
132         }
133 
134         if (SkPath::kMove_Verb == prevVerb)
135             firstStep = step;
136         prevVerb = verb;
137     }
138 DONE:
139     return true;
140 }
141 
getFactory()142 SkFlattenable::Factory SkCornerPathEffect::getFactory()
143 {
144     return CreateProc;
145 }
146 
flatten(SkFlattenableWriteBuffer & buffer)147 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
148 {
149     buffer.writeScalar(fRadius);
150 }
151 
CreateProc(SkFlattenableReadBuffer & buffer)152 SkFlattenable* SkCornerPathEffect::CreateProc(SkFlattenableReadBuffer& buffer)
153 {
154     return SkNEW_ARGS(SkCornerPathEffect, (buffer));
155 }
156 
SkCornerPathEffect(SkFlattenableReadBuffer & buffer)157 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer)
158 {
159     fRadius = buffer.readScalar();
160 }
161 
162