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