• 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 "SkFlattenableBuffers.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->set(b.fX - a.fX, b.fY - a.fY);
23 
24     if (dist <= radius * 2) {
25         step->scale(SK_ScalarHalf);
26         return false;
27     } else {
28         step->scale(SkScalarDiv(radius, dist));
29         return true;
30     }
31 }
32 
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec *,const SkRect *) const33 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
34                                     SkStrokeRec*, const SkRect*) const {
35     if (0 == fRadius) {
36         return false;
37     }
38 
39     SkPath::Iter    iter(src, false);
40     SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
41     SkPoint         pts[4];
42 
43     bool        closed;
44     SkPoint     moveTo, lastCorner;
45     SkVector    firstStep, step;
46     bool        prevIsValid = true;
47 
48     // to avoid warnings
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::kCubic_Verb:
97                 if (!prevIsValid) {
98                     dst->moveTo(pts[0]);
99                     prevIsValid = true;
100                 }
101                 // TBD - just replicate the curve for now
102                 dst->cubicTo(pts[1], pts[2], pts[3]);
103                 lastCorner = pts[3];
104                 firstStep.set(0, 0);
105                 break;
106             case SkPath::kClose_Verb:
107                 if (firstStep.fX || firstStep.fY) {
108                     dst->quadTo(lastCorner.fX, lastCorner.fY,
109                                 lastCorner.fX + firstStep.fX,
110                                 lastCorner.fY + firstStep.fY);
111                     }
112                 dst->close();
113                 break;
114             case SkPath::kDone_Verb:
115                 goto DONE;
116         }
117 
118         if (SkPath::kMove_Verb == prevVerb) {
119             firstStep = step;
120         }
121         prevVerb = verb;
122     }
123 DONE:
124     return true;
125 }
126 
flatten(SkFlattenableWriteBuffer & buffer) const127 void SkCornerPathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
128     this->INHERITED::flatten(buffer);
129     buffer.writeScalar(fRadius);
130 }
131 
SkCornerPathEffect(SkFlattenableReadBuffer & buffer)132 SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
133     fRadius = buffer.readScalar();
134 }
135